fat: Enable 4096-byte sector sizes
* Correct code that only works when sector size is 512 bytes. * For devices with 4096-byte sectors, use 4096 as the size of blocks in the block cache, and as the unit of IO requests in FAT operations. * Some values continue to be stored in 512-byte units, regardless of sector size, in keeping with the original BSD driver. * Fixes #19686. Change-Id: I8fa77aeab1bc93a5465134018c3113afb2a80b8b Reviewed-on: https://review.haiku-os.org/c/haiku/+/9542 Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
@@ -46,6 +46,7 @@
|
|||||||
|
|
||||||
#define ROUNDUP(a, b) (((a) + ((b)-1)) & ~((b)-1))
|
#define ROUNDUP(a, b) (((a) + ((b)-1)) & ~((b)-1))
|
||||||
#define ROUNDDOWN(a, b) (((a) / (b)) * (b))
|
#define ROUNDDOWN(a, b) (((a) / (b)) * (b))
|
||||||
|
#define HOWMANY(a, b) (((a) + ((b) - 1)) / (b))
|
||||||
|
|
||||||
|
|
||||||
#define CHECK_BIT(a, b) ((a) & (1 << (b)))
|
#define CHECK_BIT(a, b) ((a) & (1 << (b)))
|
||||||
|
|||||||
@@ -138,15 +138,16 @@ _bwrite(struct buf* buf)
|
|||||||
return EIO;
|
return EIO;
|
||||||
} else if (buf->b_owned == false) {
|
} else if (buf->b_owned == false) {
|
||||||
// put the single block cache block that was modified
|
// put the single block cache block that was modified
|
||||||
block_cache_put(blockCache, buf->b_blkno);
|
block_cache_put(blockCache, BLOCK_TO_SECTOR(fatVolume, buf->b_blkno));
|
||||||
} else {
|
} else {
|
||||||
|
size_t cBlockSize = fatVolume->pm_BytesPerSec;
|
||||||
|
off_t cachedBlock = BLOCK_TO_SECTOR(fatVolume, buf->b_blkno);
|
||||||
// copy b_data into mutiple block cache blocks and put them
|
// copy b_data into mutiple block cache blocks and put them
|
||||||
uint32 cBlockCount = buf->b_bufsize / CACHED_BLOCK_SIZE;
|
uint32 cBlockCount = buf->b_bufsize / cBlockSize;
|
||||||
uint32 i;
|
uint32 i;
|
||||||
for (i = 0; i < cBlockCount && buf->b_bcpointers[i] != NULL; ++i) {
|
for (i = 0; i < cBlockCount && buf->b_bcpointers[i] != NULL; ++i) {
|
||||||
memcpy((caddr_t)buf->b_bcpointers[i], buf->b_data + (i * CACHED_BLOCK_SIZE),
|
memcpy((caddr_t)buf->b_bcpointers[i], buf->b_data + (i * cBlockSize), cBlockSize);
|
||||||
CACHED_BLOCK_SIZE);
|
block_cache_put(blockCache, cachedBlock + i);
|
||||||
block_cache_put(blockCache, buf->b_blkno + i);
|
|
||||||
buf->b_bcpointers[i] = NULL;
|
buf->b_bcpointers[i] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -184,13 +185,16 @@ bawrite(struct buf* bp)
|
|||||||
if (bp->b_vreg->v_resizing == false)
|
if (bp->b_vreg->v_resizing == false)
|
||||||
file_cache_sync(bp->b_vreg->v_cache);
|
file_cache_sync(bp->b_vreg->v_cache);
|
||||||
} else {
|
} else {
|
||||||
void* blockCache = bp->b_vp->v_rdev->si_mountpt->mnt_cache;
|
struct mount* bsdVolume = bp->b_vp->v_rdev->si_mountpt;
|
||||||
|
struct msdosfsmount* fatVolume = (struct msdosfsmount*)bsdVolume->mnt_data;
|
||||||
|
void* blockCache = bsdVolume->mnt_cache;
|
||||||
|
off_t cachedBlock = BLOCK_TO_SECTOR(fatVolume, bp->b_blkno);
|
||||||
|
|
||||||
if (bp->b_owned == false) {
|
if (bp->b_owned == false) {
|
||||||
block_cache_sync_etc(blockCache, bp->b_blkno, 1);
|
block_cache_sync_etc(blockCache, cachedBlock, 1);
|
||||||
} else {
|
} else {
|
||||||
block_cache_sync_etc(blockCache, bp->b_blkno,
|
block_cache_sync_etc(blockCache, cachedBlock,
|
||||||
howmany(bp->b_bufsize, CACHED_BLOCK_SIZE));
|
howmany(bp->b_bufsize, fatVolume->pm_BytesPerSec));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,21 +219,23 @@ brelse(struct buf* bp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct mount* bsdVolume = bp->b_vp->v_rdev->si_mountpt;
|
struct mount* bsdVolume = bp->b_vp->v_rdev->si_mountpt;
|
||||||
|
struct msdosfsmount* fatVolume = (struct msdosfsmount*)bsdVolume->mnt_data;
|
||||||
void* blockCache = bsdVolume->mnt_cache;
|
void* blockCache = bsdVolume->mnt_cache;
|
||||||
|
off_t cachedBlock = BLOCK_TO_SECTOR(fatVolume, bp->b_blkno);
|
||||||
bool readOnly = MOUNTED_READ_ONLY(VFSTOMSDOSFS(bsdVolume));
|
bool readOnly = MOUNTED_READ_ONLY(VFSTOMSDOSFS(bsdVolume));
|
||||||
|
|
||||||
if (bp->b_owned == false) {
|
if (bp->b_owned == false) {
|
||||||
if (readOnly == true)
|
if (readOnly == true)
|
||||||
block_cache_set_dirty(blockCache, bp->b_blkno, false, -1);
|
block_cache_set_dirty(blockCache, cachedBlock, false, -1);
|
||||||
block_cache_put(blockCache, bp->b_blkno);
|
block_cache_put(blockCache, cachedBlock);
|
||||||
put_buf(bp);
|
put_buf(bp);
|
||||||
} else {
|
} else {
|
||||||
uint32 cBlockCount = bp->b_bufsize / CACHED_BLOCK_SIZE;
|
uint32 cBlockCount = bp->b_bufsize / fatVolume->pm_BytesPerSec;
|
||||||
uint32 i;
|
uint32 i;
|
||||||
for (i = 0; i < cBlockCount && bp->b_bcpointers[i] != NULL; ++i) {
|
for (i = 0; i < cBlockCount && bp->b_bcpointers[i] != NULL; ++i) {
|
||||||
if (readOnly == true)
|
if (readOnly == true)
|
||||||
block_cache_set_dirty(blockCache, bp->b_blkno + i, false, -1);
|
block_cache_set_dirty(blockCache, cachedBlock + i, false, -1);
|
||||||
block_cache_put(blockCache, bp->b_blkno + i);
|
block_cache_put(blockCache, cachedBlock + i);
|
||||||
bp->b_bcpointers[i] = NULL;
|
bp->b_bcpointers[i] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,6 +288,7 @@ getblkx(struct vnode* vp, daddr_t blkno, daddr_t dblkno, int size, int slpflag,
|
|||||||
|
|
||||||
uint32 i;
|
uint32 i;
|
||||||
void* blockCache = NULL;
|
void* blockCache = NULL;
|
||||||
|
size_t cBlockSize = 0;
|
||||||
uint32 cBlockCount;
|
uint32 cBlockCount;
|
||||||
// the number of block cache blocks spanned by the client's request
|
// the number of block cache blocks spanned by the client's request
|
||||||
struct buf* newBuf = NULL;
|
struct buf* newBuf = NULL;
|
||||||
@@ -304,11 +311,12 @@ getblkx(struct vnode* vp, daddr_t blkno, daddr_t dblkno, int size, int slpflag,
|
|||||||
} else {
|
} else {
|
||||||
return ENOTSUP;
|
return ENOTSUP;
|
||||||
}
|
}
|
||||||
|
cBlockSize = fatVolume->pm_BytesPerSec;
|
||||||
|
|
||||||
// Before allocating memory for a new struct buf, try to reuse an existing one
|
// Before allocating memory for a new struct buf, try to reuse an existing one
|
||||||
// in the device vnode's lists.
|
// in the device vnode's lists.
|
||||||
rw_lock_write_lock(&deviceNode->v_bufobj.bo_lock.haikuRW);
|
rw_lock_write_lock(&deviceNode->v_bufobj.bo_lock.haikuRW);
|
||||||
if (size == CACHED_BLOCK_SIZE && vp->v_type != VREG
|
if ((size_t)size == cBlockSize && vp->v_type != VREG
|
||||||
&& SLIST_EMPTY(&deviceNode->v_bufobj.bo_emptybufs) == false) {
|
&& SLIST_EMPTY(&deviceNode->v_bufobj.bo_emptybufs) == false) {
|
||||||
// Get a buf with no data space. It will just point to a block cache block.
|
// Get a buf with no data space. It will just point to a block cache block.
|
||||||
newBuf = SLIST_FIRST(&deviceNode->v_bufobj.bo_emptybufs);
|
newBuf = SLIST_FIRST(&deviceNode->v_bufobj.bo_emptybufs);
|
||||||
@@ -324,8 +332,7 @@ getblkx(struct vnode* vp, daddr_t blkno, daddr_t dblkno, int size, int slpflag,
|
|||||||
foundExisting = true;
|
foundExisting = true;
|
||||||
} else if (size == (int)fatVolume->pm_fatblocksize
|
} else if (size == (int)fatVolume->pm_fatblocksize
|
||||||
&& SLIST_EMPTY(&deviceNode->v_bufobj.bo_fatbufs) == false) {
|
&& SLIST_EMPTY(&deviceNode->v_bufobj.bo_fatbufs) == false) {
|
||||||
// This branch will never be reached in FAT16 or FAT32 so long as pm_fatblocksize and
|
// This branch is only relevant for FAT12 volumes with 512-byte sectors.
|
||||||
// CACHED_BLOCK_SIZE are both 512.
|
|
||||||
newBuf = SLIST_FIRST(&deviceNode->v_bufobj.bo_fatbufs);
|
newBuf = SLIST_FIRST(&deviceNode->v_bufobj.bo_fatbufs);
|
||||||
SLIST_REMOVE_HEAD(&deviceNode->v_bufobj.bo_fatbufs, link);
|
SLIST_REMOVE_HEAD(&deviceNode->v_bufobj.bo_fatbufs, link);
|
||||||
--deviceNode->v_bufobj.bo_fatblocks;
|
--deviceNode->v_bufobj.bo_fatblocks;
|
||||||
@@ -355,7 +362,7 @@ getblkx(struct vnode* vp, daddr_t blkno, daddr_t dblkno, int size, int slpflag,
|
|||||||
newBuf->b_vreg = vp->v_type == VREG ? vp : NULL;
|
newBuf->b_vreg = vp->v_type == VREG ? vp : NULL;
|
||||||
|
|
||||||
ASSERT(size == newBuf->b_resid);
|
ASSERT(size == newBuf->b_resid);
|
||||||
cBlockCount = howmany(size, CACHED_BLOCK_SIZE);
|
cBlockCount = howmany(size, cBlockSize);
|
||||||
|
|
||||||
// Three branches:
|
// Three branches:
|
||||||
// For regular files, copy from file cache into b_data.
|
// For regular files, copy from file cache into b_data.
|
||||||
@@ -397,18 +404,20 @@ getblkx(struct vnode* vp, daddr_t blkno, daddr_t dblkno, int size, int slpflag,
|
|||||||
put_buf(newBuf);
|
put_buf(newBuf);
|
||||||
return EIO;
|
return EIO;
|
||||||
}
|
}
|
||||||
} else if (size == CACHED_BLOCK_SIZE && vp->v_type != VREG) {
|
} else if ((size_t)size == cBlockSize && vp->v_type != VREG) {
|
||||||
|
off_t cachedBlock = BLOCK_TO_SECTOR(fatVolume, dblkno);
|
||||||
if (readOnly == true)
|
if (readOnly == true)
|
||||||
newBuf->b_data = (void*)block_cache_get(blockCache, dblkno);
|
newBuf->b_data = (void*)block_cache_get(blockCache, cachedBlock);
|
||||||
else
|
else
|
||||||
newBuf->b_data = block_cache_get_writable(blockCache, dblkno, -1);
|
newBuf->b_data = block_cache_get_writable(blockCache, cachedBlock, -1);
|
||||||
if (newBuf->b_data == NULL) {
|
if (newBuf->b_data == NULL) {
|
||||||
put_buf(newBuf);
|
put_buf(newBuf);
|
||||||
return EIO;
|
return EIO;
|
||||||
}
|
}
|
||||||
newBuf->b_bufsize = CACHED_BLOCK_SIZE;
|
newBuf->b_bufsize = cBlockSize;
|
||||||
} else {
|
} else {
|
||||||
// need to get more than one cached block and copy them to make a continuous buffer
|
// need to get more than one cached block and copy them to make a continuous buffer
|
||||||
|
off_t cachedBlock = BLOCK_TO_SECTOR(fatVolume, dblkno);
|
||||||
status = allocate_data(newBuf, size);
|
status = allocate_data(newBuf, size);
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
put_buf(newBuf);
|
put_buf(newBuf);
|
||||||
@@ -419,25 +428,26 @@ getblkx(struct vnode* vp, daddr_t blkno, daddr_t dblkno, int size, int slpflag,
|
|||||||
// for high block counts, try to get all blocks in one disk read
|
// for high block counts, try to get all blocks in one disk read
|
||||||
if (cBlockCount > 4) {
|
if (cBlockCount > 4) {
|
||||||
size_t prefetchBlocks = cBlockCount;
|
size_t prefetchBlocks = cBlockCount;
|
||||||
block_cache_prefetch(blockCache, dblkno, &prefetchBlocks);
|
block_cache_prefetch(blockCache, cachedBlock, &prefetchBlocks);
|
||||||
}
|
}
|
||||||
#endif // _KERNEL_MODE
|
#endif // _KERNEL_MODE
|
||||||
|
|
||||||
for (i = 0; i < cBlockCount; i++) {
|
for (i = 0; i < cBlockCount; i++) {
|
||||||
if (readOnly == true)
|
if (readOnly == true)
|
||||||
newBuf->b_bcpointers[i] = (void*)block_cache_get(blockCache, dblkno + i);
|
newBuf->b_bcpointers[i] = (void*)block_cache_get(blockCache, cachedBlock + i);
|
||||||
else
|
else
|
||||||
newBuf->b_bcpointers[i] = block_cache_get_writable(blockCache, dblkno + i, -1);
|
newBuf->b_bcpointers[i] = block_cache_get_writable(blockCache, cachedBlock + i,
|
||||||
|
-1);
|
||||||
if (newBuf->b_bcpointers[i] == NULL) {
|
if (newBuf->b_bcpointers[i] == NULL) {
|
||||||
put_buf(newBuf);
|
put_buf(newBuf);
|
||||||
return EIO;
|
return EIO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(cBlockCount * CACHED_BLOCK_SIZE == (u_long)newBuf->b_bufsize);
|
ASSERT(cBlockCount * cBlockSize == (u_long)newBuf->b_bufsize);
|
||||||
for (i = 0; i < cBlockCount; i++) {
|
for (i = 0; i < cBlockCount; i++) {
|
||||||
memcpy(newBuf->b_data + (i * CACHED_BLOCK_SIZE), (caddr_t)newBuf->b_bcpointers[i],
|
memcpy(newBuf->b_data + (i * cBlockSize), (caddr_t)newBuf->b_bcpointers[i],
|
||||||
CACHED_BLOCK_SIZE);
|
cBlockSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -492,15 +502,19 @@ bwrite(struct buf* bp)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// block cache
|
// block cache
|
||||||
void* blockCache = bp->b_vp->v_rdev->si_mountpt->mnt_cache;
|
struct mount* bsdVolume = bp->b_vp->v_rdev->si_mountpt;
|
||||||
|
struct msdosfsmount* fatVolume = (struct msdosfsmount*)bsdVolume->mnt_data;
|
||||||
|
|
||||||
|
void* blockCache = bsdVolume->mnt_cache;
|
||||||
|
off_t cachedBlock = BLOCK_TO_SECTOR(fatVolume, bp->b_blkno);
|
||||||
|
|
||||||
if (bp->b_owned == false) {
|
if (bp->b_owned == false) {
|
||||||
// single block
|
// single block
|
||||||
status = block_cache_sync_etc(blockCache, bp->b_blkno, 1);
|
status = block_cache_sync_etc(blockCache, cachedBlock, 1);
|
||||||
} else {
|
} else {
|
||||||
// multiple blocks
|
// multiple blocks
|
||||||
status = block_cache_sync_etc(blockCache, bp->b_blkno,
|
status = block_cache_sync_etc(blockCache, cachedBlock,
|
||||||
howmany(bp->b_bufsize, CACHED_BLOCK_SIZE));
|
howmany(bp->b_bufsize, fatVolume->pm_BytesPerSec));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define CACHED_BLOCK_SIZE 512
|
|
||||||
#define BUF_CACHE_SIZE 20
|
#define BUF_CACHE_SIZE 20
|
||||||
|
|
||||||
// notify every second if the file size has changed
|
// notify every second if the file size has changed
|
||||||
@@ -34,6 +33,9 @@
|
|||||||
((fat_volume->pm_bpcluster) / (fat_volume->pm_BlkPerSec * DEV_BSIZE))
|
((fat_volume->pm_bpcluster) / (fat_volume->pm_BlkPerSec * DEV_BSIZE))
|
||||||
#define BLOCKS_PER_CLUSTER(fatVolume) (fatVolume->pm_bpcluster / DEV_BSIZE)
|
#define BLOCKS_PER_CLUSTER(fatVolume) (fatVolume->pm_bpcluster / DEV_BSIZE)
|
||||||
|
|
||||||
|
// convert a block number from DEV_BSIZE units to volume-specific sector units
|
||||||
|
#define BLOCK_TO_SECTOR(fat_volume, block) ((block * DEV_BSIZE) / fat_volume->pm_BytesPerSec)
|
||||||
|
|
||||||
#define vIS_DATA_CLUSTER(fatVolume, cluster) \
|
#define vIS_DATA_CLUSTER(fatVolume, cluster) \
|
||||||
(((cluster) >= 2) && ((uint32)(cluster) <= fatVolume->pm_maxcluster))
|
(((cluster) >= 2) && ((uint32)(cluster) <= fatVolume->pm_maxcluster))
|
||||||
#define IS_DATA_CLUSTER(cluster) vIS_DATA_CLUSTER(fatVolume, cluster)
|
#define IS_DATA_CLUSTER(cluster) vIS_DATA_CLUSTER(fatVolume, cluster)
|
||||||
|
|||||||
@@ -575,13 +575,14 @@ dosfs_write_fs_stat(fs_volume* volume, const struct fs_info* info, uint32 mask)
|
|||||||
// update the label file if there is one
|
// update the label file if there is one
|
||||||
if (bsdVolume->mnt_volentry >= 0) {
|
if (bsdVolume->mnt_volentry >= 0) {
|
||||||
uint8* rootDirBuffer;
|
uint8* rootDirBuffer;
|
||||||
daddr_t rootDirBlock = fatVolume->pm_rootdirblk;
|
daddr_t rootDirSector = fatVolume->pm_rootdirblk;
|
||||||
if (FAT32(fatVolume) == true)
|
if (FAT32(fatVolume) == true)
|
||||||
rootDirBlock = cntobn(fatVolume, fatVolume->pm_rootdirblk);
|
rootDirSector = cntobn(fatVolume, fatVolume->pm_rootdirblk);
|
||||||
|
rootDirSector = BLOCK_TO_SECTOR(fatVolume, rootDirSector);
|
||||||
daddr_t dirOffset = bsdVolume->mnt_volentry * sizeof(direntry);
|
daddr_t dirOffset = bsdVolume->mnt_volentry * sizeof(direntry);
|
||||||
rootDirBlock += dirOffset / DEV_BSIZE;
|
rootDirSector += dirOffset / fatVolume->pm_BytesPerSec;
|
||||||
|
|
||||||
status = block_cache_get_writable_etc(blockCache, rootDirBlock, -1,
|
status = block_cache_get_writable_etc(blockCache, rootDirSector, -1,
|
||||||
reinterpret_cast<void**>(&rootDirBuffer));
|
reinterpret_cast<void**>(&rootDirBuffer));
|
||||||
if (status == B_OK) {
|
if (status == B_OK) {
|
||||||
direntry* label_direntry = reinterpret_cast<direntry*>(rootDirBuffer + dirOffset);
|
direntry* label_direntry = reinterpret_cast<direntry*>(rootDirBuffer + dirOffset);
|
||||||
@@ -593,10 +594,10 @@ dosfs_write_fs_stat(fs_volume* volume, const struct fs_info* info, uint32 mask)
|
|||||||
memcpy(label_direntry->deName, name, LABEL_LENGTH);
|
memcpy(label_direntry->deName, name, LABEL_LENGTH);
|
||||||
} else {
|
} else {
|
||||||
INFORM("wfsstat: root directory position check failed\n");
|
INFORM("wfsstat: root directory position check failed\n");
|
||||||
block_cache_set_dirty(blockCache, rootDirBlock, false, -1);
|
block_cache_set_dirty(blockCache, rootDirSector, false, -1);
|
||||||
status = B_ERROR;
|
status = B_ERROR;
|
||||||
}
|
}
|
||||||
block_cache_put(blockCache, rootDirBlock);
|
block_cache_put(blockCache, rootDirSector);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// A future enhancement could be to create a label direntry if none exists already.
|
// A future enhancement could be to create a label direntry if none exists already.
|
||||||
@@ -1213,9 +1214,11 @@ _dosfs_fsync(struct vnode* bsdNode)
|
|||||||
if (externStatus != B_OK)
|
if (externStatus != B_OK)
|
||||||
REPORT_ERROR(externStatus);
|
REPORT_ERROR(externStatus);
|
||||||
} else {
|
} else {
|
||||||
size_t fatBlocks = (fatVolume->pm_fatsize * fatVolume->pm_FATs) / DEV_BSIZE;
|
off_t fatFirstSector = fatVolume->pm_fatblk / fatVolume->pm_BytesPerSec;
|
||||||
|
size_t fatSectors = (fatVolume->pm_fatsize * fatVolume->pm_FATs)
|
||||||
|
/ fatVolume->pm_BytesPerSec;
|
||||||
status_t fatStatus
|
status_t fatStatus
|
||||||
= block_cache_sync_etc(bsdVolume->mnt_cache, fatVolume->pm_fatblk, fatBlocks);
|
= block_cache_sync_etc(bsdVolume->mnt_cache, fatFirstSector, fatSectors);
|
||||||
if (fatStatus != B_OK) {
|
if (fatStatus != B_OK) {
|
||||||
externStatus = fatStatus;
|
externStatus = fatStatus;
|
||||||
REPORT_ERROR(fatStatus);
|
REPORT_ERROR(fatStatus);
|
||||||
@@ -3309,14 +3312,6 @@ bsd_device_init(mount* bsdVolume, const dev_t devID, const char* deviceFile, cde
|
|||||||
*_readOnly = true;
|
*_readOnly = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (geometry->bytes_per_sector != 0x200) {
|
|
||||||
// FAT is compatible with 0x400, 0x800, and 0x1000 as well, but this driver has not
|
|
||||||
// been tested with those values
|
|
||||||
INFORM("The FAT driver does not currently support write access to volumes with > 1 block "
|
|
||||||
"per sector\n");
|
|
||||||
*_readOnly = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*_readOnly == false) {
|
if (*_readOnly == false) {
|
||||||
// reopen it with read/write permissions
|
// reopen it with read/write permissions
|
||||||
close(device->si_fd);
|
close(device->si_fd);
|
||||||
@@ -3652,6 +3647,7 @@ fat_volume_init(vnode* devvp, mount* bsdVolume, const uint64_t fatFlags, const c
|
|||||||
fatVolume->pm_fatblocksize = 3 * 512;
|
fatVolume->pm_fatblocksize = 3 * 512;
|
||||||
else
|
else
|
||||||
fatVolume->pm_fatblocksize = DEV_BSIZE;
|
fatVolume->pm_fatblocksize = DEV_BSIZE;
|
||||||
|
fatVolume->pm_fatblocksize = roundup(fatVolume->pm_fatblocksize, fatVolume->pm_BytesPerSec);
|
||||||
fatVolume->pm_fatblocksec = fatVolume->pm_fatblocksize / DEV_BSIZE;
|
fatVolume->pm_fatblocksec = fatVolume->pm_fatblocksize / DEV_BSIZE;
|
||||||
fatVolume->pm_bnshift = ffs(DEV_BSIZE) - 1;
|
fatVolume->pm_bnshift = ffs(DEV_BSIZE) - 1;
|
||||||
|
|
||||||
@@ -3679,9 +3675,17 @@ fat_volume_init(vnode* devvp, mount* bsdVolume, const uint64_t fatFlags, const c
|
|||||||
INFORM("si_geometry not initialized\n");
|
INFORM("si_geometry not initialized\n");
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mkfs.fat sets the BytesPerSec value in the BPB based on the -S command line parameter,
|
||||||
|
// not on the properties of the underlying device.
|
||||||
|
if (dev->si_geometry->bytes_per_sector > fatVolume->pm_BytesPerSec) {
|
||||||
|
INFORM("Volume was formatted with %u-byte sectors, but device can support %" B_PRIu32
|
||||||
|
"-byte sectors.\n", fatVolume->pm_BytesPerSec, dev->si_geometry->bytes_per_sector);
|
||||||
|
}
|
||||||
|
|
||||||
uint32 fsSectors = fatVolume->pm_HugeSectors / fatVolume->pm_BlkPerSec;
|
uint32 fsSectors = fatVolume->pm_HugeSectors / fatVolume->pm_BlkPerSec;
|
||||||
// convert back from 512-byte blocks to sectors
|
// convert back from 512-byte blocks to sectors
|
||||||
if (fsSectors > dev->si_mediasize / dev->si_geometry->bytes_per_sector) {
|
if (fsSectors > dev->si_mediasize / fatVolume->pm_BytesPerSec) {
|
||||||
INFORM("dosfs: volume extends past end of partition, mounting read-only\n");
|
INFORM("dosfs: volume extends past end of partition, mounting read-only\n");
|
||||||
readOnly = true;
|
readOnly = true;
|
||||||
}
|
}
|
||||||
@@ -3691,9 +3695,10 @@ fat_volume_init(vnode* devvp, mount* bsdVolume, const uint64_t fatFlags, const c
|
|||||||
// given the size of the FAT table, how many sectors do we expect to have in the volume?
|
// given the size of the FAT table, how many sectors do we expect to have in the volume?
|
||||||
uint32 fatSectors = fatVolume->pm_FATsecs / fatVolume->pm_BlkPerSec;
|
uint32 fatSectors = fatVolume->pm_FATsecs / fatVolume->pm_BlkPerSec;
|
||||||
// convert back from 512-byte blocks to sectors
|
// convert back from 512-byte blocks to sectors
|
||||||
uint32 minUsedFatSectors = fatSectors - 8 - (SECTORS_PER_CLUSTER(fatVolume) - 1);
|
uint32 minUsedFatSectors = fatSectors - (fatSectors / 64)
|
||||||
|
- (SECTORS_PER_CLUSTER(fatVolume) - 1);
|
||||||
// The math recommended by Microsoft to estimate required FAT sectors at initialization
|
// The math recommended by Microsoft to estimate required FAT sectors at initialization
|
||||||
// may overestimate by up to 8 sectors; fsck.fat also aligns the FAT to cluster size
|
// may overestimate the requirement; mkfs.fat also aligns the FAT to cluster size
|
||||||
uint32 fatEntriesPerSector = fatVolume->pm_BytesPerSec / 4;
|
uint32 fatEntriesPerSector = fatVolume->pm_BytesPerSec / 4;
|
||||||
uint32 minFatEntries = minUsedFatSectors * fatEntriesPerSector - (fatEntriesPerSector - 1);
|
uint32 minFatEntries = minUsedFatSectors * fatEntriesPerSector - (fatEntriesPerSector - 1);
|
||||||
// the last utilized sector of a FAT contains at least one entry
|
// the last utilized sector of a FAT contains at least one entry
|
||||||
@@ -3712,13 +3717,9 @@ fat_volume_init(vnode* devvp, mount* bsdVolume, const uint64_t fatFlags, const c
|
|||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
RETURN_ERROR(status);
|
RETURN_ERROR(status);
|
||||||
|
|
||||||
// Set up the block cache.
|
// set up the block cache to use sector-size blocks
|
||||||
// If the cached block size is ever changed, functions that work with the block cache
|
|
||||||
// will need to be re-examined because they assume a size of 512 bytes
|
|
||||||
// (e.g. dosfs_fsync, read_fsinfo, write_fsinfo, sync_clusters, discard_clusters,
|
|
||||||
// dosfs_write_fs_stat, and the functions defined in vfs_bio.c).
|
|
||||||
bsdVolume->mnt_cache
|
bsdVolume->mnt_cache
|
||||||
= block_cache_create(dev->si_fd, fatVolume->pm_HugeSectors, CACHED_BLOCK_SIZE, readOnly);
|
= block_cache_create(dev->si_fd, fsSectors, fatVolume->pm_BytesPerSec, readOnly);
|
||||||
if (bsdVolume->mnt_cache == NULL)
|
if (bsdVolume->mnt_cache == NULL)
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
|
|||||||
@@ -154,12 +154,10 @@ _dosfs_initialize(int fd, partition_id partitionID, const char* name, const char
|
|||||||
}
|
}
|
||||||
if (hasPartitionInfo) {
|
if (hasPartitionInfo) {
|
||||||
dprintf("dosfs: partition info: start at %" B_PRIdOFF " bytes "
|
dprintf("dosfs: partition info: start at %" B_PRIdOFF " bytes "
|
||||||
"(%" B_PRIdOFF " sectors), "
|
|
||||||
"%" B_PRIdOFF " KB, "
|
"%" B_PRIdOFF " KB, "
|
||||||
"%" B_PRIdOFF " MB, "
|
"%" B_PRIdOFF " MB, "
|
||||||
"%" B_PRIdOFF " GB\n",
|
"%" B_PRIdOFF " GB\n",
|
||||||
partitionInfo.offset,
|
partitionInfo.offset,
|
||||||
partitionInfo.offset / 512,
|
|
||||||
partitionInfo.offset / 1024,
|
partitionInfo.offset / 1024,
|
||||||
partitionInfo.offset / (1024 * 1024),
|
partitionInfo.offset / (1024 * 1024),
|
||||||
partitionInfo.offset / (1024 * 1024 * 1024));
|
partitionInfo.offset / (1024 * 1024 * 1024));
|
||||||
@@ -171,21 +169,15 @@ _dosfs_initialize(int fd, partition_id partitionID, const char* name, const char
|
|||||||
partitionInfo.size / 1024,
|
partitionInfo.size / 1024,
|
||||||
partitionInfo.size / (1024 * 1024),
|
partitionInfo.size / (1024 * 1024),
|
||||||
partitionInfo.size / (1024 * 1024 * 1024));
|
partitionInfo.size / (1024 * 1024 * 1024));
|
||||||
|
#ifndef FS_SHELL
|
||||||
|
dprintf("dosfs: partition info: physical block size %" B_PRId32 " bytes\n",
|
||||||
|
partitionInfo.physical_block_size);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isRawDevice && !hasPartitionInfo)
|
if (!isRawDevice && !hasPartitionInfo)
|
||||||
dprintf("dosfs Warning: couldn't get partition information\n");
|
dprintf("dosfs Warning: couldn't get partition information\n");
|
||||||
|
|
||||||
if ((hasBiosGeometry && biosGeometry.bytes_per_sector != 512)
|
|
||||||
|| (hasDeviceGeometry && deviceGeometry.bytes_per_sector != 512)) {
|
|
||||||
dprintf("dosfs Error: geometry block size not 512 bytes\n");
|
|
||||||
return B_ERROR;
|
|
||||||
} else if (hasPartitionInfo && partitionInfo.logical_block_size != 512) {
|
|
||||||
dprintf("dosfs: partition logical block size is not 512, "
|
|
||||||
"it's %" B_PRId32 " bytes\n",
|
|
||||||
partitionInfo.logical_block_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasDeviceGeometry && deviceGeometry.read_only) {
|
if (hasDeviceGeometry && deviceGeometry.read_only) {
|
||||||
dprintf("dosfs Error: this is a read-only device\n");
|
dprintf("dosfs Error: this is a read-only device\n");
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
@@ -195,17 +187,26 @@ _dosfs_initialize(int fd, partition_id partitionID, const char* name, const char
|
|||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
uint64 size = 0;
|
uint64 size = 0;
|
||||||
|
uint32 sectorSize = 512;
|
||||||
|
|
||||||
|
#ifndef FS_SHELL
|
||||||
if (hasPartitionInfo) {
|
if (hasPartitionInfo) {
|
||||||
size = partitionInfo.size;
|
size = partitionInfo.size;
|
||||||
|
sectorSize = partitionInfo.physical_block_size;
|
||||||
|
#else
|
||||||
|
ASSERT(hasPartitionInfo == false);
|
||||||
|
if (0) {
|
||||||
|
#endif // !FS_SHELL
|
||||||
} else if (hasDeviceGeometry) {
|
} else if (hasDeviceGeometry) {
|
||||||
size = uint64(deviceGeometry.bytes_per_sector)
|
size = uint64(deviceGeometry.bytes_per_sector)
|
||||||
* deviceGeometry.sectors_per_track * deviceGeometry.cylinder_count
|
* deviceGeometry.sectors_per_track * deviceGeometry.cylinder_count
|
||||||
* deviceGeometry.head_count;
|
* deviceGeometry.head_count;
|
||||||
|
sectorSize = deviceGeometry.bytes_per_sector;
|
||||||
} else if (hasBiosGeometry) {
|
} else if (hasBiosGeometry) {
|
||||||
size = uint64(biosGeometry.bytes_per_sector)
|
size = uint64(biosGeometry.bytes_per_sector)
|
||||||
* biosGeometry.sectors_per_track * biosGeometry.cylinder_count
|
* biosGeometry.sectors_per_track * biosGeometry.cylinder_count
|
||||||
* biosGeometry.head_count;
|
* biosGeometry.head_count;
|
||||||
|
sectorSize = biosGeometry.bytes_per_sector;
|
||||||
} else {
|
} else {
|
||||||
// maybe it's just a file
|
// maybe it's just a file
|
||||||
struct stat stat;
|
struct stat stat;
|
||||||
@@ -215,6 +216,12 @@ _dosfs_initialize(int fd, partition_id partitionID, const char* name, const char
|
|||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
size = stat.st_size;
|
size = stat.st_size;
|
||||||
|
|
||||||
|
#ifndef FS_SHELL
|
||||||
|
fs_info parentInfo;
|
||||||
|
if (fs_stat_dev(stat.st_dev, &parentInfo) == 0)
|
||||||
|
sectorSize = parentInfo.block_size;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
dprintf("dosfs: size = %" B_PRIu64 " bytes "
|
dprintf("dosfs: size = %" B_PRIu64 " bytes "
|
||||||
@@ -223,18 +230,19 @@ _dosfs_initialize(int fd, partition_id partitionID, const char* name, const char
|
|||||||
"%" B_PRIu64 " MB, "
|
"%" B_PRIu64 " MB, "
|
||||||
"%" B_PRIu64 " GB\n",
|
"%" B_PRIu64 " GB\n",
|
||||||
size,
|
size,
|
||||||
size / 512,
|
size / sectorSize,
|
||||||
size / 1024,
|
size / 1024,
|
||||||
size / (1024 * 1024),
|
size / (1024 * 1024),
|
||||||
size / (1024 * 1024 * 1024));
|
size / (1024 * 1024 * 1024));
|
||||||
|
dprintf("dosfs: sector size = %" B_PRIu32 " bytes\n", sectorSize);
|
||||||
|
|
||||||
uint64 sectorCount = size / 512;
|
uint64 sectorCount = size / sectorSize;
|
||||||
if (sectorCount > UINT_MAX) {
|
if (sectorCount > UINT_MAX) {
|
||||||
// The FAT spec only provides 32 bits to store the sector count on disk.
|
// The FAT spec only provides 32 bits to store the sector count on disk.
|
||||||
dprintf("dosfs Warning: sector count %" B_PRIu64 " won't fit in the FAT BPB. Only the "
|
dprintf("dosfs Warning: sector count %" B_PRIu64 " won't fit in the FAT BPB. Only the "
|
||||||
"first %u sectors will be used\n", sectorCount, UINT_MAX);
|
"first %u sectors will be used\n", sectorCount, UINT_MAX);
|
||||||
sectorCount = UINT_MAX;
|
sectorCount = UINT_MAX;
|
||||||
size = sectorCount * 512;
|
size = sectorCount * sectorSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fatbits == 0) {
|
if (fatbits == 0) {
|
||||||
@@ -254,72 +262,75 @@ _dosfs_initialize(int fd, partition_id partitionID, const char* name, const char
|
|||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64 adjustedSize = (size * 512) / sectorSize;
|
||||||
|
// The volume size cutoffs recommended by Microsoft to determine sectors per cluster
|
||||||
|
// assume 512-byte sectors.
|
||||||
int sectorPerCluster;
|
int sectorPerCluster;
|
||||||
|
|
||||||
sectorPerCluster = 0;
|
sectorPerCluster = 0;
|
||||||
if (fatbits == 12) {
|
if (fatbits == 12) {
|
||||||
sectorPerCluster = 0;
|
sectorPerCluster = 0;
|
||||||
if (size < 16777216LL)
|
if (adjustedSize < 16777216LL)
|
||||||
sectorPerCluster = 8;
|
sectorPerCluster = 8;
|
||||||
if (size <= 2949120)
|
if (adjustedSize <= 2949120)
|
||||||
sectorPerCluster = 2;
|
sectorPerCluster = 2;
|
||||||
if (size <= 1474560)
|
if (adjustedSize <= 1474560)
|
||||||
sectorPerCluster = 1;
|
sectorPerCluster = 1;
|
||||||
if (size <= 737280) {
|
if (adjustedSize <= 737280) {
|
||||||
// We follow Microsoft guidance in increasing cluster size for the smallest disks.
|
// We follow Microsoft guidance in increasing cluster size for the smallest disks.
|
||||||
// The idea was probably to keep the FAT from taking up a too much of a small disk.
|
// The idea was probably to keep the FAT from taking up a too much of a small disk.
|
||||||
sectorPerCluster = 2;
|
sectorPerCluster = 2;
|
||||||
}
|
}
|
||||||
} else if (fatbits == 16) {
|
} else if (fatbits == 16) {
|
||||||
sectorPerCluster = 0; //larger than 2 GB must fail
|
sectorPerCluster = 0; //larger than 2 GB must fail
|
||||||
if (size <= (2048 * 1024 * 1024LL)) // up to 2GB, use 32k clusters
|
if (adjustedSize <= (2048 * 1024 * 1024LL)) // up to 2GB, use 32k clusters
|
||||||
sectorPerCluster = 64;
|
sectorPerCluster = 64;
|
||||||
if (size <= (1024 * 1024 * 1024LL)) // up to 1GB, use 16k clusters
|
if (adjustedSize <= (1024 * 1024 * 1024LL)) // up to 1GB, use 16k clusters
|
||||||
sectorPerCluster = 32;
|
sectorPerCluster = 32;
|
||||||
if (size <= (512 * 1024 * 1024LL)) // up to 512MB, use 8k clusters
|
if (adjustedSize <= (512 * 1024 * 1024LL)) // up to 512MB, use 8k clusters
|
||||||
sectorPerCluster = 16;
|
sectorPerCluster = 16;
|
||||||
if (size <= (256 * 1024 * 1024LL)) // up to 256MB, use 4k clusters
|
if (adjustedSize <= (256 * 1024 * 1024LL)) // up to 256MB, use 4k clusters
|
||||||
sectorPerCluster = 8;
|
sectorPerCluster = 8;
|
||||||
if (size <= (128 * 1024 * 1024LL)) // up to 128MB, use 2k clusters
|
if (adjustedSize <= (128 * 1024 * 1024LL)) // up to 128MB, use 2k clusters
|
||||||
sectorPerCluster = 4;
|
sectorPerCluster = 4;
|
||||||
if (size <= (16 * 1024 * 1024LL)) // up to 16MB, use 1k clusters
|
if (adjustedSize <= (16 * 1024 * 1024LL)) // up to 16MB, use 1k clusters
|
||||||
sectorPerCluster = 2;
|
sectorPerCluster = 2;
|
||||||
if (size <= 4182016LL) // smaller than 4.1 MB must fail
|
if (adjustedSize <= FLOPPY_MAX_SIZE) // smaller than this must fail
|
||||||
sectorPerCluster = 0;
|
sectorPerCluster = 0;
|
||||||
} else if (fatbits == 32) {
|
} else if (fatbits == 32) {
|
||||||
sectorPerCluster = 64; // default is 32k clusters
|
sectorPerCluster = 64; // default is 32k clusters
|
||||||
if (size <= (32 * 1024 * 1024 * 1024LL)) {
|
if (adjustedSize <= (32 * 1024 * 1024 * 1024LL)) {
|
||||||
// up to 32GB, use 16k clusters
|
// up to 32GB, use 16k clusters
|
||||||
sectorPerCluster = 32;
|
sectorPerCluster = 32;
|
||||||
}
|
}
|
||||||
if (size <= (16 * 1024 * 1024 * 1024LL)) {
|
if (adjustedSize <= (16 * 1024 * 1024 * 1024LL)) {
|
||||||
// up to 16GB, use 8k clusters
|
// up to 16GB, use 8k clusters
|
||||||
sectorPerCluster = 16;
|
sectorPerCluster = 16;
|
||||||
}
|
}
|
||||||
if (size <= (8 * 1024 * 1024 * 1024LL)) {
|
if (adjustedSize <= (8 * 1024 * 1024 * 1024LL)) {
|
||||||
// up to 8GB, use 4k clusters
|
// up to 8GB, use 4k clusters
|
||||||
sectorPerCluster = 8;
|
sectorPerCluster = 8;
|
||||||
}
|
}
|
||||||
if (size <= (532480 * 512LL)) {
|
if (adjustedSize <= (532480 * 512LL)) {
|
||||||
// up to 260 MB, use 0.5k clusters
|
// up to 260 MB, use 0.5k clusters
|
||||||
sectorPerCluster = 1;
|
sectorPerCluster = 1;
|
||||||
}
|
}
|
||||||
if (size <= (66600 * 512LL)) {
|
if (adjustedSize <= (66600 * 512LL)) {
|
||||||
// smaller than 32.5 MB must fail
|
// smaller than 32.5 MB must fail
|
||||||
sectorPerCluster = 0;
|
sectorPerCluster = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sectorPerCluster == 0) {
|
if (sectorPerCluster == 0) {
|
||||||
dprintf("dosfs Error: failed to determine sector per cluster value, "
|
dprintf("dosfs Error: failed to determine sector per cluster value, %" B_PRIu64
|
||||||
"partition too large for %d bit fat\n",fatbits);
|
" partition with %" B_PRIu32 "-byte sectors too large for %d bit fat\n",
|
||||||
|
size, sectorSize, fatbits);
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
int reservedSectorCount = 0; // avoid compiler warning
|
int reservedSectorCount = 0; // avoid compiler warning
|
||||||
int rootEntryCount = 0; // avoid compiler warning
|
int rootEntryCount = 0; // avoid compiler warning
|
||||||
int numFATs;
|
int numFATs;
|
||||||
int sectorSize;
|
|
||||||
uint8 biosDriveId;
|
uint8 biosDriveId;
|
||||||
|
|
||||||
// get bios drive-id, or use 0x80
|
// get bios drive-id, or use 0x80
|
||||||
@@ -332,7 +343,6 @@ _dosfs_initialize(int fd, partition_id partitionID, const char* name, const char
|
|||||||
|
|
||||||
// default parameters for the bootsector
|
// default parameters for the bootsector
|
||||||
numFATs = 2;
|
numFATs = 2;
|
||||||
sectorSize = 512;
|
|
||||||
if (fatbits == 12 || fatbits == 16)
|
if (fatbits == 12 || fatbits == 16)
|
||||||
reservedSectorCount = 1;
|
reservedSectorCount = 1;
|
||||||
if (fatbits == 32)
|
if (fatbits == 32)
|
||||||
@@ -345,12 +355,12 @@ _dosfs_initialize(int fd, partition_id partitionID, const char* name, const char
|
|||||||
rootEntryCount = 0;
|
rootEntryCount = 0;
|
||||||
|
|
||||||
// Determine FATSize
|
// Determine FATSize
|
||||||
// calculation done as MS recommends
|
// calculation done as MS recommends (with adjustments to account for sector sizes > 512 bytes)
|
||||||
uint64 dskSize = size / sectorSize;
|
uint64 dskSize = size / sectorSize;
|
||||||
uint32 rootDirSectors = ((rootEntryCount * 32) + (sectorSize - 1))
|
uint32 rootDirSectors = ((rootEntryCount * 32) + (sectorSize - 1))
|
||||||
/ sectorSize;
|
/ sectorSize;
|
||||||
uint64 tmpVal1 = dskSize - (reservedSectorCount + rootDirSectors);
|
uint64 tmpVal1 = dskSize - (reservedSectorCount + rootDirSectors);
|
||||||
uint64 tmpVal2 = (256 * sectorPerCluster) + numFATs;
|
uint64 tmpVal2 = (256 * sectorPerCluster * sectorSize / 512) + numFATs;
|
||||||
if (fatbits == 32)
|
if (fatbits == 32)
|
||||||
tmpVal2 = tmpVal2 / 2;
|
tmpVal2 = tmpVal2 / 2;
|
||||||
uint32 FATSize = (tmpVal1 + (tmpVal2 - 1)) / tmpVal2;
|
uint32 FATSize = (tmpVal1 + (tmpVal2 - 1)) / tmpVal2;
|
||||||
@@ -365,16 +375,24 @@ _dosfs_initialize(int fd, partition_id partitionID, const char* name, const char
|
|||||||
dprintf("dosfs Error: cluster count (%" B_PRIu64 ") exceeds FAT12 limit.\n", clusterCount);
|
dprintf("dosfs Error: cluster count (%" B_PRIu64 ") exceeds FAT12 limit.\n", clusterCount);
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
}
|
}
|
||||||
if (fatbits == 16 && clusterCount > FAT16_MAX_CLUSTER_COUNT) {
|
if (fatbits == 16 && (clusterCount <= FAT12_MAX_CLUSTER_COUNT
|
||||||
dprintf("dosfs Error: cluster count (%" B_PRIu64 ") exceeds FAT16 limit.\n", clusterCount);
|
|| clusterCount > FAT16_MAX_CLUSTER_COUNT)) {
|
||||||
|
dprintf("dosfs Error: cluster count (%" B_PRIu64 ") not valid for FAT16.\n", clusterCount);
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
}
|
}
|
||||||
if (fatbits == 32 && clusterCount > FAT32_MAX_CLUSTER_COUNT) {
|
if (fatbits == 32 && (clusterCount <= FAT16_MAX_CLUSTER_COUNT
|
||||||
dprintf("dosfs Error: cluster count (%" B_PRIu64 ") exceeds FAT32 limit.\n", clusterCount);
|
|| clusterCount > FAT32_MAX_CLUSTER_COUNT)) {
|
||||||
|
dprintf("dosfs Error: cluster count (%" B_PRIu64 ") not valid for FAT32.\n", clusterCount);
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
dprintf("dosfs: fatbits = %d, clustersize = %d\n", fatbits, sectorPerCluster * 512);
|
// Verify the calculated FATSize is large enough
|
||||||
|
if (clusterCount * fatbits / 8 > FATSize * sectorSize) {
|
||||||
|
dprintf("dosfs Error: FAT size of %" B_PRIu32 " not sufficient for %" B_PRIu64
|
||||||
|
" %d-bit entries.\n", FATSize, clusterCount, fatbits);
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintf("dosfs: fatbits = %d, clustersize = %d\n", fatbits, sectorPerCluster * sectorSize);
|
||||||
dprintf("dosfs: FAT size is %" B_PRIu32 " sectors\n", FATSize);
|
dprintf("dosfs: FAT size is %" B_PRIu32 " sectors\n", FATSize);
|
||||||
dprintf("dosfs: disk label: %s\n", label);
|
dprintf("dosfs: disk label: %s\n", label);
|
||||||
|
|
||||||
@@ -473,14 +491,14 @@ _dosfs_initialize(int fd, partition_id partitionID, const char* name, const char
|
|||||||
dprintf("dosfs: Writing FAT\n");
|
dprintf("dosfs: Writing FAT\n");
|
||||||
char * zerobuffer = (char *)malloc(65536);
|
char * zerobuffer = (char *)malloc(65536);
|
||||||
memset(zerobuffer,0,65536);
|
memset(zerobuffer,0,65536);
|
||||||
int64 bytes_to_write = 512LL * (reservedSectorCount + (numFATs * FATSize)
|
int64 bytes_to_write = static_cast<int64>(sectorSize)
|
||||||
+ rootDirSectors);
|
* (reservedSectorCount + (numFATs * FATSize) + rootDirSectors);
|
||||||
int64 pos = 0;
|
int64 pos = 0;
|
||||||
while (bytes_to_write > 0) {
|
while (bytes_to_write > 0) {
|
||||||
ssize_t writesize = min_c(bytes_to_write, 65536);
|
ssize_t writesize = min_c(bytes_to_write, 65536);
|
||||||
written = write_pos(fd, pos, zerobuffer, writesize);
|
written = write_pos(fd, pos, zerobuffer, writesize);
|
||||||
if (written != writesize) {
|
if (written != writesize) {
|
||||||
dprintf("dosfs Error: write error near sector %" B_PRId64 "\n", pos / 512);
|
dprintf("dosfs Error: write error near sector %" B_PRId64 "\n", pos / sectorSize);
|
||||||
free(zerobuffer);
|
free(zerobuffer);
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
@@ -491,14 +509,15 @@ _dosfs_initialize(int fd, partition_id partitionID, const char* name, const char
|
|||||||
|
|
||||||
//write boot sector
|
//write boot sector
|
||||||
dprintf("dosfs: Writing boot block\n");
|
dprintf("dosfs: Writing boot block\n");
|
||||||
written = write_pos(fd, BOOT_SECTOR_NUM * 512, bootsector, 512);
|
written = write_pos(fd, BOOT_SECTOR_NUM * sectorSize, bootsector, 512);
|
||||||
|
// even if the boot sector is 4096 bytes, we only need to write the first 512
|
||||||
if (written != 512) {
|
if (written != 512) {
|
||||||
dprintf("dosfs Error: write error at sector %d\n", BOOT_SECTOR_NUM);
|
dprintf("dosfs Error: write error at sector %d\n", BOOT_SECTOR_NUM);
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fatbits == 32) {
|
if (fatbits == 32) {
|
||||||
written = write_pos(fd, BACKUP_SECTOR_NUM * 512, bootsector, 512);
|
written = write_pos(fd, BACKUP_SECTOR_NUM * sectorSize, bootsector, 512);
|
||||||
if (written != 512) {
|
if (written != 512) {
|
||||||
dprintf("dosfs Error: write error at sector %d\n", BACKUP_SECTOR_NUM);
|
dprintf("dosfs Error: write error at sector %d\n", BACKUP_SECTOR_NUM);
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
@@ -539,13 +558,13 @@ _dosfs_initialize(int fd, partition_id partitionID, const char* name, const char
|
|||||||
sec[10] = 0xFF;
|
sec[10] = 0xFF;
|
||||||
sec[11] = 0x0F;
|
sec[11] = 0x0F;
|
||||||
}
|
}
|
||||||
written = write_pos(fd, reservedSectorCount * 512, sec, 512);
|
written = write_pos(fd, reservedSectorCount * sectorSize, sec, 512);
|
||||||
if (written != 512) {
|
if (written != 512) {
|
||||||
dprintf("dosfs Error: write error at sector %d\n", reservedSectorCount);
|
dprintf("dosfs Error: write error at sector %d\n", reservedSectorCount);
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
if (numFATs > 1) {
|
if (numFATs > 1) {
|
||||||
written = write_pos(fd, (reservedSectorCount + FATSize) * 512,sec,512);
|
written = write_pos(fd, (reservedSectorCount + FATSize) * sectorSize, sec, 512);
|
||||||
if (written != 512) {
|
if (written != 512) {
|
||||||
dprintf("dosfs Error: write error at sector %" B_PRIu32 "\n",
|
dprintf("dosfs Error: write error at sector %" B_PRIu32 "\n",
|
||||||
reservedSectorCount + FATSize);
|
reservedSectorCount + FATSize);
|
||||||
@@ -566,7 +585,7 @@ _dosfs_initialize(int fd, partition_id partitionID, const char* name, const char
|
|||||||
= B_HOST_TO_LENDIAN_INT32((uint32)free_count);
|
= B_HOST_TO_LENDIAN_INT32((uint32)free_count);
|
||||||
fsinfosector.FSI_Nxt_Free = B_HOST_TO_LENDIAN_INT32(3);
|
fsinfosector.FSI_Nxt_Free = B_HOST_TO_LENDIAN_INT32(3);
|
||||||
fsinfosector.FSI_TrailSig = B_HOST_TO_LENDIAN_INT32(0xAA550000);
|
fsinfosector.FSI_TrailSig = B_HOST_TO_LENDIAN_INT32(0xAA550000);
|
||||||
written = write_pos(fd, FSINFO_SECTOR_NUM * 512, &fsinfosector, 512);
|
written = write_pos(fd, FSINFO_SECTOR_NUM * sectorSize, &fsinfosector, 512);
|
||||||
if (written != 512) {
|
if (written != 512) {
|
||||||
dprintf("dosfs Error: write error at sector %d\n", FSINFO_SECTOR_NUM);
|
dprintf("dosfs Error: write error at sector %d\n", FSINFO_SECTOR_NUM);
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
@@ -580,20 +599,20 @@ _dosfs_initialize(int fd, partition_id partitionID, const char* name, const char
|
|||||||
memset(data, 0, 512);
|
memset(data, 0, 512);
|
||||||
create_volume_label_sector(data, label);
|
create_volume_label_sector(data, label);
|
||||||
uint32 rootDirSector = reservedSectorCount + (numFATs * FATSize);
|
uint32 rootDirSector = reservedSectorCount + (numFATs * FATSize);
|
||||||
written = write_pos(fd, rootDirSector * 512, data, 512);
|
written = write_pos(fd, rootDirSector * sectorSize, data, 512);
|
||||||
if (written != 512) {
|
if (written != 512) {
|
||||||
dprintf("dosfs Error: write error at sector %" B_PRIu32 "\n",
|
dprintf("dosfs Error: write error at sector %" B_PRIu32 "\n",
|
||||||
rootDirSector);
|
rootDirSector);
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
} else if (fatbits == 32) {
|
} else if (fatbits == 32) {
|
||||||
int size = 512 * sectorPerCluster;
|
int size = sectorSize * sectorPerCluster;
|
||||||
uint8 *cluster = (uint8*)malloc(size);
|
uint8 *cluster = (uint8*)malloc(size);
|
||||||
memset(cluster, 0, size);
|
memset(cluster, 0, size);
|
||||||
create_volume_label_sector(cluster, label);
|
create_volume_label_sector(cluster, label);
|
||||||
uint32 rootDirSector = reservedSectorCount + (numFATs * FATSize)
|
uint32 rootDirSector = reservedSectorCount + (numFATs * FATSize)
|
||||||
+ rootDirSectors;
|
+ rootDirSectors;
|
||||||
written = write_pos(fd, rootDirSector * 512, cluster, size);
|
written = write_pos(fd, rootDirSector * sectorSize, cluster, size);
|
||||||
free(cluster);
|
free(cluster);
|
||||||
if (written != size) {
|
if (written != size) {
|
||||||
dprintf("dosfs Error: write error at sector %" B_PRIu32 "\n", rootDirSector);
|
dprintf("dosfs Error: write error at sector %" B_PRIu32 "\n", rootDirSector);
|
||||||
|
|||||||
@@ -66,8 +66,11 @@
|
|||||||
|
|
||||||
#include <AutoDeleter.h>
|
#include <AutoDeleter.h>
|
||||||
#include <file_systems/mime_ext_table.h>
|
#include <file_systems/mime_ext_table.h>
|
||||||
|
#include <kernel.h>
|
||||||
#include <real_time_clock.h>
|
#include <real_time_clock.h>
|
||||||
#include <util/AutoLock.h>
|
#include <util/AutoLock.h>
|
||||||
|
#else
|
||||||
|
#include <fssh_kernel_priv.h>
|
||||||
#endif // !FS_SHELL
|
#endif // !FS_SHELL
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
@@ -557,7 +560,8 @@ read_fsinfo(msdosfsmount* volume, const vnode* devNode)
|
|||||||
const uint8* buffer;
|
const uint8* buffer;
|
||||||
const struct fsinfo* fsInfo;
|
const struct fsinfo* fsInfo;
|
||||||
|
|
||||||
status = block_cache_get_etc(volume->pm_mountp->mnt_cache, volume->pm_fsinfo,
|
off_t cachedBlock = BLOCK_TO_SECTOR(volume, volume->pm_fsinfo);
|
||||||
|
status = block_cache_get_etc(volume->pm_mountp->mnt_cache, cachedBlock,
|
||||||
reinterpret_cast<const void**>(&buffer));
|
reinterpret_cast<const void**>(&buffer));
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
RETURN_ERROR(status);
|
RETURN_ERROR(status);
|
||||||
@@ -575,7 +579,7 @@ read_fsinfo(msdosfsmount* volume, const vnode* devNode)
|
|||||||
volume->pm_fsinfo = 0;
|
volume->pm_fsinfo = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
block_cache_put(volume->pm_mountp->mnt_cache, volume->pm_fsinfo);
|
block_cache_put(volume->pm_mountp->mnt_cache, cachedBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -603,15 +607,16 @@ write_fsinfo(msdosfsmount* volume)
|
|||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* buffer = block_cache_get_writable(volume->pm_mountp->mnt_cache, volume->pm_fsinfo, -1);
|
off_t cachedBlock = BLOCK_TO_SECTOR(volume, volume->pm_fsinfo);
|
||||||
|
void* buffer = block_cache_get_writable(volume->pm_mountp->mnt_cache, cachedBlock, -1);
|
||||||
if (buffer == NULL)
|
if (buffer == NULL)
|
||||||
RETURN_ERROR(B_ERROR);
|
RETURN_ERROR(B_ERROR);
|
||||||
|
|
||||||
struct fsinfo* fsInfo = reinterpret_cast<struct fsinfo*>(buffer);
|
struct fsinfo* fsInfo = reinterpret_cast<struct fsinfo*>(buffer);
|
||||||
if (memcmp(fsInfo->fsisig1, "RRaA", 4) != 0 || memcmp(fsInfo->fsisig2, "rrAa", 4) != 0
|
if (memcmp(fsInfo->fsisig1, "RRaA", 4) != 0 || memcmp(fsInfo->fsisig2, "rrAa", 4) != 0
|
||||||
|| memcmp(fsInfo->fsisig3, "\0\0\125\252", 4) != 0) {
|
|| memcmp(fsInfo->fsisig3, "\0\0\125\252", 4) != 0) {
|
||||||
block_cache_set_dirty(volume->pm_mountp->mnt_cache, volume->pm_fsinfo, false, -1);
|
block_cache_set_dirty(volume->pm_mountp->mnt_cache, cachedBlock, false, -1);
|
||||||
block_cache_put(volume->pm_mountp->mnt_cache, volume->pm_fsinfo);
|
block_cache_put(volume->pm_mountp->mnt_cache, cachedBlock);
|
||||||
RETURN_ERROR(B_ERROR);
|
RETURN_ERROR(B_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -619,7 +624,7 @@ write_fsinfo(msdosfsmount* volume)
|
|||||||
putulong(fsInfo->fsinxtfree, volume->pm_nxtfree);
|
putulong(fsInfo->fsinxtfree, volume->pm_nxtfree);
|
||||||
volume->pm_flags &= ~MSDOSFS_FSIMOD;
|
volume->pm_flags &= ~MSDOSFS_FSIMOD;
|
||||||
|
|
||||||
block_cache_put(volume->pm_mountp->mnt_cache, volume->pm_fsinfo);
|
block_cache_put(volume->pm_mountp->mnt_cache, cachedBlock);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -632,32 +637,36 @@ write_fsinfo(msdosfsmount* volume)
|
|||||||
status_t
|
status_t
|
||||||
check_fat(const msdosfsmount* volume)
|
check_fat(const msdosfsmount* volume)
|
||||||
{
|
{
|
||||||
uint8 fatBuffer[512];
|
uint32 bytesPerSec = volume->pm_BytesPerSec;
|
||||||
uint8 mirrorBuffer[512];
|
uint32 fatSectors = volume->pm_FATsecs / volume->pm_BlkPerSec;
|
||||||
|
// pm_FATsecs is always in units of DEV_BSIZE
|
||||||
|
|
||||||
|
uint8 fatBuffer[bytesPerSec];
|
||||||
|
uint8 mirrorBuffer[bytesPerSec];
|
||||||
|
|
||||||
// For small FATs, check whether each FAT mirror matches the active FAT.
|
// For small FATs, check whether each FAT mirror matches the active FAT.
|
||||||
// For large FATs, that takes too long, so just check the first block of each FAT.
|
// For large FATs, that takes too long, so just check the first sector of each FAT.
|
||||||
uint32 checkBlocks = volume->pm_FATsecs > 4096 ? 1 : volume->pm_FATsecs;
|
uint32 checkSectors = fatSectors > 4096 ? 1 : fatSectors;
|
||||||
PRINT("check_fat checking %" B_PRIu32 " blocks\n", checkBlocks);
|
PRINT("check_fat checking %" B_PRIu32 " sectors\n", checkSectors);
|
||||||
|
|
||||||
// for each block
|
// for each sector
|
||||||
for (uint32 i = 0; i < checkBlocks; ++i) {
|
for (uint32 i = 0; i < checkSectors; ++i) {
|
||||||
// read a block from the first/active fat
|
// read a sector from the first/active fat
|
||||||
uint32 resBlocks = volume->pm_ResSectors * volume->pm_BlkPerSec;
|
uint32 resSectors = volume->pm_ResSectors;
|
||||||
off_t position = 512 * (resBlocks + volume->pm_curfat * volume->pm_FATsecs + i);
|
off_t position = bytesPerSec * (resSectors + volume->pm_curfat * fatSectors + i);
|
||||||
ssize_t bytes_read
|
ssize_t bytes_read
|
||||||
= read_pos(volume->pm_dev->si_fd, position, reinterpret_cast<void*>(fatBuffer), 0x200);
|
= read_pos(volume->pm_dev->si_fd, position, reinterpret_cast<void*>(fatBuffer), bytesPerSec);
|
||||||
if (bytes_read != 0x200)
|
if (bytes_read != static_cast<ssize_t>(bytesPerSec))
|
||||||
RETURN_ERROR(B_IO_ERROR);
|
RETURN_ERROR(B_IO_ERROR);
|
||||||
|
|
||||||
// for each mirror
|
// for each mirror
|
||||||
for (uint32 j = 0; j < volume->pm_FATs; ++j) {
|
for (uint32 j = 0; j < volume->pm_FATs; ++j) {
|
||||||
if (j == volume->pm_curfat)
|
if (j == volume->pm_curfat)
|
||||||
continue;
|
continue;
|
||||||
position = 512 * (resBlocks + volume->pm_FATsecs * j + i);
|
position = bytesPerSec * (resSectors + fatSectors * j + i);
|
||||||
bytes_read = read_pos(volume->pm_dev->si_fd, position,
|
bytes_read = read_pos(volume->pm_dev->si_fd, position,
|
||||||
reinterpret_cast<void*>(mirrorBuffer), 0x200);
|
reinterpret_cast<void*>(mirrorBuffer), bytesPerSec);
|
||||||
if (bytes_read != 0x200)
|
if (bytes_read != static_cast<ssize_t>(bytesPerSec))
|
||||||
RETURN_ERROR(B_IO_ERROR);
|
RETURN_ERROR(B_IO_ERROR);
|
||||||
|
|
||||||
if (i == 0 && mirrorBuffer[0] != volume->pm_Media) {
|
if (i == 0 && mirrorBuffer[0] != volume->pm_Media) {
|
||||||
@@ -670,7 +679,7 @@ check_fat(const msdosfsmount* volume)
|
|||||||
// checking for exact matches of fats is too
|
// checking for exact matches of fats is too
|
||||||
// restrictive; allow these to go through in
|
// restrictive; allow these to go through in
|
||||||
// case the fat is corrupted for some reason
|
// case the fat is corrupted for some reason
|
||||||
if (memcmp(fatBuffer, mirrorBuffer, 0x200)) {
|
if (memcmp(fatBuffer, mirrorBuffer, bytesPerSec)) {
|
||||||
INFORM("FAT %" B_PRIu32 " doesn't match active FAT (%u) on %s.\n"
|
INFORM("FAT %" B_PRIu32 " doesn't match active FAT (%u) on %s.\n"
|
||||||
"Install dosfstools and use fsck.fat to inspect %s.\n",
|
"Install dosfstools and use fsck.fat to inspect %s.\n",
|
||||||
j, volume->pm_curfat, volume->pm_dev->si_device, volume->pm_dev->si_device);
|
j, volume->pm_curfat, volume->pm_dev->si_device, volume->pm_dev->si_device);
|
||||||
@@ -1081,13 +1090,17 @@ sync_clusters(vnode* bsdNode)
|
|||||||
u_long cluster = fatNode->de_dirclust;
|
u_long cluster = fatNode->de_dirclust;
|
||||||
|
|
||||||
if (cluster == MSDOSFSROOT) {
|
if (cluster == MSDOSFSROOT) {
|
||||||
status = block_cache_sync_etc(bsdVolume->mnt_cache, fatVolume->pm_rootdirblk,
|
off_t cachedBlock = BLOCK_TO_SECTOR(fatVolume, fatVolume->pm_rootdirblk);
|
||||||
fatVolume->pm_rootdirsize);
|
size_t numBlocks =
|
||||||
|
HOWMANY(fatVolume->pm_rootdirsize * DEV_BSIZE, fatVolume->pm_BytesPerSec);
|
||||||
|
status = block_cache_sync_etc(bsdVolume->mnt_cache, cachedBlock, numBlocks);
|
||||||
} else {
|
} else {
|
||||||
status_t fatStatus = B_OK;
|
status_t fatStatus = B_OK;
|
||||||
while ((IS_DATA_CLUSTER(cluster)) && status == B_OK && fatStatus == B_OK) {
|
while ((IS_DATA_CLUSTER(cluster)) && status == B_OK && fatStatus == B_OK) {
|
||||||
status = block_cache_sync_etc(bsdVolume->mnt_cache, de_cn2bn(fatVolume, cluster),
|
off_t cachedBlock = BLOCK_TO_SECTOR(fatVolume, cntobn(fatVolume, cluster));
|
||||||
BLOCKS_PER_CLUSTER(fatVolume));
|
// changed from de_cn2bn
|
||||||
|
status = block_cache_sync_etc(bsdVolume->mnt_cache, cachedBlock,
|
||||||
|
SECTORS_PER_CLUSTER(fatVolume));
|
||||||
fatStatus = B_FROM_POSIX_ERROR(fatentry(FAT_GET, fatVolume, cluster, &cluster, 0));
|
fatStatus = B_FROM_POSIX_ERROR(fatentry(FAT_GET, fatVolume, cluster, &cluster, 0));
|
||||||
}
|
}
|
||||||
if (fatStatus != B_OK)
|
if (fatStatus != B_OK)
|
||||||
@@ -1117,14 +1130,14 @@ discard_clusters(vnode* bsdNode, off_t newLength)
|
|||||||
// Typically we are discarding all clusters associated with a directory. However, in
|
// Typically we are discarding all clusters associated with a directory. However, in
|
||||||
// the case of an error, the driver might shrink a directory to undo an attempted expansion,
|
// the case of an error, the driver might shrink a directory to undo an attempted expansion,
|
||||||
// as in createde.
|
// as in createde.
|
||||||
for (uint32 skip = howmany(newLength, fatVolume->pm_bpcluster); skip > 0 && status == B_OK;
|
for (uint32 skip = HOWMANY(newLength, fatVolume->pm_bpcluster); skip > 0 && status == B_OK;
|
||||||
skip--) {
|
skip--) {
|
||||||
status = B_FROM_POSIX_ERROR(fatentry(FAT_GET, fatVolume, cluster, &cluster, 0));
|
status = B_FROM_POSIX_ERROR(fatentry(FAT_GET, fatVolume, cluster, &cluster, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((IS_DATA_CLUSTER(cluster)) && status == B_OK) {
|
while ((IS_DATA_CLUSTER(cluster)) && status == B_OK) {
|
||||||
block_cache_discard(bsdVolume->mnt_cache, de_cn2bn(fatVolume, cluster),
|
off_t cachedBlock = BLOCK_TO_SECTOR(fatVolume, cntobn(fatVolume, cluster));
|
||||||
BLOCKS_PER_CLUSTER(fatVolume));
|
block_cache_discard(bsdVolume->mnt_cache, cachedBlock, SECTORS_PER_CLUSTER(fatVolume));
|
||||||
status = B_FROM_POSIX_ERROR(fatentry(FAT_GET, fatVolume, cluster, &cluster, 0));
|
status = B_FROM_POSIX_ERROR(fatentry(FAT_GET, fatVolume, cluster, &cluster, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user