Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/volsrv/empty.c

    r5772aa1 r363a504  
    3838#include <errno.h>
    3939#include <io/log.h>
    40 #include <label/empty.h>
    4140#include <loc.h>
    4241#include <stdlib.h>
     
    4443#include "empty.h"
    4544
    46 static int empty_get_bsize(void *, size_t *);
    47 static int empty_get_nblocks(void *, aoff64_t *);
    48 static int empty_read(void *, aoff64_t, size_t, void *);
    49 static int empty_write(void *, aoff64_t, size_t, const void *);
    50 
    51 /** Provide disk access to liblabel */
    52 static label_bd_ops_t empty_bd_ops = {
    53         .get_bsize = empty_get_bsize,
    54         .get_nblocks = empty_get_nblocks,
    55         .read = empty_read,
    56         .write = empty_write
     45/*
     46 * The partition will be considered empty if at least a minimum number of
     47 * bytes *and* blocks (whichever is larger) at the beginning and end of
     48 * the partition is zero.
     49 */
     50enum {
     51        min_empty_bytes = 16384,
     52        /*
     53         * First block in ISO 9660 that cannot be empty is the first
     54         * volume descriptor at LBA 16
     55         */
     56        min_empty_blocks = 17
    5757};
    5858
     59static bool mem_is_zero(void *buf, size_t size)
     60{
     61        uint8_t *bp;
     62        size_t i;
     63
     64        bp = (uint8_t *)buf;
     65        for (i = 0; i < size; i++) {
     66                if (bp[i] != 0)
     67                        return false;
     68        }
     69
     70        return true;
     71}
     72
     73/** Calculate number of blocks to check.
     74 *
     75 * Will store to @a *ncb the number of blocks that should be checked
     76 * at the beginning and end of device each.
     77 *
     78 * @param nblocks Total number of blocks on block device
     79 * @param block_size Block size
     80 * @param ncb Place to store number of blocks to check.
     81 */
     82static void calc_num_check_blocks(aoff64_t nblocks, size_t block_size,
     83    aoff64_t *ncb)
     84{
     85        aoff64_t n;
     86
     87        /* Check first 16 kiB / 16 blocks, whichever is more */
     88        n = (min_empty_bytes + block_size - 1) / block_size;
     89        if (n < min_empty_blocks)
     90                n = min_empty_blocks;
     91        /*
     92         * Limit to half of the device so we do not process the same blocks
     93         * twice
     94         */
     95        if (n > (nblocks + 1) / 2)
     96                n = (nblocks + 1) / 2;
     97
     98        *ncb = n;
     99}
     100
    59101int volsrv_part_is_empty(service_id_t sid, bool *rempty)
    60102{
    61103        int rc;
    62         label_bd_t lbd;
     104        bool block_inited = false;
     105        void *buf = NULL;
     106        aoff64_t nblocks;
     107        aoff64_t n;
     108        aoff64_t i;
     109        size_t block_size;
     110        bool empty;
    63111
    64112        rc = block_init(sid, 2048);
     
    66114                log_msg(LOG_DEFAULT, LVL_ERROR, "Error opening "
    67115                    "block device service %zu", sid);
    68                 return EIO;
    69         }
    70 
    71         lbd.ops = &empty_bd_ops;
    72         lbd.arg = (void *)&sid;
    73 
    74         rc = label_bd_is_empty(&lbd, rempty);
    75 
     116                rc = EIO;
     117                goto error;
     118        }
     119
     120        block_inited = true;
     121
     122        rc = block_get_bsize(sid, &block_size);
     123        if (rc != EOK) {
     124                log_msg(LOG_DEFAULT, LVL_ERROR, "Error getting "
     125                    "block size.");
     126                rc = EIO;
     127                goto error;
     128        }
     129
     130        rc = block_get_nblocks(sid, &nblocks);
     131        if (rc != EOK) {
     132                log_msg(LOG_DEFAULT, LVL_ERROR, "Error getting "
     133                    "number of blocks.");
     134                rc = EIO;
     135                goto error;
     136        }
     137
     138        calc_num_check_blocks(nblocks, block_size, &n);
     139
     140        buf = calloc(block_size, 1);
     141        if (buf == NULL) {
     142                log_msg(LOG_DEFAULT, LVL_ERROR, "Error allocating buffer.");
     143                rc = ENOMEM;
     144                goto error;
     145        }
     146
     147        empty = true;
     148
     149        for (i = 0; i < n; i++) {
     150                rc = block_read_direct(sid, i, 1, buf);
     151                if (rc != EOK) {
     152                        log_msg(LOG_DEFAULT, LVL_ERROR, "Error "
     153                            "reading blocks.");
     154                        rc = EIO;
     155                        goto error;
     156                }
     157
     158                if (!mem_is_zero(buf, block_size)) {
     159                        empty = false;
     160                        goto done;
     161                }
     162        }
     163
     164        for (i = 0; i < n; i++) {
     165                rc = block_read_direct(sid, nblocks - n + i, 1, buf);
     166                if (rc != EOK) {
     167                        log_msg(LOG_DEFAULT, LVL_ERROR, "Error "
     168                            "reading blocks.");
     169                        rc = EIO;
     170                        goto error;
     171                }
     172
     173                if (!mem_is_zero(buf, block_size)) {
     174                        empty = false;
     175                        goto done;
     176                }
     177        }
     178
     179done:
    76180        block_fini(sid);
     181        free(buf);
     182        *rempty = empty;
     183        return EOK;
     184error:
     185        if (block_inited)
     186                block_fini(sid);
     187        if (buf != NULL)
     188                free(buf);
    77189        return rc;
    78190}
     
    81193{
    82194        int rc;
    83         label_bd_t lbd;
     195        bool block_inited = false;
     196        void *buf = NULL;
     197        aoff64_t nblocks;
     198        aoff64_t n;
     199        aoff64_t i;
     200        size_t block_size;
    84201
    85202        rc = block_init(sid, 2048);
     
    87204                log_msg(LOG_DEFAULT, LVL_ERROR, "Error opening "
    88205                    "block device service %zu", sid);
    89                 return EIO;
    90         }
    91 
    92         lbd.ops = &empty_bd_ops;
    93         lbd.arg = (void *)&sid;
    94 
    95         rc = label_bd_empty(&lbd);
     206                rc = EIO;
     207                goto error;
     208        }
     209
     210        block_inited = true;
     211
     212        rc = block_get_bsize(sid, &block_size);
     213        if (rc != EOK) {
     214                log_msg(LOG_DEFAULT, LVL_ERROR, "Error getting "
     215                    "block size.");
     216                rc = EIO;
     217                goto error;
     218        }
     219
     220        rc = block_get_nblocks(sid, &nblocks);
     221        if (rc != EOK) {
     222                log_msg(LOG_DEFAULT, LVL_ERROR, "Error getting "
     223                    "number of blocks.");
     224                rc = EIO;
     225                goto error;
     226        }
     227
     228        calc_num_check_blocks(nblocks, block_size, &n);
     229
     230        buf = calloc(block_size, 1);
     231        if (buf == NULL) {
     232                log_msg(LOG_DEFAULT, LVL_ERROR, "Error allocating buffer.");
     233                rc = ENOMEM;
     234                goto error;
     235        }
     236
     237        for (i = 0; i < n; i++) {
     238                rc = block_write_direct(sid, i, 1, buf);
     239                if (rc != EOK) {
     240                        log_msg(LOG_DEFAULT, LVL_ERROR, "Error "
     241                            "reading blocks.");
     242                        rc = EIO;
     243                        goto error;
     244                }
     245        }
     246
     247        for (i = 0; i < n; i++) {
     248                rc = block_write_direct(sid, nblocks - n + i, 1, buf);
     249                if (rc != EOK) {
     250                        log_msg(LOG_DEFAULT, LVL_ERROR, "Error "
     251                            "reading blocks.");
     252                        rc = EIO;
     253                        goto error;
     254                }
     255        }
    96256
    97257        block_fini(sid);
     258        free(buf);
     259        return EOK;
     260error:
     261        if (block_inited)
     262                block_fini(sid);
     263        if (buf != NULL)
     264                free(buf);
    98265        return rc;
    99266}
    100267
    101 /** Get block size wrapper for liblabel */
    102 static int empty_get_bsize(void *arg, size_t *bsize)
    103 {
    104         service_id_t svc_id = *(service_id_t *)arg;
    105         return block_get_bsize(svc_id, bsize);
    106 }
    107 
    108 /** Get number of blocks wrapper for liblabel */
    109 static int empty_get_nblocks(void *arg, aoff64_t *nblocks)
    110 {
    111         service_id_t svc_id = *(service_id_t *)arg;
    112         return block_get_nblocks(svc_id, nblocks);
    113 }
    114 
    115 /** Read blocks wrapper for liblabel */
    116 static int empty_read(void *arg, aoff64_t ba, size_t cnt, void *buf)
    117 {
    118         service_id_t svc_id = *(service_id_t *)arg;
    119         return block_read_direct(svc_id, ba, cnt, buf);
    120 }
    121 
    122 /** Write blocks wrapper for liblabel */
    123 static int empty_write(void *arg, aoff64_t ba, size_t cnt, const void *data)
    124 {
    125         service_id_t svc_id = *(service_id_t *)arg;
    126         return block_write_direct(svc_id, ba, cnt, data);
    127 }
    128 
    129268/** @}
    130269 */
Note: See TracChangeset for help on using the changeset viewer.