Changes in uspace/srv/fs/fat/fat_ops.c [92bee46:ed903174] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/fs/fat/fat_ops.c
r92bee46 red903174 45 45 #include <ipc/services.h> 46 46 #include <ipc/devmap.h> 47 #include <macros.h> 47 48 #include <async.h> 48 49 #include <errno.h> … … 79 80 static int fat_has_children(bool *, fs_node_t *); 80 81 static fs_index_t fat_index_get(fs_node_t *); 81 static size_t fat_size_get(fs_node_t *);82 static aoff64_t fat_size_get(fs_node_t *); 82 83 static unsigned fat_lnkcnt_get(fs_node_t *); 83 84 static char fat_plb_get_char(unsigned); … … 137 138 rc = block_put(b); 138 139 return rc; 140 } 141 142 static int fat_node_fini_by_dev_handle(dev_handle_t dev_handle) 143 { 144 link_t *lnk; 145 fat_node_t *nodep; 146 int rc; 147 148 /* 149 * We are called from fat_unmounted() and assume that there are already 150 * no nodes belonging to this instance with non-zero refcount. Therefore 151 * it is sufficient to clean up only the FAT free node list. 152 */ 153 154 restart: 155 fibril_mutex_lock(&ffn_mutex); 156 for (lnk = ffn_head.next; lnk != &ffn_head; lnk = lnk->next) { 157 nodep = list_get_instance(lnk, fat_node_t, ffn_link); 158 if (!fibril_mutex_trylock(&nodep->lock)) { 159 fibril_mutex_unlock(&ffn_mutex); 160 goto restart; 161 } 162 if (!fibril_mutex_trylock(&nodep->idx->lock)) { 163 fibril_mutex_unlock(&nodep->lock); 164 fibril_mutex_unlock(&ffn_mutex); 165 goto restart; 166 } 167 if (nodep->idx->dev_handle != dev_handle) { 168 fibril_mutex_unlock(&nodep->idx->lock); 169 fibril_mutex_unlock(&nodep->lock); 170 continue; 171 } 172 173 list_remove(&nodep->ffn_link); 174 fibril_mutex_unlock(&ffn_mutex); 175 176 /* 177 * We can unlock the node and its index structure because we are 178 * the last player on this playground and VFS is preventing new 179 * players from entering. 180 */ 181 fibril_mutex_unlock(&nodep->idx->lock); 182 fibril_mutex_unlock(&nodep->lock); 183 184 if (nodep->dirty) { 185 rc = fat_node_sync(nodep); 186 if (rc != EOK) 187 return rc; 188 } 189 nodep->idx->nodep = NULL; 190 free(nodep->bp); 191 free(nodep); 192 193 /* Need to restart because we changed the ffn_head list. */ 194 goto restart; 195 } 196 fibril_mutex_unlock(&ffn_mutex); 197 198 return EOK; 139 199 } 140 200 … … 290 350 291 351 *nodepp = nodep; 292 return EOK;293 }294 295 /** Perform basic sanity checks on the file system.296 *297 * Verify if values of boot sector fields are sane. Also verify media298 * descriptor. This is used to rule out cases when a device obviously299 * does not contain a fat file system.300 */301 static int fat_sanity_check(fat_bs_t *bs, dev_handle_t dev_handle)302 {303 fat_cluster_t e0, e1;304 unsigned fat_no;305 int rc;306 307 /* Check number of FATs. */308 if (bs->fatcnt == 0)309 return ENOTSUP;310 311 /* Check total number of sectors. */312 313 if (bs->totsec16 == 0 && bs->totsec32 == 0)314 return ENOTSUP;315 316 if (bs->totsec16 != 0 && bs->totsec32 != 0 &&317 bs->totsec16 != bs->totsec32)318 return ENOTSUP;319 320 /* Check media descriptor. Must be between 0xf0 and 0xff. */321 if ((bs->mdesc & 0xf0) != 0xf0)322 return ENOTSUP;323 324 /* Check number of sectors per FAT. */325 if (bs->sec_per_fat == 0)326 return ENOTSUP;327 328 /*329 * Check that the root directory entries take up whole blocks.330 * This check is rather strict, but it allows us to treat the root331 * directory and non-root directories uniformly in some places.332 * It can be removed provided that functions such as fat_read() are333 * sanitized to support file systems with this property.334 */335 if ((uint16_t_le2host(bs->root_ent_max) * sizeof(fat_dentry_t)) %336 uint16_t_le2host(bs->bps) != 0)337 return ENOTSUP;338 339 /* Check signature of each FAT. */340 341 for (fat_no = 0; fat_no < bs->fatcnt; fat_no++) {342 rc = fat_get_cluster(bs, dev_handle, fat_no, 0, &e0);343 if (rc != EOK)344 return EIO;345 346 rc = fat_get_cluster(bs, dev_handle, fat_no, 1, &e1);347 if (rc != EOK)348 return EIO;349 350 /* Check that first byte of FAT contains the media descriptor. */351 if ((e0 & 0xff) != bs->mdesc)352 return ENOTSUP;353 354 /*355 * Check that remaining bits of the first two entries are356 * set to one.357 */358 if ((e0 >> 8) != 0xff || e1 != 0xffff)359 return ENOTSUP;360 }361 362 352 return EOK; 363 353 } … … 733 723 fibril_mutex_lock(&childp->idx->lock); 734 724 735 /* 736 * If possible, create the Sub-directory Identifier Entry and the 737 * Sub-directory Parent Pointer Entry (i.e. "." and ".."). These entries 738 * are not mandatory according to Standard ECMA-107 and HelenOS VFS does 739 * not use them anyway, so this is rather a sign of our good will. 740 */ 741 rc = fat_block_get(&b, bs, childp, 0, BLOCK_FLAGS_NONE); 742 if (rc != EOK) { 725 if (childp->type == FAT_DIRECTORY) { 743 726 /* 744 * Rather than returning an error, simply skip the creation of 745 * these two entries. 727 * If possible, create the Sub-directory Identifier Entry and 728 * the Sub-directory Parent Pointer Entry (i.e. "." and ".."). 729 * These entries are not mandatory according to Standard 730 * ECMA-107 and HelenOS VFS does not use them anyway, so this is 731 * rather a sign of our good will. 746 732 */ 747 goto skip_dots; 748 } 749 d = (fat_dentry_t *)b->data; 750 if (fat_classify_dentry(d) == FAT_DENTRY_LAST || 751 str_cmp(d->name, FAT_NAME_DOT) == 0) { 752 memset(d, 0, sizeof(fat_dentry_t)); 753 str_cpy(d->name, 8, FAT_NAME_DOT); 754 str_cpy(d->ext, 3, FAT_EXT_PAD); 755 d->attr = FAT_ATTR_SUBDIR; 756 d->firstc = host2uint16_t_le(childp->firstc); 757 /* TODO: initialize also the date/time members. */ 758 } 759 d++; 760 if (fat_classify_dentry(d) == FAT_DENTRY_LAST || 761 str_cmp(d->name, FAT_NAME_DOT_DOT) == 0) { 762 memset(d, 0, sizeof(fat_dentry_t)); 763 str_cpy(d->name, 8, FAT_NAME_DOT_DOT); 764 str_cpy(d->ext, 3, FAT_EXT_PAD); 765 d->attr = FAT_ATTR_SUBDIR; 766 d->firstc = (parentp->firstc == FAT_CLST_ROOT) ? 767 host2uint16_t_le(FAT_CLST_RES0) : 768 host2uint16_t_le(parentp->firstc); 769 /* TODO: initialize also the date/time members. */ 770 } 771 b->dirty = true; /* need to sync block */ 772 /* 773 * Ignore the return value as we would have fallen through on error 774 * anyway. 775 */ 776 (void) block_put(b); 733 rc = fat_block_get(&b, bs, childp, 0, BLOCK_FLAGS_NONE); 734 if (rc != EOK) { 735 /* 736 * Rather than returning an error, simply skip the 737 * creation of these two entries. 738 */ 739 goto skip_dots; 740 } 741 d = (fat_dentry_t *) b->data; 742 if ((fat_classify_dentry(d) == FAT_DENTRY_LAST) || 743 (str_cmp((char *) d->name, FAT_NAME_DOT)) == 0) { 744 memset(d, 0, sizeof(fat_dentry_t)); 745 str_cpy((char *) d->name, 8, FAT_NAME_DOT); 746 str_cpy((char *) d->ext, 3, FAT_EXT_PAD); 747 d->attr = FAT_ATTR_SUBDIR; 748 d->firstc = host2uint16_t_le(childp->firstc); 749 /* TODO: initialize also the date/time members. */ 750 } 751 d++; 752 if ((fat_classify_dentry(d) == FAT_DENTRY_LAST) || 753 (str_cmp((char *) d->name, FAT_NAME_DOT_DOT) == 0)) { 754 memset(d, 0, sizeof(fat_dentry_t)); 755 str_cpy((char *) d->name, 8, FAT_NAME_DOT_DOT); 756 str_cpy((char *) d->ext, 3, FAT_EXT_PAD); 757 d->attr = FAT_ATTR_SUBDIR; 758 d->firstc = (parentp->firstc == FAT_CLST_ROOT) ? 759 host2uint16_t_le(FAT_CLST_RES0) : 760 host2uint16_t_le(parentp->firstc); 761 /* TODO: initialize also the date/time members. */ 762 } 763 b->dirty = true; /* need to sync block */ 764 /* 765 * Ignore the return value as we would have fallen through on error 766 * anyway. 767 */ 768 (void) block_put(b); 769 } 777 770 skip_dots: 778 771 … … 923 916 } 924 917 925 size_t fat_size_get(fs_node_t *fn)918 aoff64_t fat_size_get(fs_node_t *fn) 926 919 { 927 920 return FAT_NODE(fn)->size; … … 985 978 uint16_t bps; 986 979 uint16_t rde; 987 int rc; 988 989 /* accept the mount options */ 990 ipc_callid_t callid; 991 size_t size; 992 if (!async_data_write_receive(&callid, &size)) { 993 ipc_answer_0(callid, EINVAL); 994 ipc_answer_0(rid, EINVAL); 995 return; 996 } 997 char *opts = malloc(size + 1); 998 if (!opts) { 999 ipc_answer_0(callid, ENOMEM); 1000 ipc_answer_0(rid, ENOMEM); 1001 return; 1002 } 1003 ipcarg_t retval = async_data_write_finalize(callid, opts, size); 1004 if (retval != EOK) { 1005 ipc_answer_0(rid, retval); 1006 free(opts); 1007 return; 1008 } 1009 opts[size] = '\0'; 980 981 /* Accept the mount options */ 982 char *opts; 983 int rc = async_data_write_accept((void **) &opts, true, 0, 0, 0, NULL); 984 985 if (rc != EOK) { 986 ipc_answer_0(rid, rc); 987 return; 988 } 1010 989 1011 990 /* Check for option enabling write through. */ … … 1015 994 cmode = CACHE_MODE_WB; 1016 995 996 free(opts); 997 1017 998 /* initialize libblock */ 1018 999 rc = block_init(dev_handle, BS_SIZE); … … 1054 1035 rc = fat_sanity_check(bs, dev_handle); 1055 1036 if (rc != EOK) { 1037 (void) block_cache_fini(dev_handle); 1056 1038 block_fini(dev_handle); 1057 1039 ipc_answer_0(rid, rc); … … 1061 1043 rc = fat_idx_init_by_dev_handle(dev_handle); 1062 1044 if (rc != EOK) { 1045 (void) block_cache_fini(dev_handle); 1063 1046 block_fini(dev_handle); 1064 1047 ipc_answer_0(rid, rc); … … 1069 1052 fs_node_t *rfn = (fs_node_t *)malloc(sizeof(fs_node_t)); 1070 1053 if (!rfn) { 1054 (void) block_cache_fini(dev_handle); 1071 1055 block_fini(dev_handle); 1072 1056 fat_idx_fini_by_dev_handle(dev_handle); … … 1078 1062 if (!rootp) { 1079 1063 free(rfn); 1064 (void) block_cache_fini(dev_handle); 1080 1065 block_fini(dev_handle); 1081 1066 fat_idx_fini_by_dev_handle(dev_handle); … … 1089 1074 free(rfn); 1090 1075 free(rootp); 1076 (void) block_cache_fini(dev_handle); 1091 1077 block_fini(dev_handle); 1092 1078 fat_idx_fini_by_dev_handle(dev_handle); … … 1117 1103 } 1118 1104 1105 void fat_unmounted(ipc_callid_t rid, ipc_call_t *request) 1106 { 1107 dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request); 1108 fs_node_t *fn; 1109 fat_node_t *nodep; 1110 int rc; 1111 1112 rc = fat_root_get(&fn, dev_handle); 1113 if (rc != EOK) { 1114 ipc_answer_0(rid, rc); 1115 return; 1116 } 1117 nodep = FAT_NODE(fn); 1118 1119 /* 1120 * We expect exactly two references on the root node. One for the 1121 * fat_root_get() above and one created in fat_mounted(). 1122 */ 1123 if (nodep->refcnt != 2) { 1124 (void) fat_node_put(fn); 1125 ipc_answer_0(rid, EBUSY); 1126 return; 1127 } 1128 1129 /* 1130 * Put the root node and force it to the FAT free node list. 1131 */ 1132 (void) fat_node_put(fn); 1133 (void) fat_node_put(fn); 1134 1135 /* 1136 * Perform cleanup of the node structures, index structures and 1137 * associated data. Write back this file system's dirty blocks and 1138 * stop using libblock for this instance. 1139 */ 1140 (void) fat_node_fini_by_dev_handle(dev_handle); 1141 fat_idx_fini_by_dev_handle(dev_handle); 1142 (void) block_cache_fini(dev_handle); 1143 block_fini(dev_handle); 1144 1145 ipc_answer_0(rid, EOK); 1146 } 1147 1148 void fat_unmount(ipc_callid_t rid, ipc_call_t *request) 1149 { 1150 libfs_unmount(&fat_libfs_ops, rid, request); 1151 } 1152 1119 1153 void fat_lookup(ipc_callid_t rid, ipc_call_t *request) 1120 1154 { … … 1124 1158 void fat_read(ipc_callid_t rid, ipc_call_t *request) 1125 1159 { 1126 dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request); 1127 fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request); 1128 off_t pos = (off_t)IPC_GET_ARG3(*request); 1160 dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request); 1161 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request); 1162 aoff64_t pos = 1163 (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request)); 1129 1164 fs_node_t *fn; 1130 1165 fat_node_t *nodep; … … 1190 1225 } else { 1191 1226 unsigned bnum; 1192 off_t spos = pos;1227 aoff64_t spos = pos; 1193 1228 char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1]; 1194 1229 fat_dentry_t *d; … … 1206 1241 bnum = (pos * sizeof(fat_dentry_t)) / bps; 1207 1242 while (bnum < nodep->size / bps) { 1208 off_t o;1243 aoff64_t o; 1209 1244 1210 1245 rc = fat_block_get(&b, bs, nodep, bnum, … … 1262 1297 void fat_write(ipc_callid_t rid, ipc_call_t *request) 1263 1298 { 1264 dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request); 1265 fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request); 1266 off_t pos = (off_t)IPC_GET_ARG3(*request); 1299 dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request); 1300 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request); 1301 aoff64_t pos = 1302 (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request)); 1267 1303 fs_node_t *fn; 1268 1304 fat_node_t *nodep; … … 1273 1309 unsigned spc; 1274 1310 unsigned bpc; /* bytes per cluster */ 1275 off_t boundary;1311 aoff64_t boundary; 1276 1312 int flags = BLOCK_FLAGS_NONE; 1277 1313 int rc; … … 1419 1455 void fat_truncate(ipc_callid_t rid, ipc_call_t *request) 1420 1456 { 1421 dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request); 1422 fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request); 1423 size_t size = (off_t)IPC_GET_ARG3(*request); 1457 dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request); 1458 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request); 1459 aoff64_t size = 1460 (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request)); 1424 1461 fs_node_t *fn; 1425 1462 fat_node_t *nodep;
Note:
See TracChangeset
for help on using the changeset viewer.