Changeset 0fc1e5d in mainline
- Timestamp:
- 2009-10-01T11:09:38Z (15 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 9a15176
- Parents:
- 17bf658
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/fs/fat/fat_ops.c
r17bf658 r0fc1e5d 65 65 static LIST_INITIALIZE(ffn_head); 66 66 67 static void fat_node_initialize(fat_node_t *node)68 {69 fibril_mutex_initialize(&node->lock);70 node->bp = NULL;71 node->idx = NULL;72 node->type = 0;73 link_initialize(&node->ffn_link);74 node->size = 0;75 node->lnkcnt = 0;76 node->refcnt = 0;77 node->dirty = false;78 }79 80 static int fat_node_sync(fat_node_t *node)81 {82 block_t *b;83 fat_bs_t *bs;84 fat_dentry_t *d;85 uint16_t bps;86 unsigned dps;87 int rc;88 89 assert(node->dirty);90 91 bs = block_bb_get(node->idx->dev_handle);92 bps = uint16_t_le2host(bs->bps);93 dps = bps / sizeof(fat_dentry_t);94 95 /* Read the block that contains the dentry of interest. */96 rc = _fat_block_get(&b, bs, node->idx->dev_handle, node->idx->pfc,97 (node->idx->pdi * sizeof(fat_dentry_t)) / bps, BLOCK_FLAGS_NONE);98 if (rc != EOK)99 return rc;100 101 d = ((fat_dentry_t *)b->data) + (node->idx->pdi % dps);102 103 d->firstc = host2uint16_t_le(node->firstc);104 if (node->type == FAT_FILE) {105 d->size = host2uint32_t_le(node->size);106 } else if (node->type == FAT_DIRECTORY) {107 d->attr = FAT_ATTR_SUBDIR;108 }109 110 /* TODO: update other fields? (e.g time fields) */111 112 b->dirty = true; /* need to sync block */113 rc = block_put(b);114 return rc;115 }116 117 static int fat_node_get_new(fat_node_t **nodepp)118 {119 fs_node_t *fn;120 fat_node_t *nodep;121 int rc;122 123 fibril_mutex_lock(&ffn_mutex);124 if (!list_empty(&ffn_head)) {125 /* Try to use a cached free node structure. */126 fat_idx_t *idxp_tmp;127 nodep = list_get_instance(ffn_head.next, fat_node_t, ffn_link);128 if (!fibril_mutex_trylock(&nodep->lock))129 goto skip_cache;130 idxp_tmp = nodep->idx;131 if (!fibril_mutex_trylock(&idxp_tmp->lock)) {132 fibril_mutex_unlock(&nodep->lock);133 goto skip_cache;134 }135 list_remove(&nodep->ffn_link);136 fibril_mutex_unlock(&ffn_mutex);137 if (nodep->dirty) {138 rc = fat_node_sync(nodep);139 if (rc != EOK) {140 idxp_tmp->nodep = NULL;141 fibril_mutex_unlock(&nodep->lock);142 fibril_mutex_unlock(&idxp_tmp->lock);143 free(nodep->bp);144 free(nodep);145 return rc;146 }147 }148 idxp_tmp->nodep = NULL;149 fibril_mutex_unlock(&nodep->lock);150 fibril_mutex_unlock(&idxp_tmp->lock);151 fn = FS_NODE(nodep);152 } else {153 skip_cache:154 /* Try to allocate a new node structure. */155 fibril_mutex_unlock(&ffn_mutex);156 fn = (fs_node_t *)malloc(sizeof(fs_node_t));157 if (!fn)158 return ENOMEM;159 nodep = (fat_node_t *)malloc(sizeof(fat_node_t));160 if (!nodep) {161 free(fn);162 return ENOMEM;163 }164 }165 fat_node_initialize(nodep);166 fs_node_initialize(fn);167 fn->data = nodep;168 nodep->bp = fn;169 170 *nodepp = nodep;171 return EOK;172 }173 174 /** Internal version of fat_node_get().175 *176 * @param idxp Locked index structure.177 */178 static fat_node_t *fat_node_get_core(fat_idx_t *idxp)179 {180 block_t *b;181 fat_bs_t *bs;182 fat_dentry_t *d;183 fat_node_t *nodep = NULL;184 unsigned bps;185 unsigned spc;186 unsigned dps;187 int rc;188 189 if (idxp->nodep) {190 /*191 * We are lucky.192 * The node is already instantiated in memory.193 */194 fibril_mutex_lock(&idxp->nodep->lock);195 if (!idxp->nodep->refcnt++) {196 fibril_mutex_lock(&ffn_mutex);197 list_remove(&idxp->nodep->ffn_link);198 fibril_mutex_unlock(&ffn_mutex);199 }200 fibril_mutex_unlock(&idxp->nodep->lock);201 return idxp->nodep;202 }203 204 /*205 * We must instantiate the node from the file system.206 */207 208 assert(idxp->pfc);209 210 rc = fat_node_get_new(&nodep);211 if (rc != EOK)212 return NULL;213 214 bs = block_bb_get(idxp->dev_handle);215 bps = uint16_t_le2host(bs->bps);216 spc = bs->spc;217 dps = bps / sizeof(fat_dentry_t);218 219 /* Read the block that contains the dentry of interest. */220 rc = _fat_block_get(&b, bs, idxp->dev_handle, idxp->pfc,221 (idxp->pdi * sizeof(fat_dentry_t)) / bps, BLOCK_FLAGS_NONE);222 assert(rc == EOK);223 224 d = ((fat_dentry_t *)b->data) + (idxp->pdi % dps);225 if (d->attr & FAT_ATTR_SUBDIR) {226 /*227 * The only directory which does not have this bit set is the228 * root directory itself. The root directory node is handled229 * and initialized elsewhere.230 */231 nodep->type = FAT_DIRECTORY;232 /*233 * Unfortunately, the 'size' field of the FAT dentry is not234 * defined for the directory entry type. We must determine the235 * size of the directory by walking the FAT.236 */237 uint16_t clusters;238 rc = fat_clusters_get(&clusters, bs, idxp->dev_handle,239 uint16_t_le2host(d->firstc));240 assert(rc == EOK);241 nodep->size = bps * spc * clusters;242 } else {243 nodep->type = FAT_FILE;244 nodep->size = uint32_t_le2host(d->size);245 }246 nodep->firstc = uint16_t_le2host(d->firstc);247 nodep->lnkcnt = 1;248 nodep->refcnt = 1;249 250 rc = block_put(b);251 assert(rc == EOK);252 253 /* Link the idx structure with the node structure. */254 nodep->idx = idxp;255 idxp->nodep = nodep;256 257 return nodep;258 }259 260 67 /* 261 68 * Forward declarations of FAT libfs operations. … … 276 83 static bool fat_is_directory(fs_node_t *); 277 84 static bool fat_is_file(fs_node_t *node); 85 86 /* 87 * Helper functions. 88 */ 89 static void fat_node_initialize(fat_node_t *node) 90 { 91 fibril_mutex_initialize(&node->lock); 92 node->bp = NULL; 93 node->idx = NULL; 94 node->type = 0; 95 link_initialize(&node->ffn_link); 96 node->size = 0; 97 node->lnkcnt = 0; 98 node->refcnt = 0; 99 node->dirty = false; 100 } 101 102 static int fat_node_sync(fat_node_t *node) 103 { 104 block_t *b; 105 fat_bs_t *bs; 106 fat_dentry_t *d; 107 uint16_t bps; 108 unsigned dps; 109 int rc; 110 111 assert(node->dirty); 112 113 bs = block_bb_get(node->idx->dev_handle); 114 bps = uint16_t_le2host(bs->bps); 115 dps = bps / sizeof(fat_dentry_t); 116 117 /* Read the block that contains the dentry of interest. */ 118 rc = _fat_block_get(&b, bs, node->idx->dev_handle, node->idx->pfc, 119 (node->idx->pdi * sizeof(fat_dentry_t)) / bps, BLOCK_FLAGS_NONE); 120 if (rc != EOK) 121 return rc; 122 123 d = ((fat_dentry_t *)b->data) + (node->idx->pdi % dps); 124 125 d->firstc = host2uint16_t_le(node->firstc); 126 if (node->type == FAT_FILE) { 127 d->size = host2uint32_t_le(node->size); 128 } else if (node->type == FAT_DIRECTORY) { 129 d->attr = FAT_ATTR_SUBDIR; 130 } 131 132 /* TODO: update other fields? (e.g time fields) */ 133 134 b->dirty = true; /* need to sync block */ 135 rc = block_put(b); 136 return rc; 137 } 138 139 static int fat_node_get_new(fat_node_t **nodepp) 140 { 141 fs_node_t *fn; 142 fat_node_t *nodep; 143 int rc; 144 145 fibril_mutex_lock(&ffn_mutex); 146 if (!list_empty(&ffn_head)) { 147 /* Try to use a cached free node structure. */ 148 fat_idx_t *idxp_tmp; 149 nodep = list_get_instance(ffn_head.next, fat_node_t, ffn_link); 150 if (!fibril_mutex_trylock(&nodep->lock)) 151 goto skip_cache; 152 idxp_tmp = nodep->idx; 153 if (!fibril_mutex_trylock(&idxp_tmp->lock)) { 154 fibril_mutex_unlock(&nodep->lock); 155 goto skip_cache; 156 } 157 list_remove(&nodep->ffn_link); 158 fibril_mutex_unlock(&ffn_mutex); 159 if (nodep->dirty) { 160 rc = fat_node_sync(nodep); 161 if (rc != EOK) { 162 idxp_tmp->nodep = NULL; 163 fibril_mutex_unlock(&nodep->lock); 164 fibril_mutex_unlock(&idxp_tmp->lock); 165 free(nodep->bp); 166 free(nodep); 167 return rc; 168 } 169 } 170 idxp_tmp->nodep = NULL; 171 fibril_mutex_unlock(&nodep->lock); 172 fibril_mutex_unlock(&idxp_tmp->lock); 173 fn = FS_NODE(nodep); 174 } else { 175 skip_cache: 176 /* Try to allocate a new node structure. */ 177 fibril_mutex_unlock(&ffn_mutex); 178 fn = (fs_node_t *)malloc(sizeof(fs_node_t)); 179 if (!fn) 180 return ENOMEM; 181 nodep = (fat_node_t *)malloc(sizeof(fat_node_t)); 182 if (!nodep) { 183 free(fn); 184 return ENOMEM; 185 } 186 } 187 fat_node_initialize(nodep); 188 fs_node_initialize(fn); 189 fn->data = nodep; 190 nodep->bp = fn; 191 192 *nodepp = nodep; 193 return EOK; 194 } 195 196 /** Internal version of fat_node_get(). 197 * 198 * @param idxp Locked index structure. 199 */ 200 static int fat_node_get_core(fat_node_t **nodepp, fat_idx_t *idxp) 201 { 202 block_t *b; 203 fat_bs_t *bs; 204 fat_dentry_t *d; 205 fat_node_t *nodep = NULL; 206 unsigned bps; 207 unsigned spc; 208 unsigned dps; 209 int rc; 210 211 if (idxp->nodep) { 212 /* 213 * We are lucky. 214 * The node is already instantiated in memory. 215 */ 216 fibril_mutex_lock(&idxp->nodep->lock); 217 if (!idxp->nodep->refcnt++) { 218 fibril_mutex_lock(&ffn_mutex); 219 list_remove(&idxp->nodep->ffn_link); 220 fibril_mutex_unlock(&ffn_mutex); 221 } 222 fibril_mutex_unlock(&idxp->nodep->lock); 223 *nodepp = idxp->nodep; 224 return EOK; 225 } 226 227 /* 228 * We must instantiate the node from the file system. 229 */ 230 231 assert(idxp->pfc); 232 233 rc = fat_node_get_new(&nodep); 234 if (rc != EOK) 235 return rc; 236 237 bs = block_bb_get(idxp->dev_handle); 238 bps = uint16_t_le2host(bs->bps); 239 spc = bs->spc; 240 dps = bps / sizeof(fat_dentry_t); 241 242 /* Read the block that contains the dentry of interest. */ 243 rc = _fat_block_get(&b, bs, idxp->dev_handle, idxp->pfc, 244 (idxp->pdi * sizeof(fat_dentry_t)) / bps, BLOCK_FLAGS_NONE); 245 if (rc != EOK) { 246 (void) fat_node_put(FS_NODE(nodep)); 247 return rc; 248 } 249 250 d = ((fat_dentry_t *)b->data) + (idxp->pdi % dps); 251 if (d->attr & FAT_ATTR_SUBDIR) { 252 /* 253 * The only directory which does not have this bit set is the 254 * root directory itself. The root directory node is handled 255 * and initialized elsewhere. 256 */ 257 nodep->type = FAT_DIRECTORY; 258 /* 259 * Unfortunately, the 'size' field of the FAT dentry is not 260 * defined for the directory entry type. We must determine the 261 * size of the directory by walking the FAT. 262 */ 263 uint16_t clusters; 264 rc = fat_clusters_get(&clusters, bs, idxp->dev_handle, 265 uint16_t_le2host(d->firstc)); 266 if (rc != EOK) { 267 (void) fat_node_put(FS_NODE(nodep)); 268 return rc; 269 } 270 nodep->size = bps * spc * clusters; 271 } else { 272 nodep->type = FAT_FILE; 273 nodep->size = uint32_t_le2host(d->size); 274 } 275 nodep->firstc = uint16_t_le2host(d->firstc); 276 nodep->lnkcnt = 1; 277 nodep->refcnt = 1; 278 279 rc = block_put(b); 280 if (rc != EOK) { 281 (void) fat_node_put(FS_NODE(nodep)); 282 return rc; 283 } 284 285 /* Link the idx structure with the node structure. */ 286 nodep->idx = idxp; 287 idxp->nodep = nodep; 288 289 *nodepp = nodep; 290 return EOK; 291 } 278 292 279 293 /* … … 351 365 return ENOMEM; 352 366 } 353 nodep = fat_node_get_core(idx); 367 rc = fat_node_get_core(&nodep, idx); 368 assert(rc == EOK); 354 369 fibril_mutex_unlock(&idx->lock); 355 370 rc = block_put(b); … … 374 389 fat_node_t *nodep; 375 390 fat_idx_t *idxp; 391 int rc; 376 392 377 393 idxp = fat_idx_get_by_index(dev_handle, index); … … 381 397 } 382 398 /* idxp->lock held */ 383 nodep = fat_node_get_core(idxp);399 rc = fat_node_get_core(&nodep, idxp); 384 400 fibril_mutex_unlock(&idxp->lock); 385 *rfn = FS_NODE(nodep); 386 return EOK; 401 if (rc == EOK) 402 *rfn = FS_NODE(nodep); 403 return rc; 387 404 } 388 405
Note:
See TracChangeset
for help on using the changeset viewer.