Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/fs/fat/fat_ops.c

    r92bee46 red903174  
    4545#include <ipc/services.h>
    4646#include <ipc/devmap.h>
     47#include <macros.h>
    4748#include <async.h>
    4849#include <errno.h>
     
    7980static int fat_has_children(bool *, fs_node_t *);
    8081static fs_index_t fat_index_get(fs_node_t *);
    81 static size_t fat_size_get(fs_node_t *);
     82static aoff64_t fat_size_get(fs_node_t *);
    8283static unsigned fat_lnkcnt_get(fs_node_t *);
    8384static char fat_plb_get_char(unsigned);
     
    137138        rc = block_put(b);
    138139        return rc;
     140}
     141
     142static 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
     154restart:
     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;
    139199}
    140200
     
    290350
    291351        *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 media
    298  * descriptor. This is used to rule out cases when a device obviously
    299  * 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 root
    331          * directory and non-root directories uniformly in some places.
    332          * It can be removed provided that functions such as fat_read() are
    333          * 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 are
    356                  * set to one.
    357                  */
    358                 if ((e0 >> 8) != 0xff || e1 != 0xffff)
    359                         return ENOTSUP;
    360         }
    361 
    362352        return EOK;
    363353}
     
    733723        fibril_mutex_lock(&childp->idx->lock);
    734724       
    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) {
    743726                /*
    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.
    746732                 */
    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        }
    777770skip_dots:
    778771
     
    923916}
    924917
    925 size_t fat_size_get(fs_node_t *fn)
     918aoff64_t fat_size_get(fs_node_t *fn)
    926919{
    927920        return FAT_NODE(fn)->size;
     
    985978        uint16_t bps;
    986979        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        }
    1010989
    1011990        /* Check for option enabling write through. */
     
    1015994                cmode = CACHE_MODE_WB;
    1016995
     996        free(opts);
     997
    1017998        /* initialize libblock */
    1018999        rc = block_init(dev_handle, BS_SIZE);
     
    10541035        rc = fat_sanity_check(bs, dev_handle);
    10551036        if (rc != EOK) {
     1037                (void) block_cache_fini(dev_handle);
    10561038                block_fini(dev_handle);
    10571039                ipc_answer_0(rid, rc);
     
    10611043        rc = fat_idx_init_by_dev_handle(dev_handle);
    10621044        if (rc != EOK) {
     1045                (void) block_cache_fini(dev_handle);
    10631046                block_fini(dev_handle);
    10641047                ipc_answer_0(rid, rc);
     
    10691052        fs_node_t *rfn = (fs_node_t *)malloc(sizeof(fs_node_t));
    10701053        if (!rfn) {
     1054                (void) block_cache_fini(dev_handle);
    10711055                block_fini(dev_handle);
    10721056                fat_idx_fini_by_dev_handle(dev_handle);
     
    10781062        if (!rootp) {
    10791063                free(rfn);
     1064                (void) block_cache_fini(dev_handle);
    10801065                block_fini(dev_handle);
    10811066                fat_idx_fini_by_dev_handle(dev_handle);
     
    10891074                free(rfn);
    10901075                free(rootp);
     1076                (void) block_cache_fini(dev_handle);
    10911077                block_fini(dev_handle);
    10921078                fat_idx_fini_by_dev_handle(dev_handle);
     
    11171103}
    11181104
     1105void 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
     1148void fat_unmount(ipc_callid_t rid, ipc_call_t *request)
     1149{
     1150        libfs_unmount(&fat_libfs_ops, rid, request);
     1151}
     1152
    11191153void fat_lookup(ipc_callid_t rid, ipc_call_t *request)
    11201154{
     
    11241158void fat_read(ipc_callid_t rid, ipc_call_t *request)
    11251159{
    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));
    11291164        fs_node_t *fn;
    11301165        fat_node_t *nodep;
     
    11901225        } else {
    11911226                unsigned bnum;
    1192                 off_t spos = pos;
     1227                aoff64_t spos = pos;
    11931228                char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
    11941229                fat_dentry_t *d;
     
    12061241                bnum = (pos * sizeof(fat_dentry_t)) / bps;
    12071242                while (bnum < nodep->size / bps) {
    1208                         off_t o;
     1243                        aoff64_t o;
    12091244
    12101245                        rc = fat_block_get(&b, bs, nodep, bnum,
     
    12621297void fat_write(ipc_callid_t rid, ipc_call_t *request)
    12631298{
    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));
    12671303        fs_node_t *fn;
    12681304        fat_node_t *nodep;
     
    12731309        unsigned spc;
    12741310        unsigned bpc;           /* bytes per cluster */
    1275         off_t boundary;
     1311        aoff64_t boundary;
    12761312        int flags = BLOCK_FLAGS_NONE;
    12771313        int rc;
     
    14191455void fat_truncate(ipc_callid_t rid, ipc_call_t *request)
    14201456{
    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));
    14241461        fs_node_t *fn;
    14251462        fat_node_t *nodep;
Note: See TracChangeset for help on using the changeset viewer.