LCOV - code coverage report
Current view: top level - drivers/md - dm-log.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 18 286 6.3 %
Date: 2022-03-28 15:32:58 Functions: 3 31 9.7 %
Branches: 6 142 4.2 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (C) 2003 Sistina Software
       3                 :            :  * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
       4                 :            :  *
       5                 :            :  * This file is released under the LGPL.
       6                 :            :  */
       7                 :            : 
       8                 :            : #include <linux/init.h>
       9                 :            : #include <linux/slab.h>
      10                 :            : #include <linux/module.h>
      11                 :            : #include <linux/vmalloc.h>
      12                 :            : #include <linux/dm-io.h>
      13                 :            : #include <linux/dm-dirty-log.h>
      14                 :            : 
      15                 :            : #include <linux/device-mapper.h>
      16                 :            : 
      17                 :            : #define DM_MSG_PREFIX "dirty region log"
      18                 :            : 
      19                 :            : static LIST_HEAD(_log_types);
      20                 :            : static DEFINE_SPINLOCK(_lock);
      21                 :            : 
      22                 :         56 : static struct dm_dirty_log_type *__find_dirty_log_type(const char *name)
      23                 :            : {
      24                 :         56 :         struct dm_dirty_log_type *log_type;
      25                 :            : 
      26         [ +  + ]:         84 :         list_for_each_entry(log_type, &_log_types, list)
      27         [ -  + ]:         28 :                 if (!strcmp(name, log_type->name))
      28                 :          0 :                         return log_type;
      29                 :            : 
      30                 :            :         return NULL;
      31                 :            : }
      32                 :            : 
      33                 :          0 : static struct dm_dirty_log_type *_get_dirty_log_type(const char *name)
      34                 :            : {
      35                 :          0 :         struct dm_dirty_log_type *log_type;
      36                 :            : 
      37                 :          0 :         spin_lock(&_lock);
      38                 :            : 
      39                 :          0 :         log_type = __find_dirty_log_type(name);
      40   [ #  #  #  # ]:          0 :         if (log_type && !try_module_get(log_type->module))
      41                 :          0 :                 log_type = NULL;
      42                 :            : 
      43                 :          0 :         spin_unlock(&_lock);
      44                 :            : 
      45                 :          0 :         return log_type;
      46                 :            : }
      47                 :            : 
      48                 :            : /*
      49                 :            :  * get_type
      50                 :            :  * @type_name
      51                 :            :  *
      52                 :            :  * Attempt to retrieve the dm_dirty_log_type by name.  If not already
      53                 :            :  * available, attempt to load the appropriate module.
      54                 :            :  *
      55                 :            :  * Log modules are named "dm-log-" followed by the 'type_name'.
      56                 :            :  * Modules may contain multiple types.
      57                 :            :  * This function will first try the module "dm-log-<type_name>",
      58                 :            :  * then truncate 'type_name' on the last '-' and try again.
      59                 :            :  *
      60                 :            :  * For example, if type_name was "clustered-disk", it would search
      61                 :            :  * 'dm-log-clustered-disk' then 'dm-log-clustered'.
      62                 :            :  *
      63                 :            :  * Returns: dirty_log_type* on success, NULL on failure
      64                 :            :  */
      65                 :          0 : static struct dm_dirty_log_type *get_type(const char *type_name)
      66                 :            : {
      67                 :          0 :         char *p, *type_name_dup;
      68                 :          0 :         struct dm_dirty_log_type *log_type;
      69                 :            : 
      70         [ #  # ]:          0 :         if (!type_name)
      71                 :            :                 return NULL;
      72                 :            : 
      73                 :          0 :         log_type = _get_dirty_log_type(type_name);
      74         [ #  # ]:          0 :         if (log_type)
      75                 :            :                 return log_type;
      76                 :            : 
      77                 :          0 :         type_name_dup = kstrdup(type_name, GFP_KERNEL);
      78         [ #  # ]:          0 :         if (!type_name_dup) {
      79                 :          0 :                 DMWARN("No memory left to attempt log module load for \"%s\"",
      80                 :            :                        type_name);
      81                 :          0 :                 return NULL;
      82                 :            :         }
      83                 :            : 
      84   [ #  #  #  # ]:          0 :         while (request_module("dm-log-%s", type_name_dup) ||
      85                 :          0 :                !(log_type = _get_dirty_log_type(type_name))) {
      86                 :          0 :                 p = strrchr(type_name_dup, '-');
      87         [ #  # ]:          0 :                 if (!p)
      88                 :            :                         break;
      89                 :          0 :                 p[0] = '\0';
      90                 :            :         }
      91                 :            : 
      92         [ #  # ]:          0 :         if (!log_type)
      93                 :          0 :                 DMWARN("Module for logging type \"%s\" not found.", type_name);
      94                 :            : 
      95                 :          0 :         kfree(type_name_dup);
      96                 :            : 
      97                 :          0 :         return log_type;
      98                 :            : }
      99                 :            : 
     100                 :          0 : static void put_type(struct dm_dirty_log_type *type)
     101                 :            : {
     102         [ #  # ]:          0 :         if (!type)
     103                 :            :                 return;
     104                 :            : 
     105                 :          0 :         spin_lock(&_lock);
     106         [ #  # ]:          0 :         if (!__find_dirty_log_type(type->name))
     107                 :          0 :                 goto out;
     108                 :            : 
     109                 :          0 :         module_put(type->module);
     110                 :            : 
     111                 :          0 : out:
     112                 :          0 :         spin_unlock(&_lock);
     113                 :            : }
     114                 :            : 
     115                 :         56 : int dm_dirty_log_type_register(struct dm_dirty_log_type *type)
     116                 :            : {
     117                 :         56 :         int r = 0;
     118                 :            : 
     119                 :         56 :         spin_lock(&_lock);
     120         [ +  - ]:         56 :         if (!__find_dirty_log_type(type->name))
     121                 :         56 :                 list_add(&type->list, &_log_types);
     122                 :            :         else
     123                 :            :                 r = -EEXIST;
     124                 :         56 :         spin_unlock(&_lock);
     125                 :            : 
     126                 :         56 :         return r;
     127                 :            : }
     128                 :            : EXPORT_SYMBOL(dm_dirty_log_type_register);
     129                 :            : 
     130                 :          0 : int dm_dirty_log_type_unregister(struct dm_dirty_log_type *type)
     131                 :            : {
     132                 :          0 :         spin_lock(&_lock);
     133                 :            : 
     134         [ #  # ]:          0 :         if (!__find_dirty_log_type(type->name)) {
     135                 :          0 :                 spin_unlock(&_lock);
     136                 :          0 :                 return -EINVAL;
     137                 :            :         }
     138                 :            : 
     139                 :          0 :         list_del(&type->list);
     140                 :            : 
     141                 :          0 :         spin_unlock(&_lock);
     142                 :            : 
     143                 :          0 :         return 0;
     144                 :            : }
     145                 :            : EXPORT_SYMBOL(dm_dirty_log_type_unregister);
     146                 :            : 
     147                 :          0 : struct dm_dirty_log *dm_dirty_log_create(const char *type_name,
     148                 :            :                         struct dm_target *ti,
     149                 :            :                         int (*flush_callback_fn)(struct dm_target *ti),
     150                 :            :                         unsigned int argc, char **argv)
     151                 :            : {
     152                 :          0 :         struct dm_dirty_log_type *type;
     153                 :          0 :         struct dm_dirty_log *log;
     154                 :            : 
     155                 :          0 :         log = kmalloc(sizeof(*log), GFP_KERNEL);
     156         [ #  # ]:          0 :         if (!log)
     157                 :            :                 return NULL;
     158                 :            : 
     159                 :          0 :         type = get_type(type_name);
     160         [ #  # ]:          0 :         if (!type) {
     161                 :          0 :                 kfree(log);
     162                 :          0 :                 return NULL;
     163                 :            :         }
     164                 :            : 
     165                 :          0 :         log->flush_callback_fn = flush_callback_fn;
     166                 :          0 :         log->type = type;
     167         [ #  # ]:          0 :         if (type->ctr(log, ti, argc, argv)) {
     168                 :          0 :                 kfree(log);
     169                 :          0 :                 put_type(type);
     170                 :          0 :                 return NULL;
     171                 :            :         }
     172                 :            : 
     173                 :            :         return log;
     174                 :            : }
     175                 :            : EXPORT_SYMBOL(dm_dirty_log_create);
     176                 :            : 
     177                 :          0 : void dm_dirty_log_destroy(struct dm_dirty_log *log)
     178                 :            : {
     179                 :          0 :         log->type->dtr(log);
     180                 :          0 :         put_type(log->type);
     181                 :          0 :         kfree(log);
     182                 :          0 : }
     183                 :            : EXPORT_SYMBOL(dm_dirty_log_destroy);
     184                 :            : 
     185                 :            : /*-----------------------------------------------------------------
     186                 :            :  * Persistent and core logs share a lot of their implementation.
     187                 :            :  * FIXME: need a reload method to be called from a resume
     188                 :            :  *---------------------------------------------------------------*/
     189                 :            : /*
     190                 :            :  * Magic for persistent mirrors: "MiRr"
     191                 :            :  */
     192                 :            : #define MIRROR_MAGIC 0x4D695272
     193                 :            : 
     194                 :            : /*
     195                 :            :  * The on-disk version of the metadata.
     196                 :            :  */
     197                 :            : #define MIRROR_DISK_VERSION 2
     198                 :            : #define LOG_OFFSET 2
     199                 :            : 
     200                 :            : struct log_header_disk {
     201                 :            :         __le32 magic;
     202                 :            : 
     203                 :            :         /*
     204                 :            :          * Simple, incrementing version. no backward
     205                 :            :          * compatibility.
     206                 :            :          */
     207                 :            :         __le32 version;
     208                 :            :         __le64 nr_regions;
     209                 :            : } __packed;
     210                 :            : 
     211                 :            : struct log_header_core {
     212                 :            :         uint32_t magic;
     213                 :            :         uint32_t version;
     214                 :            :         uint64_t nr_regions;
     215                 :            : };
     216                 :            : 
     217                 :            : struct log_c {
     218                 :            :         struct dm_target *ti;
     219                 :            :         int touched_dirtied;
     220                 :            :         int touched_cleaned;
     221                 :            :         int flush_failed;
     222                 :            :         uint32_t region_size;
     223                 :            :         unsigned int region_count;
     224                 :            :         region_t sync_count;
     225                 :            : 
     226                 :            :         unsigned bitset_uint32_count;
     227                 :            :         uint32_t *clean_bits;
     228                 :            :         uint32_t *sync_bits;
     229                 :            :         uint32_t *recovering_bits;      /* FIXME: this seems excessive */
     230                 :            : 
     231                 :            :         int sync_search;
     232                 :            : 
     233                 :            :         /* Resync flag */
     234                 :            :         enum sync {
     235                 :            :                 DEFAULTSYNC,    /* Synchronize if necessary */
     236                 :            :                 NOSYNC,         /* Devices known to be already in sync */
     237                 :            :                 FORCESYNC,      /* Force a sync to happen */
     238                 :            :         } sync;
     239                 :            : 
     240                 :            :         struct dm_io_request io_req;
     241                 :            : 
     242                 :            :         /*
     243                 :            :          * Disk log fields
     244                 :            :          */
     245                 :            :         int log_dev_failed;
     246                 :            :         int log_dev_flush_failed;
     247                 :            :         struct dm_dev *log_dev;
     248                 :            :         struct log_header_core header;
     249                 :            : 
     250                 :            :         struct dm_io_region header_location;
     251                 :            :         struct log_header_disk *disk_header;
     252                 :            : };
     253                 :            : 
     254                 :            : /*
     255                 :            :  * The touched member needs to be updated every time we access
     256                 :            :  * one of the bitsets.
     257                 :            :  */
     258                 :          0 : static inline int log_test_bit(uint32_t *bs, unsigned bit)
     259                 :            : {
     260                 :          0 :         return test_bit_le(bit, bs) ? 1 : 0;
     261                 :            : }
     262                 :            : 
     263                 :          0 : static inline void log_set_bit(struct log_c *l,
     264                 :            :                                uint32_t *bs, unsigned bit)
     265                 :            : {
     266                 :          0 :         __set_bit_le(bit, bs);
     267                 :          0 :         l->touched_cleaned = 1;
     268                 :          0 : }
     269                 :            : 
     270                 :          0 : static inline void log_clear_bit(struct log_c *l,
     271                 :            :                                  uint32_t *bs, unsigned bit)
     272                 :            : {
     273                 :          0 :         __clear_bit_le(bit, bs);
     274                 :          0 :         l->touched_dirtied = 1;
     275                 :          0 : }
     276                 :            : 
     277                 :            : /*----------------------------------------------------------------
     278                 :            :  * Header IO
     279                 :            :  *--------------------------------------------------------------*/
     280                 :          0 : static void header_to_disk(struct log_header_core *core, struct log_header_disk *disk)
     281                 :            : {
     282                 :          0 :         disk->magic = cpu_to_le32(core->magic);
     283                 :          0 :         disk->version = cpu_to_le32(core->version);
     284                 :          0 :         disk->nr_regions = cpu_to_le64(core->nr_regions);
     285                 :            : }
     286                 :            : 
     287                 :          0 : static void header_from_disk(struct log_header_core *core, struct log_header_disk *disk)
     288                 :            : {
     289                 :          0 :         core->magic = le32_to_cpu(disk->magic);
     290                 :          0 :         core->version = le32_to_cpu(disk->version);
     291                 :          0 :         core->nr_regions = le64_to_cpu(disk->nr_regions);
     292                 :            : }
     293                 :            : 
     294                 :          0 : static int rw_header(struct log_c *lc, int op)
     295                 :            : {
     296                 :          0 :         lc->io_req.bi_op = op;
     297                 :          0 :         lc->io_req.bi_op_flags = 0;
     298                 :            : 
     299                 :          0 :         return dm_io(&lc->io_req, 1, &lc->header_location, NULL);
     300                 :            : }
     301                 :            : 
     302                 :          0 : static int flush_header(struct log_c *lc)
     303                 :            : {
     304                 :          0 :         struct dm_io_region null_location = {
     305                 :          0 :                 .bdev = lc->header_location.bdev,
     306                 :            :                 .sector = 0,
     307                 :            :                 .count = 0,
     308                 :            :         };
     309                 :            : 
     310                 :          0 :         lc->io_req.bi_op = REQ_OP_WRITE;
     311                 :          0 :         lc->io_req.bi_op_flags = REQ_PREFLUSH;
     312                 :            : 
     313                 :          0 :         return dm_io(&lc->io_req, 1, &null_location, NULL);
     314                 :            : }
     315                 :            : 
     316                 :          0 : static int read_header(struct log_c *log)
     317                 :            : {
     318                 :          0 :         int r;
     319                 :            : 
     320                 :          0 :         r = rw_header(log, REQ_OP_READ);
     321         [ #  # ]:          0 :         if (r)
     322                 :            :                 return r;
     323                 :            : 
     324                 :          0 :         header_from_disk(&log->header, log->disk_header);
     325                 :            : 
     326                 :            :         /* New log required? */
     327   [ #  #  #  # ]:          0 :         if (log->sync != DEFAULTSYNC || log->header.magic != MIRROR_MAGIC) {
     328                 :          0 :                 log->header.magic = MIRROR_MAGIC;
     329                 :          0 :                 log->header.version = MIRROR_DISK_VERSION;
     330                 :          0 :                 log->header.nr_regions = 0;
     331                 :            :         }
     332                 :            : 
     333                 :            : #ifdef __LITTLE_ENDIAN
     334         [ #  # ]:          0 :         if (log->header.version == 1)
     335                 :          0 :                 log->header.version = 2;
     336                 :            : #endif
     337                 :            : 
     338         [ #  # ]:          0 :         if (log->header.version != MIRROR_DISK_VERSION) {
     339                 :          0 :                 DMWARN("incompatible disk log version");
     340                 :          0 :                 return -EINVAL;
     341                 :            :         }
     342                 :            : 
     343                 :            :         return 0;
     344                 :            : }
     345                 :            : 
     346                 :            : static int _check_region_size(struct dm_target *ti, uint32_t region_size)
     347                 :            : {
     348                 :            :         if (region_size < 2 || region_size > ti->len)
     349                 :            :                 return 0;
     350                 :            : 
     351                 :            :         if (!is_power_of_2(region_size))
     352                 :            :                 return 0;
     353                 :            : 
     354                 :            :         return 1;
     355                 :            : }
     356                 :            : 
     357                 :            : /*----------------------------------------------------------------
     358                 :            :  * core log constructor/destructor
     359                 :            :  *
     360                 :            :  * argv contains region_size followed optionally by [no]sync
     361                 :            :  *--------------------------------------------------------------*/
     362                 :            : #define BYTE_SHIFT 3
     363                 :            : static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
     364                 :            :                               unsigned int argc, char **argv,
     365                 :            :                               struct dm_dev *dev)
     366                 :            : {
     367                 :            :         enum sync sync = DEFAULTSYNC;
     368                 :            : 
     369                 :            :         struct log_c *lc;
     370                 :            :         uint32_t region_size;
     371                 :            :         unsigned int region_count;
     372                 :            :         size_t bitset_size, buf_size;
     373                 :            :         int r;
     374                 :            :         char dummy;
     375                 :            : 
     376                 :            :         if (argc < 1 || argc > 2) {
     377                 :            :                 DMWARN("wrong number of arguments to dirty region log");
     378                 :            :                 return -EINVAL;
     379                 :            :         }
     380                 :            : 
     381                 :            :         if (argc > 1) {
     382                 :            :                 if (!strcmp(argv[1], "sync"))
     383                 :            :                         sync = FORCESYNC;
     384                 :            :                 else if (!strcmp(argv[1], "nosync"))
     385                 :            :                         sync = NOSYNC;
     386                 :            :                 else {
     387                 :            :                         DMWARN("unrecognised sync argument to "
     388                 :            :                                "dirty region log: %s", argv[1]);
     389                 :            :                         return -EINVAL;
     390                 :            :                 }
     391                 :            :         }
     392                 :            : 
     393                 :            :         if (sscanf(argv[0], "%u%c", &region_size, &dummy) != 1 ||
     394                 :            :             !_check_region_size(ti, region_size)) {
     395                 :            :                 DMWARN("invalid region size %s", argv[0]);
     396                 :            :                 return -EINVAL;
     397                 :            :         }
     398                 :            : 
     399                 :            :         region_count = dm_sector_div_up(ti->len, region_size);
     400                 :            : 
     401                 :            :         lc = kmalloc(sizeof(*lc), GFP_KERNEL);
     402                 :            :         if (!lc) {
     403                 :            :                 DMWARN("couldn't allocate core log");
     404                 :            :                 return -ENOMEM;
     405                 :            :         }
     406                 :            : 
     407                 :            :         lc->ti = ti;
     408                 :            :         lc->touched_dirtied = 0;
     409                 :            :         lc->touched_cleaned = 0;
     410                 :            :         lc->flush_failed = 0;
     411                 :            :         lc->region_size = region_size;
     412                 :            :         lc->region_count = region_count;
     413                 :            :         lc->sync = sync;
     414                 :            : 
     415                 :            :         /*
     416                 :            :          * Work out how many "unsigned long"s we need to hold the bitset.
     417                 :            :          */
     418                 :            :         bitset_size = dm_round_up(region_count,
     419                 :            :                                   sizeof(*lc->clean_bits) << BYTE_SHIFT);
     420                 :            :         bitset_size >>= BYTE_SHIFT;
     421                 :            : 
     422                 :            :         lc->bitset_uint32_count = bitset_size / sizeof(*lc->clean_bits);
     423                 :            : 
     424                 :            :         /*
     425                 :            :          * Disk log?
     426                 :            :          */
     427                 :            :         if (!dev) {
     428                 :            :                 lc->clean_bits = vmalloc(bitset_size);
     429                 :            :                 if (!lc->clean_bits) {
     430                 :            :                         DMWARN("couldn't allocate clean bitset");
     431                 :            :                         kfree(lc);
     432                 :            :                         return -ENOMEM;
     433                 :            :                 }
     434                 :            :                 lc->disk_header = NULL;
     435                 :            :         } else {
     436                 :            :                 lc->log_dev = dev;
     437                 :            :                 lc->log_dev_failed = 0;
     438                 :            :                 lc->log_dev_flush_failed = 0;
     439                 :            :                 lc->header_location.bdev = lc->log_dev->bdev;
     440                 :            :                 lc->header_location.sector = 0;
     441                 :            : 
     442                 :            :                 /*
     443                 :            :                  * Buffer holds both header and bitset.
     444                 :            :                  */
     445                 :            :                 buf_size =
     446                 :            :                     dm_round_up((LOG_OFFSET << SECTOR_SHIFT) + bitset_size,
     447                 :            :                                 bdev_logical_block_size(lc->header_location.
     448                 :            :                                                             bdev));
     449                 :            : 
     450                 :            :                 if (buf_size > i_size_read(dev->bdev->bd_inode)) {
     451                 :            :                         DMWARN("log device %s too small: need %llu bytes",
     452                 :            :                                 dev->name, (unsigned long long)buf_size);
     453                 :            :                         kfree(lc);
     454                 :            :                         return -EINVAL;
     455                 :            :                 }
     456                 :            : 
     457                 :            :                 lc->header_location.count = buf_size >> SECTOR_SHIFT;
     458                 :            : 
     459                 :            :                 lc->io_req.mem.type = DM_IO_VMA;
     460                 :            :                 lc->io_req.notify.fn = NULL;
     461                 :            :                 lc->io_req.client = dm_io_client_create();
     462                 :            :                 if (IS_ERR(lc->io_req.client)) {
     463                 :            :                         r = PTR_ERR(lc->io_req.client);
     464                 :            :                         DMWARN("couldn't allocate disk io client");
     465                 :            :                         kfree(lc);
     466                 :            :                         return r;
     467                 :            :                 }
     468                 :            : 
     469                 :            :                 lc->disk_header = vmalloc(buf_size);
     470                 :            :                 if (!lc->disk_header) {
     471                 :            :                         DMWARN("couldn't allocate disk log buffer");
     472                 :            :                         dm_io_client_destroy(lc->io_req.client);
     473                 :            :                         kfree(lc);
     474                 :            :                         return -ENOMEM;
     475                 :            :                 }
     476                 :            : 
     477                 :            :                 lc->io_req.mem.ptr.vma = lc->disk_header;
     478                 :            :                 lc->clean_bits = (void *)lc->disk_header +
     479                 :            :                                  (LOG_OFFSET << SECTOR_SHIFT);
     480                 :            :         }
     481                 :            : 
     482                 :            :         memset(lc->clean_bits, -1, bitset_size);
     483                 :            : 
     484                 :            :         lc->sync_bits = vmalloc(bitset_size);
     485                 :            :         if (!lc->sync_bits) {
     486                 :            :                 DMWARN("couldn't allocate sync bitset");
     487                 :            :                 if (!dev)
     488                 :            :                         vfree(lc->clean_bits);
     489                 :            :                 else
     490                 :            :                         dm_io_client_destroy(lc->io_req.client);
     491                 :            :                 vfree(lc->disk_header);
     492                 :            :                 kfree(lc);
     493                 :            :                 return -ENOMEM;
     494                 :            :         }
     495                 :            :         memset(lc->sync_bits, (sync == NOSYNC) ? -1 : 0, bitset_size);
     496                 :            :         lc->sync_count = (sync == NOSYNC) ? region_count : 0;
     497                 :            : 
     498                 :            :         lc->recovering_bits = vzalloc(bitset_size);
     499                 :            :         if (!lc->recovering_bits) {
     500                 :            :                 DMWARN("couldn't allocate sync bitset");
     501                 :            :                 vfree(lc->sync_bits);
     502                 :            :                 if (!dev)
     503                 :            :                         vfree(lc->clean_bits);
     504                 :            :                 else
     505                 :            :                         dm_io_client_destroy(lc->io_req.client);
     506                 :            :                 vfree(lc->disk_header);
     507                 :            :                 kfree(lc);
     508                 :            :                 return -ENOMEM;
     509                 :            :         }
     510                 :            :         lc->sync_search = 0;
     511                 :            :         log->context = lc;
     512                 :            : 
     513                 :            :         return 0;
     514                 :            : }
     515                 :            : 
     516                 :          0 : static int core_ctr(struct dm_dirty_log *log, struct dm_target *ti,
     517                 :            :                     unsigned int argc, char **argv)
     518                 :            : {
     519                 :          0 :         return create_log_context(log, ti, argc, argv, NULL);
     520                 :            : }
     521                 :            : 
     522                 :          0 : static void destroy_log_context(struct log_c *lc)
     523                 :            : {
     524                 :          0 :         vfree(lc->sync_bits);
     525                 :          0 :         vfree(lc->recovering_bits);
     526                 :          0 :         kfree(lc);
     527                 :          0 : }
     528                 :            : 
     529                 :          0 : static void core_dtr(struct dm_dirty_log *log)
     530                 :            : {
     531                 :          0 :         struct log_c *lc = (struct log_c *) log->context;
     532                 :            : 
     533                 :          0 :         vfree(lc->clean_bits);
     534                 :          0 :         destroy_log_context(lc);
     535                 :          0 : }
     536                 :            : 
     537                 :            : /*----------------------------------------------------------------
     538                 :            :  * disk log constructor/destructor
     539                 :            :  *
     540                 :            :  * argv contains log_device region_size followed optionally by [no]sync
     541                 :            :  *--------------------------------------------------------------*/
     542                 :          0 : static int disk_ctr(struct dm_dirty_log *log, struct dm_target *ti,
     543                 :            :                     unsigned int argc, char **argv)
     544                 :            : {
     545                 :          0 :         int r;
     546                 :          0 :         struct dm_dev *dev;
     547                 :            : 
     548         [ #  # ]:          0 :         if (argc < 2 || argc > 3) {
     549                 :          0 :                 DMWARN("wrong number of arguments to disk dirty region log");
     550                 :          0 :                 return -EINVAL;
     551                 :            :         }
     552                 :            : 
     553                 :          0 :         r = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &dev);
     554         [ #  # ]:          0 :         if (r)
     555                 :            :                 return r;
     556                 :            : 
     557                 :          0 :         r = create_log_context(log, ti, argc - 1, argv + 1, dev);
     558         [ #  # ]:          0 :         if (r) {
     559                 :          0 :                 dm_put_device(ti, dev);
     560                 :          0 :                 return r;
     561                 :            :         }
     562                 :            : 
     563                 :            :         return 0;
     564                 :            : }
     565                 :            : 
     566                 :          0 : static void disk_dtr(struct dm_dirty_log *log)
     567                 :            : {
     568                 :          0 :         struct log_c *lc = (struct log_c *) log->context;
     569                 :            : 
     570                 :          0 :         dm_put_device(lc->ti, lc->log_dev);
     571                 :          0 :         vfree(lc->disk_header);
     572                 :          0 :         dm_io_client_destroy(lc->io_req.client);
     573                 :          0 :         destroy_log_context(lc);
     574                 :          0 : }
     575                 :            : 
     576                 :          0 : static void fail_log_device(struct log_c *lc)
     577                 :            : {
     578                 :          0 :         if (lc->log_dev_failed)
     579                 :            :                 return;
     580                 :            : 
     581                 :          0 :         lc->log_dev_failed = 1;
     582                 :          0 :         dm_table_event(lc->ti->table);
     583                 :            : }
     584                 :            : 
     585                 :          0 : static int disk_resume(struct dm_dirty_log *log)
     586                 :            : {
     587                 :          0 :         int r;
     588                 :          0 :         unsigned i;
     589                 :          0 :         struct log_c *lc = (struct log_c *) log->context;
     590                 :          0 :         size_t size = lc->bitset_uint32_count * sizeof(uint32_t);
     591                 :            : 
     592                 :            :         /* read the disk header */
     593                 :          0 :         r = read_header(lc);
     594         [ #  # ]:          0 :         if (r) {
     595                 :          0 :                 DMWARN("%s: Failed to read header on dirty region log device",
     596                 :            :                        lc->log_dev->name);
     597         [ #  # ]:          0 :                 fail_log_device(lc);
     598                 :            :                 /*
     599                 :            :                  * If the log device cannot be read, we must assume
     600                 :            :                  * all regions are out-of-sync.  If we simply return
     601                 :            :                  * here, the state will be uninitialized and could
     602                 :            :                  * lead us to return 'in-sync' status for regions
     603                 :            :                  * that are actually 'out-of-sync'.
     604                 :            :                  */
     605                 :          0 :                 lc->header.nr_regions = 0;
     606                 :            :         }
     607                 :            : 
     608                 :            :         /* set or clear any new bits -- device has grown */
     609         [ #  # ]:          0 :         if (lc->sync == NOSYNC)
     610         [ #  # ]:          0 :                 for (i = lc->header.nr_regions; i < lc->region_count; i++)
     611                 :            :                         /* FIXME: amazingly inefficient */
     612                 :          0 :                         log_set_bit(lc, lc->clean_bits, i);
     613                 :            :         else
     614         [ #  # ]:          0 :                 for (i = lc->header.nr_regions; i < lc->region_count; i++)
     615                 :            :                         /* FIXME: amazingly inefficient */
     616                 :          0 :                         log_clear_bit(lc, lc->clean_bits, i);
     617                 :            : 
     618                 :            :         /* clear any old bits -- device has shrunk */
     619         [ #  # ]:          0 :         for (i = lc->region_count; i % (sizeof(*lc->clean_bits) << BYTE_SHIFT); i++)
     620                 :          0 :                 log_clear_bit(lc, lc->clean_bits, i);
     621                 :            : 
     622                 :            :         /* copy clean across to sync */
     623                 :          0 :         memcpy(lc->sync_bits, lc->clean_bits, size);
     624                 :          0 :         lc->sync_count = memweight(lc->clean_bits,
     625                 :          0 :                                 lc->bitset_uint32_count * sizeof(uint32_t));
     626                 :          0 :         lc->sync_search = 0;
     627                 :            : 
     628                 :            :         /* set the correct number of regions in the header */
     629                 :          0 :         lc->header.nr_regions = lc->region_count;
     630                 :            : 
     631                 :          0 :         header_to_disk(&lc->header, lc->disk_header);
     632                 :            : 
     633                 :            :         /* write the new header */
     634                 :          0 :         r = rw_header(lc, REQ_OP_WRITE);
     635         [ #  # ]:          0 :         if (!r) {
     636                 :          0 :                 r = flush_header(lc);
     637         [ #  # ]:          0 :                 if (r)
     638                 :          0 :                         lc->log_dev_flush_failed = 1;
     639                 :            :         }
     640         [ #  # ]:          0 :         if (r) {
     641                 :          0 :                 DMWARN("%s: Failed to write header on dirty region log device",
     642                 :            :                        lc->log_dev->name);
     643         [ #  # ]:          0 :                 fail_log_device(lc);
     644                 :            :         }
     645                 :            : 
     646                 :          0 :         return r;
     647                 :            : }
     648                 :            : 
     649                 :          0 : static uint32_t core_get_region_size(struct dm_dirty_log *log)
     650                 :            : {
     651                 :          0 :         struct log_c *lc = (struct log_c *) log->context;
     652                 :          0 :         return lc->region_size;
     653                 :            : }
     654                 :            : 
     655                 :          0 : static int core_resume(struct dm_dirty_log *log)
     656                 :            : {
     657                 :          0 :         struct log_c *lc = (struct log_c *) log->context;
     658                 :          0 :         lc->sync_search = 0;
     659                 :          0 :         return 0;
     660                 :            : }
     661                 :            : 
     662                 :          0 : static int core_is_clean(struct dm_dirty_log *log, region_t region)
     663                 :            : {
     664                 :          0 :         struct log_c *lc = (struct log_c *) log->context;
     665                 :          0 :         return log_test_bit(lc->clean_bits, region);
     666                 :            : }
     667                 :            : 
     668                 :          0 : static int core_in_sync(struct dm_dirty_log *log, region_t region, int block)
     669                 :            : {
     670                 :          0 :         struct log_c *lc = (struct log_c *) log->context;
     671                 :          0 :         return log_test_bit(lc->sync_bits, region);
     672                 :            : }
     673                 :            : 
     674                 :          0 : static int core_flush(struct dm_dirty_log *log)
     675                 :            : {
     676                 :            :         /* no op */
     677                 :          0 :         return 0;
     678                 :            : }
     679                 :            : 
     680                 :          0 : static int disk_flush(struct dm_dirty_log *log)
     681                 :            : {
     682                 :          0 :         int r, i;
     683                 :          0 :         struct log_c *lc = log->context;
     684                 :            : 
     685                 :            :         /* only write if the log has changed */
     686         [ #  # ]:          0 :         if (!lc->touched_cleaned && !lc->touched_dirtied)
     687                 :            :                 return 0;
     688                 :            : 
     689   [ #  #  #  #  :          0 :         if (lc->touched_cleaned && log->flush_callback_fn &&
                   #  # ]
     690                 :          0 :             log->flush_callback_fn(lc->ti)) {
     691                 :            :                 /*
     692                 :            :                  * At this point it is impossible to determine which
     693                 :            :                  * regions are clean and which are dirty (without
     694                 :            :                  * re-reading the log off disk). So mark all of them
     695                 :            :                  * dirty.
     696                 :            :                  */
     697                 :          0 :                 lc->flush_failed = 1;
     698         [ #  # ]:          0 :                 for (i = 0; i < lc->region_count; i++)
     699                 :          0 :                         log_clear_bit(lc, lc->clean_bits, i);
     700                 :            :         }
     701                 :            : 
     702                 :          0 :         r = rw_header(lc, REQ_OP_WRITE);
     703         [ #  # ]:          0 :         if (r)
     704         [ #  # ]:          0 :                 fail_log_device(lc);
     705                 :            :         else {
     706         [ #  # ]:          0 :                 if (lc->touched_dirtied) {
     707                 :          0 :                         r = flush_header(lc);
     708         [ #  # ]:          0 :                         if (r) {
     709                 :          0 :                                 lc->log_dev_flush_failed = 1;
     710         [ #  # ]:          0 :                                 fail_log_device(lc);
     711                 :            :                         } else
     712                 :          0 :                                 lc->touched_dirtied = 0;
     713                 :            :                 }
     714                 :          0 :                 lc->touched_cleaned = 0;
     715                 :            :         }
     716                 :            : 
     717                 :            :         return r;
     718                 :            : }
     719                 :            : 
     720                 :          0 : static void core_mark_region(struct dm_dirty_log *log, region_t region)
     721                 :            : {
     722                 :          0 :         struct log_c *lc = (struct log_c *) log->context;
     723                 :          0 :         log_clear_bit(lc, lc->clean_bits, region);
     724                 :          0 : }
     725                 :            : 
     726                 :          0 : static void core_clear_region(struct dm_dirty_log *log, region_t region)
     727                 :            : {
     728                 :          0 :         struct log_c *lc = (struct log_c *) log->context;
     729         [ #  # ]:          0 :         if (likely(!lc->flush_failed))
     730                 :          0 :                 log_set_bit(lc, lc->clean_bits, region);
     731                 :          0 : }
     732                 :            : 
     733                 :          0 : static int core_get_resync_work(struct dm_dirty_log *log, region_t *region)
     734                 :            : {
     735                 :          0 :         struct log_c *lc = (struct log_c *) log->context;
     736                 :            : 
     737         [ #  # ]:          0 :         if (lc->sync_search >= lc->region_count)
     738                 :            :                 return 0;
     739                 :            : 
     740                 :          0 :         do {
     741                 :          0 :                 *region = find_next_zero_bit_le(lc->sync_bits,
     742                 :          0 :                                              lc->region_count,
     743                 :          0 :                                              lc->sync_search);
     744                 :          0 :                 lc->sync_search = *region + 1;
     745                 :            : 
     746         [ #  # ]:          0 :                 if (*region >= lc->region_count)
     747                 :            :                         return 0;
     748                 :            : 
     749         [ #  # ]:          0 :         } while (log_test_bit(lc->recovering_bits, *region));
     750                 :            : 
     751                 :          0 :         log_set_bit(lc, lc->recovering_bits, *region);
     752                 :          0 :         return 1;
     753                 :            : }
     754                 :            : 
     755                 :          0 : static void core_set_region_sync(struct dm_dirty_log *log, region_t region,
     756                 :            :                                  int in_sync)
     757                 :            : {
     758                 :          0 :         struct log_c *lc = (struct log_c *) log->context;
     759                 :            : 
     760                 :          0 :         log_clear_bit(lc, lc->recovering_bits, region);
     761         [ #  # ]:          0 :         if (in_sync) {
     762                 :          0 :                 log_set_bit(lc, lc->sync_bits, region);
     763                 :          0 :                 lc->sync_count++;
     764         [ #  # ]:          0 :         } else if (log_test_bit(lc->sync_bits, region)) {
     765                 :          0 :                 lc->sync_count--;
     766                 :          0 :                 log_clear_bit(lc, lc->sync_bits, region);
     767                 :            :         }
     768                 :          0 : }
     769                 :            : 
     770                 :          0 : static region_t core_get_sync_count(struct dm_dirty_log *log)
     771                 :            : {
     772                 :          0 :         struct log_c *lc = (struct log_c *) log->context;
     773                 :            : 
     774                 :          0 :         return lc->sync_count;
     775                 :            : }
     776                 :            : 
     777                 :            : #define DMEMIT_SYNC \
     778                 :            :         if (lc->sync != DEFAULTSYNC) \
     779                 :            :                 DMEMIT("%ssync ", lc->sync == NOSYNC ? "no" : "")
     780                 :            : 
     781                 :          0 : static int core_status(struct dm_dirty_log *log, status_type_t status,
     782                 :            :                        char *result, unsigned int maxlen)
     783                 :            : {
     784                 :          0 :         int sz = 0;
     785                 :          0 :         struct log_c *lc = log->context;
     786                 :            : 
     787      [ #  #  # ]:          0 :         switch(status) {
     788                 :          0 :         case STATUSTYPE_INFO:
     789         [ #  # ]:          0 :                 DMEMIT("1 %s", log->type->name);
     790                 :            :                 break;
     791                 :            : 
     792                 :          0 :         case STATUSTYPE_TABLE:
     793   [ #  #  #  # ]:          0 :                 DMEMIT("%s %u %u ", log->type->name,
     794                 :            :                        lc->sync == DEFAULTSYNC ? 1 : 2, lc->region_size);
     795   [ #  #  #  #  :          0 :                 DMEMIT_SYNC;
                   #  # ]
     796                 :            :         }
     797                 :            : 
     798                 :          0 :         return sz;
     799                 :            : }
     800                 :            : 
     801                 :          0 : static int disk_status(struct dm_dirty_log *log, status_type_t status,
     802                 :            :                        char *result, unsigned int maxlen)
     803                 :            : {
     804                 :          0 :         int sz = 0;
     805                 :          0 :         struct log_c *lc = log->context;
     806                 :            : 
     807      [ #  #  # ]:          0 :         switch(status) {
     808                 :          0 :         case STATUSTYPE_INFO:
     809   [ #  #  #  #  :          0 :                 DMEMIT("3 %s %s %c", log->type->name, lc->log_dev->name,
                   #  # ]
     810                 :            :                        lc->log_dev_flush_failed ? 'F' :
     811                 :            :                        lc->log_dev_failed ? 'D' :
     812                 :            :                        'A');
     813                 :            :                 break;
     814                 :            : 
     815                 :          0 :         case STATUSTYPE_TABLE:
     816   [ #  #  #  # ]:          0 :                 DMEMIT("%s %u %s %u ", log->type->name,
     817                 :            :                        lc->sync == DEFAULTSYNC ? 2 : 3, lc->log_dev->name,
     818                 :            :                        lc->region_size);
     819   [ #  #  #  #  :          0 :                 DMEMIT_SYNC;
                   #  # ]
     820                 :            :         }
     821                 :            : 
     822                 :          0 :         return sz;
     823                 :            : }
     824                 :            : 
     825                 :            : static struct dm_dirty_log_type _core_type = {
     826                 :            :         .name = "core",
     827                 :            :         .module = THIS_MODULE,
     828                 :            :         .ctr = core_ctr,
     829                 :            :         .dtr = core_dtr,
     830                 :            :         .resume = core_resume,
     831                 :            :         .get_region_size = core_get_region_size,
     832                 :            :         .is_clean = core_is_clean,
     833                 :            :         .in_sync = core_in_sync,
     834                 :            :         .flush = core_flush,
     835                 :            :         .mark_region = core_mark_region,
     836                 :            :         .clear_region = core_clear_region,
     837                 :            :         .get_resync_work = core_get_resync_work,
     838                 :            :         .set_region_sync = core_set_region_sync,
     839                 :            :         .get_sync_count = core_get_sync_count,
     840                 :            :         .status = core_status,
     841                 :            : };
     842                 :            : 
     843                 :            : static struct dm_dirty_log_type _disk_type = {
     844                 :            :         .name = "disk",
     845                 :            :         .module = THIS_MODULE,
     846                 :            :         .ctr = disk_ctr,
     847                 :            :         .dtr = disk_dtr,
     848                 :            :         .postsuspend = disk_flush,
     849                 :            :         .resume = disk_resume,
     850                 :            :         .get_region_size = core_get_region_size,
     851                 :            :         .is_clean = core_is_clean,
     852                 :            :         .in_sync = core_in_sync,
     853                 :            :         .flush = disk_flush,
     854                 :            :         .mark_region = core_mark_region,
     855                 :            :         .clear_region = core_clear_region,
     856                 :            :         .get_resync_work = core_get_resync_work,
     857                 :            :         .set_region_sync = core_set_region_sync,
     858                 :            :         .get_sync_count = core_get_sync_count,
     859                 :            :         .status = disk_status,
     860                 :            : };
     861                 :            : 
     862                 :         28 : static int __init dm_dirty_log_init(void)
     863                 :            : {
     864                 :         28 :         int r;
     865                 :            : 
     866                 :         28 :         r = dm_dirty_log_type_register(&_core_type);
     867         [ -  + ]:         28 :         if (r)
     868                 :          0 :                 DMWARN("couldn't register core log");
     869                 :            : 
     870                 :         28 :         r = dm_dirty_log_type_register(&_disk_type);
     871         [ -  + ]:         28 :         if (r) {
     872                 :          0 :                 DMWARN("couldn't register disk type");
     873                 :          0 :                 dm_dirty_log_type_unregister(&_core_type);
     874                 :            :         }
     875                 :            : 
     876                 :         28 :         return r;
     877                 :            : }
     878                 :            : 
     879                 :          0 : static void __exit dm_dirty_log_exit(void)
     880                 :            : {
     881                 :          0 :         dm_dirty_log_type_unregister(&_disk_type);
     882                 :          0 :         dm_dirty_log_type_unregister(&_core_type);
     883                 :          0 : }
     884                 :            : 
     885                 :            : module_init(dm_dirty_log_init);
     886                 :            : module_exit(dm_dirty_log_exit);
     887                 :            : 
     888                 :            : MODULE_DESCRIPTION(DM_NAME " dirty region log");
     889                 :            : MODULE_AUTHOR("Joe Thornber, Heinz Mauelshagen <dm-devel@redhat.com>");
     890                 :            : MODULE_LICENSE("GPL");

Generated by: LCOV version 1.14