/branches/dynload/uspace/lib/libblock/libblock.c |
---|
48,6 → 48,7 |
#include <assert.h> |
#include <futex.h> |
#include <libadt/list.h> |
#include <libadt/hash_table.h> |
/** Lock protecting the device connection list */ |
static futex_t dcl_lock = FUTEX_INITIALIZER; |
54,7 → 55,18 |
/** Device connection list head. */ |
static LIST_INITIALIZE(dcl_head); |
#define CACHE_BUCKETS_LOG2 10 |
#define CACHE_BUCKETS (1 << CACHE_BUCKETS_LOG2) |
typedef struct { |
futex_t lock; |
size_t block_size; /**< Block size. */ |
unsigned block_count; /**< Total number of blocks. */ |
hash_table_t block_hash; |
link_t free_head; |
} cache_t; |
typedef struct { |
link_t link; |
int dev_handle; |
int dev_phone; |
63,6 → 75,7 |
void *bb_buf; |
off_t bb_off; |
size_t bb_size; |
cache_t *cache; |
} devcon_t; |
static devcon_t *devcon_search(dev_handle_t dev_handle) |
82,7 → 95,7 |
} |
static int devcon_add(dev_handle_t dev_handle, int dev_phone, void *com_area, |
size_t com_size, void *bb_buf, off_t bb_off, size_t bb_size) |
size_t com_size) |
{ |
link_t *cur; |
devcon_t *devcon; |
96,9 → 109,10 |
devcon->dev_phone = dev_phone; |
devcon->com_area = com_area; |
devcon->com_size = com_size; |
devcon->bb_buf = bb_buf; |
devcon->bb_off = bb_off; |
devcon->bb_size = bb_size; |
devcon->bb_buf = NULL; |
devcon->bb_off = 0; |
devcon->bb_size = 0; |
devcon->cache = NULL; |
futex_down(&dcl_lock); |
for (cur = dcl_head.next; cur != &dcl_head; cur = cur->next) { |
121,23 → 135,15 |
futex_up(&dcl_lock); |
} |
int |
block_init(dev_handle_t dev_handle, size_t com_size, off_t bb_off, |
size_t bb_size) |
int block_init(dev_handle_t dev_handle, size_t com_size) |
{ |
int rc; |
int dev_phone; |
void *com_area; |
void *bb_buf; |
bb_buf = malloc(bb_size); |
if (!bb_buf) |
return ENOMEM; |
com_area = mmap(NULL, com_size, PROTO_READ | PROTO_WRITE, |
MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); |
if (!com_area) { |
free(bb_buf); |
return ENOMEM; |
} |
dev_phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP, |
144,7 → 150,6 |
DEVMAP_CONNECT_TO_DEVICE, dev_handle); |
if (dev_phone < 0) { |
free(bb_buf); |
munmap(com_area, com_size); |
return dev_phone; |
} |
152,29 → 157,18 |
rc = ipc_share_out_start(dev_phone, com_area, |
AS_AREA_READ | AS_AREA_WRITE); |
if (rc != EOK) { |
free(bb_buf); |
munmap(com_area, com_size); |
ipc_hangup(dev_phone); |
return rc; |
} |
rc = devcon_add(dev_handle, dev_phone, com_area, com_size, bb_buf, |
bb_off, bb_size); |
rc = devcon_add(dev_handle, dev_phone, com_area, com_size); |
if (rc != EOK) { |
free(bb_buf); |
munmap(com_area, com_size); |
ipc_hangup(dev_phone); |
return rc; |
} |
off_t bufpos = 0; |
size_t buflen = 0; |
if (!block_read(dev_handle, &bufpos, &buflen, &bb_off, |
bb_buf, bb_size, bb_size)) { |
block_fini(dev_handle); |
return EIO; /* XXX real error code */ |
} |
return EOK; |
} |
185,7 → 179,14 |
devcon_remove(devcon); |
free(devcon->bb_buf); |
if (devcon->bb_buf) |
free(devcon->bb_buf); |
if (devcon->cache) { |
hash_table_destroy(&devcon->cache->block_hash); |
free(devcon->cache); |
} |
munmap(devcon->com_area, devcon->com_size); |
ipc_hangup(devcon->dev_phone); |
192,6 → 193,35 |
free(devcon); |
} |
int block_bb_read(dev_handle_t dev_handle, off_t off, size_t size) |
{ |
void *bb_buf; |
int rc; |
devcon_t *devcon = devcon_search(dev_handle); |
if (!devcon) |
return ENOENT; |
if (devcon->bb_buf) |
return EEXIST; |
bb_buf = malloc(size); |
if (!bb_buf) |
return ENOMEM; |
off_t bufpos = 0; |
size_t buflen = 0; |
rc = block_read(dev_handle, &bufpos, &buflen, &off, |
bb_buf, size, size); |
if (rc != EOK) { |
free(bb_buf); |
return rc; |
} |
devcon->bb_buf = bb_buf; |
devcon->bb_off = off; |
devcon->bb_size = size; |
return EOK; |
} |
void *block_bb_get(dev_handle_t dev_handle) |
{ |
devcon_t *devcon = devcon_search(dev_handle); |
199,6 → 229,203 |
return devcon->bb_buf; |
} |
static hash_index_t cache_hash(unsigned long *key) |
{ |
return *key & (CACHE_BUCKETS - 1); |
} |
static int cache_compare(unsigned long *key, hash_count_t keys, link_t *item) |
{ |
block_t *b = hash_table_get_instance(item, block_t, hash_link); |
return b->boff == *key; |
} |
static void cache_remove_callback(link_t *item) |
{ |
} |
static hash_table_operations_t cache_ops = { |
.hash = cache_hash, |
.compare = cache_compare, |
.remove_callback = cache_remove_callback |
}; |
int block_cache_init(dev_handle_t dev_handle, size_t size, unsigned blocks) |
{ |
devcon_t *devcon = devcon_search(dev_handle); |
cache_t *cache; |
if (!devcon) |
return ENOENT; |
if (devcon->cache) |
return EEXIST; |
cache = malloc(sizeof(cache_t)); |
if (!cache) |
return ENOMEM; |
futex_initialize(&cache->lock, 1); |
list_initialize(&cache->free_head); |
cache->block_size = size; |
cache->block_count = blocks; |
if (!hash_table_create(&cache->block_hash, CACHE_BUCKETS, 1, |
&cache_ops)) { |
free(cache); |
return ENOMEM; |
} |
devcon->cache = cache; |
return EOK; |
} |
static bool cache_can_grow(cache_t *cache) |
{ |
return true; |
} |
static void block_initialize(block_t *b) |
{ |
futex_initialize(&b->lock, 1); |
b->refcnt = 1; |
b->dirty = false; |
rwlock_initialize(&b->contents_lock); |
link_initialize(&b->free_link); |
link_initialize(&b->hash_link); |
} |
/** Instantiate a block in memory and get a reference to it. |
* |
* @param dev_handle Device handle of the block device. |
* @param boff Block offset. |
* |
* @return Block structure. |
*/ |
block_t *block_get(dev_handle_t dev_handle, off_t boff) |
{ |
devcon_t *devcon; |
cache_t *cache; |
block_t *b; |
link_t *l; |
unsigned long key = boff; |
devcon = devcon_search(dev_handle); |
assert(devcon); |
assert(devcon->cache); |
cache = devcon->cache; |
futex_down(&cache->lock); |
l = hash_table_find(&cache->block_hash, &key); |
if (l) { |
/* |
* We found the block in the cache. |
*/ |
b = hash_table_get_instance(l, block_t, hash_link); |
futex_down(&b->lock); |
if (b->refcnt++ == 0) |
list_remove(&b->free_link); |
futex_up(&b->lock); |
futex_up(&cache->lock); |
} else { |
/* |
* The block was not found in the cache. |
*/ |
int rc; |
off_t bufpos = 0; |
size_t buflen = 0; |
off_t pos = boff * cache->block_size; |
bool sync = false; |
if (cache_can_grow(cache)) { |
/* |
* We can grow the cache by allocating new blocks. |
* Should the allocation fail, we fail over and try to |
* recycle a block from the cache. |
*/ |
b = malloc(sizeof(block_t)); |
if (!b) |
goto recycle; |
b->data = malloc(cache->block_size); |
if (!b->data) { |
free(b); |
goto recycle; |
} |
} else { |
/* |
* Try to recycle a block from the free list. |
*/ |
unsigned long temp_key; |
recycle: |
assert(!list_empty(&cache->free_head)); |
l = cache->free_head.next; |
list_remove(l); |
b = hash_table_get_instance(l, block_t, hash_link); |
sync = b->dirty; |
temp_key = b->boff; |
hash_table_remove(&cache->block_hash, &temp_key, 1); |
} |
block_initialize(b); |
b->dev_handle = dev_handle; |
b->size = cache->block_size; |
b->boff = boff; |
hash_table_insert(&cache->block_hash, &key, &b->hash_link); |
/* |
* Lock the block before releasing the cache lock. Thus we don't |
* kill concurent operations on the cache while doing I/O on the |
* block. |
*/ |
futex_down(&b->lock); |
futex_up(&cache->lock); |
if (sync) { |
/* |
* The block is dirty and needs to be written back to |
* the device before we can read in the new contents. |
*/ |
abort(); /* TODO: block_write() */ |
} |
/* |
* The block contains old or no data. We need to read the new |
* contents from the device. |
*/ |
rc = block_read(dev_handle, &bufpos, &buflen, &pos, b->data, |
cache->block_size, cache->block_size); |
assert(rc == EOK); |
futex_up(&b->lock); |
} |
return b; |
} |
/** Release a reference to a block. |
* |
* If the last reference is dropped, the block is put on the free list. |
* |
* @param block Block of which a reference is to be released. |
*/ |
void block_put(block_t *block) |
{ |
devcon_t *devcon = devcon_search(block->dev_handle); |
cache_t *cache; |
assert(devcon); |
assert(devcon->cache); |
cache = devcon->cache; |
futex_down(&cache->lock); |
futex_down(&block->lock); |
if (!--block->refcnt) { |
/* |
* Last reference to the block was dropped, put the block on the |
* free list. |
*/ |
list_append(&block->free_link, &cache->free_head); |
} |
futex_up(&block->lock); |
futex_up(&cache->lock); |
} |
/** Read data from a block device. |
* |
* @param dev_handle Device handle of the block device. |
211,9 → 438,9 |
* @param size Size of the destination buffer. |
* @param block_size Block size to be used for the transfer. |
* |
* @return True on success, false on failure. |
* @return EOK on success or a negative return code on failure. |
*/ |
bool |
int |
block_read(int dev_handle, off_t *bufpos, size_t *buflen, off_t *pos, void *dst, |
size_t size, size_t block_size) |
{ |
248,7 → 475,7 |
int rc = async_req_2_1(devcon->dev_phone, RD_READ_BLOCK, |
*pos / block_size, block_size, &retval); |
if ((rc != EOK) || (retval != EOK)) |
return false; |
return (rc != EOK ? rc : retval); |
*bufpos = 0; |
*buflen = block_size; |
255,44 → 482,8 |
} |
} |
return true; |
return EOK; |
} |
block_t *block_get(dev_handle_t dev_handle, off_t offset, size_t bs) |
{ |
/* FIXME */ |
block_t *b; |
off_t bufpos = 0; |
size_t buflen = 0; |
off_t pos = offset * bs; |
b = malloc(sizeof(block_t)); |
if (!b) |
return NULL; |
b->data = malloc(bs); |
if (!b->data) { |
free(b); |
return NULL; |
} |
b->size = bs; |
if (!block_read(dev_handle, &bufpos, &buflen, &pos, b->data, |
bs, bs)) { |
free(b->data); |
free(b); |
return NULL; |
} |
return b; |
} |
void block_put(block_t *block) |
{ |
/* FIXME */ |
free(block->data); |
free(block); |
} |
/** @} |
*/ |
/branches/dynload/uspace/lib/libblock/libblock.h |
---|
67,14 → 67,18 |
void *data; |
} block_t; |
extern int block_init(dev_handle_t, size_t, off_t, size_t); |
extern int block_init(dev_handle_t, size_t); |
extern void block_fini(dev_handle_t); |
extern int block_bb_read(dev_handle_t, off_t, size_t); |
extern void *block_bb_get(dev_handle_t); |
extern block_t *block_get(dev_handle_t, off_t, size_t); |
extern int block_cache_init(dev_handle_t, size_t, unsigned); |
extern block_t *block_get(dev_handle_t, off_t); |
extern void block_put(block_t *); |
extern bool block_read(int, off_t *, size_t *, off_t *, void *, size_t, size_t); |
extern int block_read(int, off_t *, size_t *, off_t *, void *, size_t, size_t); |
#endif |
/branches/dynload/uspace/srv/loader/main.c |
---|
247,7 → 247,7 |
if (prog_info.interp == NULL) { |
/* Statically linked program */ |
// printf("Run statically linked program\n"); |
// printf("entry point: 0x%llx\n", prog_info.entry); |
// printf("entry point: 0x%lx\n", prog_info.entry); |
is_dyn_linked = false; |
ipc_answer_0(rid, EOK); |
return 0; |
324,6 → 324,8 |
callid = async_get_call(&call); |
switch (IPC_GET_METHOD(call)) { |
case IPC_M_PHONE_HUNGUP: |
exit(0); |
case LOADER_GET_TASKID: |
loader_get_taskid(callid, &call); |
continue; |
/branches/dynload/uspace/srv/fs/tmpfs/tmpfs_dump.c |
---|
65,8 → 65,8 |
tmpfs_dentry_t *node; |
uint32_t size; |
if (!block_read(dev, bufpos, buflen, pos, &entry, sizeof(entry), |
TMPFS_BLOCK_SIZE)) |
if (block_read(dev, bufpos, buflen, pos, &entry, sizeof(entry), |
TMPFS_BLOCK_SIZE) != EOK) |
return false; |
entry.len = uint32_t_le2host(entry.len); |
85,8 → 85,8 |
return false; |
} |
if (!block_read(dev, bufpos, buflen, pos, fname, |
entry.len, TMPFS_BLOCK_SIZE)) { |
if (block_read(dev, bufpos, buflen, pos, fname, |
entry.len, TMPFS_BLOCK_SIZE) != EOK) { |
ops->destroy((void *) node); |
free(fname); |
return false; |
100,8 → 100,8 |
} |
free(fname); |
if (!block_read(dev, bufpos, buflen, pos, &size, |
sizeof(size), TMPFS_BLOCK_SIZE)) |
if (block_read(dev, bufpos, buflen, pos, &size, |
sizeof(size), TMPFS_BLOCK_SIZE) != EOK) |
return false; |
size = uint32_t_le2host(size); |
111,8 → 111,8 |
return false; |
node->size = size; |
if (!block_read(dev, bufpos, buflen, pos, node->data, |
size, TMPFS_BLOCK_SIZE)) |
if (block_read(dev, bufpos, buflen, pos, node->data, |
size, TMPFS_BLOCK_SIZE) != EOK) |
return false; |
break; |
127,8 → 127,8 |
return false; |
} |
if (!block_read(dev, bufpos, buflen, pos, |
fname, entry.len, TMPFS_BLOCK_SIZE)) { |
if (block_read(dev, bufpos, buflen, pos, fname, |
entry.len, TMPFS_BLOCK_SIZE) != EOK) { |
ops->destroy((void *) node); |
free(fname); |
return false; |
160,7 → 160,7 |
libfs_ops_t *ops = &tmpfs_libfs_ops; |
int rc; |
rc = block_init(dev, TMPFS_BLOCK_SIZE, 0, 0); |
rc = block_init(dev, TMPFS_BLOCK_SIZE); |
if (rc != EOK) |
return false; |
169,8 → 169,8 |
off_t pos = 0; |
char tag[6]; |
if (!block_read(dev, &bufpos, &buflen, &pos, tag, 5, |
TMPFS_BLOCK_SIZE)) |
if (block_read(dev, &bufpos, &buflen, &pos, tag, 5, |
TMPFS_BLOCK_SIZE) != EOK) |
goto error; |
tag[5] = 0; |
/branches/dynload/uspace/srv/fs/fat/fat.h |
---|
202,6 → 202,7 |
extern void fat_lookup(ipc_callid_t, ipc_call_t *); |
extern void fat_read(ipc_callid_t, ipc_call_t *); |
extern void fat_write(ipc_callid_t, ipc_call_t *); |
extern void fat_truncate(ipc_callid_t, ipc_call_t *); |
extern fat_idx_t *fat_idx_get_by_pos(dev_handle_t, fat_cluster_t, unsigned); |
extern fat_idx_t *fat_idx_get_by_index(dev_handle_t, fs_index_t); |
/branches/dynload/uspace/srv/fs/fat/fat_fat.c |
---|
54,127 → 54,118 |
*/ |
static futex_t fat_alloc_lock = FUTEX_INITIALIZER; |
/** Read block from file located on a FAT file system. |
/** Walk the cluster chain. |
* |
* @param bs Buffer holding the boot sector of the file system. |
* @param dev_handle Device handle of the file system. |
* @param firstc First cluster used by the file. Can be zero if the file |
* is empty. |
* @param offset Offset in blocks. |
* @param bs Buffer holding the boot sector for the file. |
* @param dev_handle Device handle of the device with the file. |
* @param firstc First cluster to start the walk with. |
* @param penult If non-NULL, output argument hodling the |
* the penultimate cluster visited. |
* @param ult If non-NULL, output argument holding the |
* ultimate cluster visited. |
* @param max_clusters Maximum number of clusters to visit. |
* |
* @return Block structure holding the requested block. |
* @return Number of clusters seen during the walk. |
*/ |
block_t * |
_fat_block_get(fat_bs_t *bs, dev_handle_t dev_handle, fat_cluster_t firstc, |
off_t offset) |
uint16_t |
fat_cluster_walk(fat_bs_t *bs, dev_handle_t dev_handle, fat_cluster_t firstc, |
fat_cluster_t *penult, fat_cluster_t *ult, uint16_t max_clusters) |
{ |
block_t *b; |
unsigned bps; |
unsigned spc; |
unsigned rscnt; /* block address of the first FAT */ |
unsigned fatcnt; |
unsigned rde; |
unsigned rds; /* root directory size */ |
unsigned sf; |
unsigned ssa; /* size of the system area */ |
unsigned clusters; |
uint16_t clusters = 0; |
fat_cluster_t clst = firstc; |
unsigned i; |
bps = uint16_t_le2host(bs->bps); |
spc = bs->spc; |
rscnt = uint16_t_le2host(bs->rscnt); |
fatcnt = bs->fatcnt; |
rde = uint16_t_le2host(bs->root_ent_max); |
sf = uint16_t_le2host(bs->sec_per_fat); |
rds = (sizeof(fat_dentry_t) * rde) / bps; |
rds += ((sizeof(fat_dentry_t) * rde) % bps != 0); |
ssa = rscnt + fatcnt * sf + rds; |
if (firstc == FAT_CLST_ROOT) { |
/* root directory special case */ |
assert(offset < rds); |
b = block_get(dev_handle, rscnt + fatcnt * sf + offset, bps); |
return b; |
if (firstc == FAT_CLST_RES0) { |
/* No space allocated to the file. */ |
if (ult) |
*ult = firstc; |
return 0; |
} |
clusters = offset / spc; |
for (i = 0; i < clusters; i++) { |
/* At this point, the meaning of penult is not well-defined. */ |
if (penult) |
*penult = FAT_CLST_RES0; |
while (clst < FAT_CLST_LAST1 && clusters < max_clusters) { |
unsigned fsec; /* sector offset relative to FAT1 */ |
unsigned fidx; /* FAT1 entry index */ |
assert(clst >= FAT_CLST_FIRST && clst < FAT_CLST_BAD); |
assert(clst >= FAT_CLST_FIRST); |
if (penult) |
*penult = clst; /* remember the penultimate cluster */ |
fsec = (clst * sizeof(fat_cluster_t)) / bps; |
fidx = clst % (bps / sizeof(fat_cluster_t)); |
/* read FAT1 */ |
b = block_get(dev_handle, rscnt + fsec, bps); |
b = block_get(dev_handle, rscnt + fsec); |
clst = uint16_t_le2host(((fat_cluster_t *)b->data)[fidx]); |
assert(clst != FAT_CLST_BAD); |
assert(clst < FAT_CLST_LAST1); |
block_put(b); |
clusters++; |
} |
b = block_get(dev_handle, ssa + (clst - FAT_CLST_FIRST) * spc + |
offset % spc, bps); |
if (ult) |
*ult = clst; |
return b; |
return clusters; |
} |
/** Return number of blocks allocated to a file. |
/** Read block from file located on a FAT file system. |
* |
* @param bs Buffer holding the boot sector for the file. |
* @param dev_handle Device handle of the device with the file. |
* @param firstc First cluster of the file. |
* @param lastc If non-NULL, output argument holding the |
* last cluster. |
* @param bs Buffer holding the boot sector of the file system. |
* @param dev_handle Device handle of the file system. |
* @param firstc First cluster used by the file. Can be zero if the file |
* is empty. |
* @param offset Offset in blocks. |
* |
* @return Number of blocks allocated to the file. |
* @return Block structure holding the requested block. |
*/ |
uint16_t |
_fat_blcks_get(fat_bs_t *bs, dev_handle_t dev_handle, fat_cluster_t firstc, |
fat_cluster_t *lastc) |
block_t * |
_fat_block_get(fat_bs_t *bs, dev_handle_t dev_handle, fat_cluster_t firstc, |
off_t offset) |
{ |
block_t *b; |
unsigned bps; |
unsigned spc; |
unsigned rscnt; /* block address of the first FAT */ |
unsigned clusters = 0; |
fat_cluster_t clst = firstc; |
unsigned rde; |
unsigned rds; /* root directory size */ |
unsigned sf; |
unsigned ssa; /* size of the system area */ |
unsigned clusters, max_clusters; |
fat_cluster_t lastc, clst = firstc; |
bps = uint16_t_le2host(bs->bps); |
spc = bs->spc; |
rscnt = uint16_t_le2host(bs->rscnt); |
rde = uint16_t_le2host(bs->root_ent_max); |
sf = uint16_t_le2host(bs->sec_per_fat); |
if (firstc == FAT_CLST_RES0) { |
/* No space allocated to the file. */ |
if (lastc) |
*lastc = firstc; |
return 0; |
rds = (sizeof(fat_dentry_t) * rde) / bps; |
rds += ((sizeof(fat_dentry_t) * rde) % bps != 0); |
ssa = rscnt + bs->fatcnt * sf + rds; |
if (firstc == FAT_CLST_ROOT) { |
/* root directory special case */ |
assert(offset < rds); |
b = block_get(dev_handle, rscnt + bs->fatcnt * sf + offset); |
return b; |
} |
while (clst < FAT_CLST_LAST1) { |
unsigned fsec; /* sector offset relative to FAT1 */ |
unsigned fidx; /* FAT1 entry index */ |
max_clusters = offset / bs->spc; |
clusters = fat_cluster_walk(bs, dev_handle, firstc, NULL, &lastc, |
max_clusters); |
assert(clusters == max_clusters); |
assert(clst >= FAT_CLST_FIRST); |
if (lastc) |
*lastc = clst; /* remember the last cluster */ |
fsec = (clst * sizeof(fat_cluster_t)) / bps; |
fidx = clst % (bps / sizeof(fat_cluster_t)); |
/* read FAT1 */ |
b = block_get(dev_handle, rscnt + fsec, bps); |
clst = uint16_t_le2host(((fat_cluster_t *)b->data)[fidx]); |
assert(clst != FAT_CLST_BAD); |
block_put(b); |
clusters++; |
} |
b = block_get(dev_handle, ssa + (lastc - FAT_CLST_FIRST) * bs->spc + |
offset % bs->spc); |
if (lastc) |
*lastc = clst; |
return clusters * spc; |
return b; |
} |
/** Fill the gap between EOF and a new file position. |
* |
* @param bs Buffer holding the boot sector for nodep. |
243,7 → 234,7 |
assert(fatno < bs->fatcnt); |
b = block_get(dev_handle, rscnt + sf * fatno + |
(clst * sizeof(fat_cluster_t)) / bps, bps); |
(clst * sizeof(fat_cluster_t)) / bps); |
cp = (fat_cluster_t *)b->data + clst % (bps / sizeof(fat_cluster_t)); |
*cp = host2uint16_t_le(value); |
b->dirty = true; /* need to sync block */ |
313,7 → 304,7 |
*/ |
futex_down(&fat_alloc_lock); |
for (b = 0, cl = 0; b < sf; blk++) { |
blk = block_get(dev_handle, rscnt + b, bps); |
blk = block_get(dev_handle, rscnt + b); |
for (c = 0; c < bps / sizeof(fat_cluster_t); c++, cl++) { |
fat_cluster_t *clst = (fat_cluster_t *)blk->data + c; |
if (uint16_t_le2host(*clst) == FAT_CLST_RES0) { |
369,7 → 360,9 |
fat_cluster_t lcl; |
uint8_t fatno; |
if (_fat_blcks_get(bs, dev_handle, nodep->firstc, &lcl) == 0) { |
if (fat_cluster_walk(bs, nodep->idx->dev_handle, nodep->firstc, &lcl, |
NULL, (uint16_t) -1) == 0) { |
/* No clusters allocated to the node yet. */ |
nodep->firstc = host2uint16_t_le(mcl); |
nodep->dirty = true; /* need to sync node */ |
return; |
/branches/dynload/uspace/srv/fs/fat/fat_fat.h |
---|
57,13 → 57,15 |
typedef uint16_t fat_cluster_t; |
#define fat_clusters_get(bs, dh, fc) \ |
fat_cluster_walk((bs), (dh), (fc), NULL, NULL, (uint16_t) -1) |
#define fat_block_get(bs, np, off) \ |
_fat_block_get((bs), (np)->idx->dev_handle, (np)->firstc, (off)) |
extern struct block *_fat_block_get(struct fat_bs *, dev_handle_t, |
fat_cluster_t, off_t); |
extern uint16_t _fat_blcks_get(struct fat_bs *, dev_handle_t, fat_cluster_t, |
fat_cluster_t *); |
extern uint16_t fat_cluster_walk(struct fat_bs *, dev_handle_t, fat_cluster_t, |
fat_cluster_t *, fat_cluster_t *, uint16_t); |
extern void fat_append_clusters(struct fat_bs *, struct fat_node *, |
fat_cluster_t); |
/branches/dynload/uspace/srv/fs/fat/fat.c |
---|
113,6 → 113,9 |
case VFS_WRITE: |
fat_write(callid, &call); |
break; |
case VFS_TRUNCATE: |
fat_truncate(callid, &call); |
break; |
default: |
ipc_answer_0(callid, ENOTSUP); |
break; |
/branches/dynload/uspace/srv/fs/fat/fat_ops.c |
---|
113,6 → 113,7 |
fat_dentry_t *d; |
fat_node_t *nodep = NULL; |
unsigned bps; |
unsigned spc; |
unsigned dps; |
if (idxp->nodep) { |
164,6 → 165,7 |
bs = block_bb_get(idxp->dev_handle); |
bps = uint16_t_le2host(bs->bps); |
spc = bs->spc; |
dps = bps / sizeof(fat_dentry_t); |
/* Read the block that contains the dentry of interest. */ |
184,8 → 186,8 |
* defined for the directory entry type. We must determine the |
* size of the directory by walking the FAT. |
*/ |
nodep->size = bps * _fat_blcks_get(bs, idxp->dev_handle, |
uint16_t_le2host(d->firstc), NULL); |
nodep->size = bps * spc * fat_clusters_get(bs, idxp->dev_handle, |
uint16_t_le2host(d->firstc)); |
} else { |
nodep->type = FAT_FILE; |
nodep->size = uint32_t_le2host(d->size); |
434,12 → 436,20 |
int rc; |
/* initialize libblock */ |
rc = block_init(dev_handle, BS_SIZE, BS_BLOCK * BS_SIZE, BS_SIZE); |
rc = block_init(dev_handle, BS_SIZE); |
if (rc != EOK) { |
ipc_answer_0(rid, 0); |
ipc_answer_0(rid, rc); |
return; |
} |
/* prepare the boot block */ |
rc = block_bb_read(dev_handle, BS_BLOCK * BS_SIZE, BS_SIZE); |
if (rc != EOK) { |
block_fini(dev_handle); |
ipc_answer_0(rid, rc); |
return; |
} |
/* get the buffer with the boot sector */ |
bs = block_bb_get(dev_handle); |
453,6 → 463,14 |
return; |
} |
/* Initialize the block cache */ |
rc = block_cache_init(dev_handle, bps, 0 /* XXX */); |
if (rc != EOK) { |
block_fini(dev_handle); |
ipc_answer_0(rid, rc); |
return; |
} |
rc = fat_idx_init_by_dev_handle(dev_handle); |
if (rc != EOK) { |
block_fini(dev_handle); |
623,13 → 641,6 |
return; |
} |
/* XXX remove me when you are ready */ |
{ |
ipc_answer_0(rid, ENOTSUP); |
fat_node_put(nodep); |
return; |
} |
ipc_callid_t callid; |
size_t len; |
if (!ipc_data_write_receive(&callid, &len)) { |
680,8 → 691,8 |
*/ |
int status; |
unsigned nclsts; |
fat_cluster_t mcl, lcl; |
fat_cluster_t mcl, lcl; |
nclsts = (ROUND_UP(pos + bytes, bps * spc) - boundary) / |
bps * spc; |
/* create an independent chain of nclsts clusters in all FATs */ |
696,8 → 707,7 |
} |
/* zero fill any gaps */ |
fat_fill_gap(bs, nodep, mcl, pos); |
b = _fat_block_get(bs, dev_handle, lcl, |
(pos / bps) % spc); |
b = _fat_block_get(bs, dev_handle, lcl, (pos / bps) % spc); |
(void) ipc_data_write_finalize(callid, b->data + pos % bps, |
bytes); |
b->dirty = true; /* need to sync block */ |
715,6 → 725,39 |
} |
} |
void fat_truncate(ipc_callid_t rid, ipc_call_t *request) |
{ |
dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request); |
fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request); |
size_t size = (off_t)IPC_GET_ARG3(*request); |
fat_node_t *nodep = (fat_node_t *)fat_node_get(dev_handle, index); |
int rc; |
if (!nodep) { |
ipc_answer_0(rid, ENOENT); |
return; |
} |
if (nodep->size == size) { |
rc = EOK; |
} else if (nodep->size < size) { |
/* |
* TODO: the standard says we have the freedom to grow the file. |
* For now, we simply return an error. |
*/ |
rc = EINVAL; |
} else { |
/* |
* The file is to be shrunk. |
*/ |
rc = ENOTSUP; /* XXX */ |
} |
fat_node_put(nodep); |
ipc_answer_0(rid, rc); |
return; |
} |
/** |
* @} |
*/ |