diff options
author | Philipp Reisner <philipp.reisner@linbit.com> | 2009-06-25 15:57:22 +0200 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2009-07-29 10:45:13 +0200 |
commit | 65b0b44dbf9dfec3f78ded84ee22b0a0a1bf82bf (patch) | |
tree | f3d14a3f200594b94717657e682a0a79a33499ef /drivers/block | |
parent | b8e44af93cf7dd81fa1ead3e96b16df843fd99aa (diff) |
Tracking DRBD mainline (and minor cleanups)
* drbd-8.3: (134 commits)
Missing pices of the unaligned memory access stuff.
possible fix for XEN crashes on disconnect
fix regression: initial sync target hung in WFBitMapT
fix a comment: there are no more ioctls.
possible fix for XEN crashes on disconnect
fix regression: initial sync target hung in WFBitMapT
...
Removed compat code from lru_cache.h
All STATIC -> static
DRBD_ENABLE_FAULTS -> CONFIG_DRBD_FAULT_INJECTION
* drbd-8.3:
Fixed some errors/warnings when compiles without DBG_ALL_SYMBOLS (i.e. STATIC = static)
Fixed a regression introduced with fb51e2eb1fac83839231499333bf683629388484
No longer include drbd_config.h directly, include drbd.h instead
Got rid of drbd_config.h
Support lru_cache as module
Removing the drbd_buildtag.c file
* drbd-8.3:
Fixes for architectures that does not support unaligned memory accesses
fix reading of the AL ring buffer
sync handshake: fix detection of "unrelated" data - it was detected as "regular" split-brain
* drbd-8.3:
Preparing 8.3.2rc2
compat: 2.6.31 -- q->limits.* and accessor functions
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Diffstat (limited to 'drivers/block')
-rw-r--r-- | drivers/block/drbd/Kconfig | 32 | ||||
-rw-r--r-- | drivers/block/drbd/Makefile | 2 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_actlog.c | 65 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_bitmap.c | 35 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_buildtag.c | 7 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_int.h | 65 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_main.c | 222 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_nl.c | 362 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_proc.c | 11 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_receiver.c | 235 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_req.c | 10 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_strings.c | 6 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_tracing.c | 10 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_worker.c | 134 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_wrappers.h | 5 |
15 files changed, 707 insertions, 494 deletions
diff --git a/drivers/block/drbd/Kconfig b/drivers/block/drbd/Kconfig index b3676771731d..f133a8925cbb 100644 --- a/drivers/block/drbd/Kconfig +++ b/drivers/block/drbd/Kconfig @@ -46,3 +46,35 @@ config DRBD_TRACE Say Y here if you want to be able to trace various events in DRBD. If unsure, say N. + +config DRBD_FAULT_INJECTION + bool "DRBD fault injection" + depends on BLK_DEV_DRBD + help + + Say Y here if you want to simulate IO errors, in order to test DRBD's + behavior. + + The actual simulation of IO errors is done by writing 3 values to + /sys/module/drbd/parameters/ + + enable_faults: bitmask of... + 1 meta data write + 2 read + 4 resync data write + 8 read + 16 data write + 32 data read + 64 read ahead + 128 kmalloc of bitmap + 256 allocation of EE (epoch_entries) + + fault_devs: bitmask of minor numbers + fault_rate: frequency in percent + + Example: Simulate data write errors on /dev/drbd0 with a probability of 5%. + echo 16 > /sys/module/drbd/parameters/enable_faults + echo 1 > /sys/module/drbd/parameters/fault_devs + echo 5 > /sys/module/drbd/parameters/fault_rate + + If unsure, say N. diff --git a/drivers/block/drbd/Makefile b/drivers/block/drbd/Makefile index 9dd069b0ded0..68d1e7ce9aa3 100644 --- a/drivers/block/drbd/Makefile +++ b/drivers/block/drbd/Makefile @@ -1,4 +1,4 @@ -drbd-y := drbd_buildtag.o drbd_bitmap.o drbd_proc.o +drbd-y := drbd_bitmap.o drbd_proc.o drbd-y += drbd_worker.o drbd_receiver.o drbd_req.o drbd_actlog.o drbd-y += drbd_main.o drbd_strings.o drbd_nl.o diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index 6b096b1720ea..1e53d16c943c 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -77,7 +77,7 @@ void trace_drbd_resync(struct drbd_conf *mdev, int level, const char *fmt, ...) va_end(ap); } -STATIC int _drbd_md_sync_page_io(struct drbd_conf *mdev, +static int _drbd_md_sync_page_io(struct drbd_conf *mdev, struct drbd_backing_dev *bdev, struct page *page, sector_t sector, int rw, int size) @@ -133,7 +133,7 @@ STATIC int _drbd_md_sync_page_io(struct drbd_conf *mdev, int drbd_md_sync_page_io(struct drbd_conf *mdev, struct drbd_backing_dev *bdev, sector_t sector, int rw) { - int hardsect_size, mask, ok; + int logical_block_size, mask, ok; int offset = 0; struct page *iop = mdev->md_io_page; @@ -141,15 +141,15 @@ int drbd_md_sync_page_io(struct drbd_conf *mdev, struct drbd_backing_dev *bdev, BUG_ON(!bdev->md_bdev); - hardsect_size = drbd_get_hardsect_size(bdev->md_bdev); - if (hardsect_size == 0) - hardsect_size = MD_SECTOR_SIZE; + logical_block_size = bdev_logical_block_size(bdev->md_bdev); + if (logical_block_size == 0) + logical_block_size = MD_SECTOR_SIZE; - /* in case hardsect_size != 512 [ s390 only? ] */ - if (hardsect_size != MD_SECTOR_SIZE) { - mask = (hardsect_size / MD_SECTOR_SIZE) - 1; + /* in case logical_block_size != 512 [ s390 only? ] */ + if (logical_block_size != MD_SECTOR_SIZE) { + mask = (logical_block_size / MD_SECTOR_SIZE) - 1; D_ASSERT(mask == 1 || mask == 3 || mask == 7); - D_ASSERT(hardsect_size == (mask+1) * MD_SECTOR_SIZE); + D_ASSERT(logical_block_size == (mask+1) * MD_SECTOR_SIZE); offset = sector & mask; sector = sector & ~mask; iop = mdev->md_io_tmpp; @@ -161,11 +161,11 @@ int drbd_md_sync_page_io(struct drbd_conf *mdev, struct drbd_backing_dev *bdev, void *hp = page_address(mdev->md_io_tmpp); ok = _drbd_md_sync_page_io(mdev, bdev, iop, sector, - READ, hardsect_size); + READ, logical_block_size); if (unlikely(!ok)) { dev_err(DEV, "drbd_md_sync_page_io(,%llus," - "READ [hardsect_size!=512]) failed!\n", + "READ [logical_block_size!=512]) failed!\n", (unsigned long long)sector); return 0; } @@ -180,14 +180,14 @@ int drbd_md_sync_page_io(struct drbd_conf *mdev, struct drbd_backing_dev *bdev, current->comm, current->pid, __func__, (unsigned long long)sector, (rw & WRITE) ? "WRITE" : "READ"); - ok = _drbd_md_sync_page_io(mdev, bdev, iop, sector, rw, hardsect_size); + ok = _drbd_md_sync_page_io(mdev, bdev, iop, sector, rw, logical_block_size); if (unlikely(!ok)) { dev_err(DEV, "drbd_md_sync_page_io(,%llus,%s) failed!\n", (unsigned long long)sector, (rw & WRITE) ? "WRITE" : "READ"); return 0; } - if (hardsect_size != MD_SECTOR_SIZE && !(rw & WRITE)) { + if (logical_block_size != MD_SECTOR_SIZE && !(rw & WRITE)) { void *p = page_address(mdev->md_io_page); void *hp = page_address(mdev->md_io_tmpp); @@ -378,7 +378,7 @@ w_al_write_transaction(struct drbd_conf *mdev, struct drbd_work *w, int unused) * * Returns -1 on IO error, 0 on checksum error and 1 upon success. */ -STATIC int drbd_al_read_tr(struct drbd_conf *mdev, +static int drbd_al_read_tr(struct drbd_conf *mdev, struct drbd_backing_dev *bdev, struct al_transaction *b, int index) @@ -416,14 +416,14 @@ int drbd_al_read_log(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) int i; int rv; int mx; - int cnr; int active_extents = 0; int transactions = 0; - int overflow = 0; - int from = -1; - int to = -1; - u32 from_tnr = -1; + int found_valid = 0; + int from = 0; + int to = 0; + u32 from_tnr = 0; u32 to_tnr = 0; + u32 cnr; mx = div_ceil(mdev->act_log->nr_elements, AL_EXTENTS_PT); @@ -444,22 +444,27 @@ int drbd_al_read_log(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) } cnr = be32_to_cpu(buffer->tr_number); - if (cnr == -1) - overflow = 1; - - if (cnr < from_tnr && !overflow) { + if (++found_valid == 1) { + from = i; + to = i; + from_tnr = cnr; + to_tnr = cnr; + continue; + } + if ((int)cnr - (int)from_tnr < 0) { + D_ASSERT(from_tnr - cnr + i - from == mx+1); from = i; from_tnr = cnr; } - if (cnr > to_tnr) { + if ((int)cnr - (int)to_tnr > 0) { + D_ASSERT(cnr - to_tnr == i - to); to = i; to_tnr = cnr; } } - if (from == -1 || to == -1) { + if (!found_valid) { dev_warn(DEV, "No usable activity log found.\n"); - mutex_unlock(&mdev->md_io_mutex); return 1; } @@ -524,7 +529,7 @@ cancel: return 1; } -STATIC void atodb_endio(struct bio *bio, int error) +static void atodb_endio(struct bio *bio, int error) { struct drbd_atodb_wait *wc = bio->bi_private; struct drbd_conf *mdev = wc->mdev; @@ -555,7 +560,7 @@ STATIC void atodb_endio(struct bio *bio, int error) #define S2W(s) ((s)<<(BM_EXT_SHIFT-BM_BLOCK_SHIFT-LN2_BPL)) /* activity log to on disk bitmap -- prepare bio unless that sector * is already covered by previously prepared bios */ -STATIC int atodb_prepare_unless_covered(struct drbd_conf *mdev, +static int atodb_prepare_unless_covered(struct drbd_conf *mdev, struct bio **bios, unsigned int enr, struct drbd_atodb_wait *wc) __must_hold(local) @@ -803,7 +808,7 @@ void drbd_al_shrink(struct drbd_conf *mdev) wake_up(&mdev->al_wait); } -STATIC int w_update_odbm(struct drbd_conf *mdev, struct drbd_work *w, int unused) +static int w_update_odbm(struct drbd_conf *mdev, struct drbd_work *w, int unused) { struct update_odbm_work *udw = (struct update_odbm_work *)w; @@ -840,7 +845,7 @@ STATIC int w_update_odbm(struct drbd_conf *mdev, struct drbd_work *w, int unused * * TODO will be obsoleted once we have a caching lru of the on disk bitmap */ -STATIC void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector, +static void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector, int count, int success) { struct lc_element *e; diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index d9b59b0611b0..417da6e3cea3 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -26,6 +26,7 @@ #include <linux/vmalloc.h> #include <linux/string.h> #include <linux/drbd.h> +#include <asm/kmap_types.h> #include "drbd_int.h" /* OPAQUE outside this file! @@ -150,7 +151,7 @@ void drbd_bm_unlock(struct drbd_conf *mdev) } /* word offset to long pointer */ -STATIC unsigned long *__bm_map_paddr(struct drbd_bitmap *b, unsigned long offset, const enum km_type km) +static unsigned long *__bm_map_paddr(struct drbd_bitmap *b, unsigned long offset, const enum km_type km) { struct page *page; unsigned long page_nr; @@ -197,7 +198,7 @@ void bm_unmap(unsigned long *p_addr) * to be able to report device specific. */ -STATIC void bm_free_pages(struct page **pages, unsigned long number) +static void bm_free_pages(struct page **pages, unsigned long number) { unsigned long i; if (!pages) @@ -215,7 +216,7 @@ STATIC void bm_free_pages(struct page **pages, unsigned long number) } } -STATIC void bm_vk_free(void *ptr, int v) +static void bm_vk_free(void *ptr, int v) { if (v) vfree(ptr); @@ -226,7 +227,7 @@ STATIC void bm_vk_free(void *ptr, int v) /* * "have" and "want" are NUMBER OF PAGES. */ -STATIC struct page **bm_realloc_pages(struct drbd_bitmap *b, unsigned long want) +static struct page **bm_realloc_pages(struct drbd_bitmap *b, unsigned long want) { struct page **old_pages = b->bm_pages; struct page **new_pages, *page; @@ -239,7 +240,11 @@ STATIC struct page **bm_realloc_pages(struct drbd_bitmap *b, unsigned long want) if (have == want) return old_pages; - /* Trying kmalloc first, falling back to vmalloc... */ + /* Trying kmalloc first, falling back to vmalloc. + * GFP_KERNEL is ok, as this is done when a lower level disk is + * "attached" to the drbd. Context is receiver thread or cqueue + * thread. As we have no disk yet, we are not in the IO path, + * not even the IO path of the peer. */ bytes = sizeof(struct page *)*want; new_pages = kmalloc(bytes, GFP_KERNEL); if (!new_pages) { @@ -320,7 +325,7 @@ void drbd_bm_cleanup(struct drbd_conf *mdev) * this masks out the remaining bits. * Rerturns the number of bits cleared. */ -STATIC int bm_clear_surplus(struct drbd_bitmap *b) +static int bm_clear_surplus(struct drbd_bitmap *b) { const unsigned long mask = (1UL << (b->bm_bits & (BITS_PER_LONG-1))) - 1; size_t w = b->bm_bits >> LN2_BPL; @@ -343,7 +348,7 @@ STATIC int bm_clear_surplus(struct drbd_bitmap *b) return cleared; } -STATIC void bm_set_surplus(struct drbd_bitmap *b) +static void bm_set_surplus(struct drbd_bitmap *b) { const unsigned long mask = (1UL << (b->bm_bits & (BITS_PER_LONG-1))) - 1; size_t w = b->bm_bits >> LN2_BPL; @@ -362,7 +367,7 @@ STATIC void bm_set_surplus(struct drbd_bitmap *b) bm_unmap(p_addr); } -STATIC unsigned long __bm_count_bits(struct drbd_bitmap *b, const int swap_endian) +static unsigned long __bm_count_bits(struct drbd_bitmap *b, const int swap_endian) { unsigned long *p_addr, *bm, offset = 0; unsigned long bits = 0; @@ -420,7 +425,7 @@ void _drbd_bm_recount_bits(struct drbd_conf *mdev, char *file, int line) } /* offset and len in long words.*/ -STATIC void bm_memset(struct drbd_bitmap *b, size_t offset, int c, size_t len) +static void bm_memset(struct drbd_bitmap *b, size_t offset, int c, size_t len) { unsigned long *p_addr, *bm; size_t do_now, end; @@ -752,7 +757,7 @@ static void bm_async_io_complete(struct bio *bio, int error) bio_put(bio); } -STATIC void bm_page_io_async(struct drbd_conf *mdev, struct drbd_bitmap *b, int page_nr, int rw) __must_hold(local) +static void bm_page_io_async(struct drbd_conf *mdev, struct drbd_bitmap *b, int page_nr, int rw) __must_hold(local) { /* we are process context. we always get a bio */ struct bio *bio = bio_alloc(GFP_KERNEL, 1); @@ -790,6 +795,8 @@ void bm_cpu_to_lel(struct drbd_bitmap *b) * this may be optimized by using * cpu_to_lel(-1) == -1 and cpu_to_lel(0) == 0; * the following is still not optimal, but better than nothing */ + unsigned int i; + unsigned long *p_addr, *bm; if (b->bm_set == 0) { /* no page at all; avoid swap if all is 0 */ i = b->bm_number_of_pages; @@ -801,12 +808,10 @@ void bm_cpu_to_lel(struct drbd_bitmap *b) i = 0; } for (; i < b->bm_number_of_pages; i++) { - unsigned long *bm; - /* if you'd want to use kmap_atomic, you'd have to disable irq! */ - p_addr = kmap(b->bm_pages[i]); + p_addr = kmap_atomic(b->bm_pages[i], KM_USER0); for (bm = p_addr; bm < p_addr + PAGE_SIZE/sizeof(long); bm++) *bm = cpu_to_lel(*bm); - kunmap(p_addr); + kunmap_atomic(p_addr, KM_USER0); } } # endif @@ -816,7 +821,7 @@ void bm_cpu_to_lel(struct drbd_bitmap *b) /* * bm_rw: read/write the whole bitmap from/to its on disk location. */ -STATIC int bm_rw(struct drbd_conf *mdev, int rw) __must_hold(local) +static int bm_rw(struct drbd_conf *mdev, int rw) __must_hold(local) { struct drbd_bitmap *b = mdev->bitmap; /* sector_t sector; */ diff --git a/drivers/block/drbd/drbd_buildtag.c b/drivers/block/drbd/drbd_buildtag.c deleted file mode 100644 index 20fe72a104d3..000000000000 --- a/drivers/block/drbd/drbd_buildtag.c +++ /dev/null @@ -1,7 +0,0 @@ -/* automatically generated. DO NOT EDIT. */ -#include <linux/drbd_config.h> -const char *drbd_buildtag(void) -{ - return "GIT-hash: b0abb3832a730d4fbd145013f6f51fc977bba3cc drbd/drbd_int.h" - " build by phil@fat-tyre, 2009-05-15 11:54:26"; -} diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 83f9f33e65ea..a63595d80579 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -106,22 +106,6 @@ extern char usermode_helper[]; struct drbd_conf; -#ifdef DBG_ALL_SYMBOLS -# define STATIC -#else -# define STATIC static -#endif - -/* - * Some Message Macros - *************************/ - -#define DUMPP(A) dev_err(DEV, #A " = %p in %s:%d\n", (A), __FILE__, __LINE__); -#define DUMPLU(A) dev_err(DEV, #A " = %lu in %s:%d\n", (unsigned long)(A), __FILE__, __LINE__); -#define DUMPLLU(A) dev_err(DEV, #A " = %llu in %s:%d\n", (unsigned long long)(A), __FILE__, __LINE__); -#define DUMPLX(A) dev_err(DEV, #A " = %lx in %s:%d\n", (A), __FILE__, __LINE__); -#define DUMPI(A) dev_err(DEV, #A " = %d in %s:%d\n", (int)(A), __FILE__, __LINE__); - /* to shorten dev_warn(DEV, "msg"); and relatives statements */ #define DEV (disk_to_dev(mdev->vdisk)) @@ -139,14 +123,14 @@ struct drbd_conf; /* Defines to control fault insertion */ enum { DRBD_FAULT_MD_WR = 0, /* meta data write */ - DRBD_FAULT_MD_RD, /* read */ - DRBD_FAULT_RS_WR, /* resync */ - DRBD_FAULT_RS_RD, - DRBD_FAULT_DT_WR, /* data */ - DRBD_FAULT_DT_RD, - DRBD_FAULT_DT_RA, /* data read ahead */ - DRBD_FAULT_BM_ALLOC, /* bitmap allocation */ - DRBD_FAULT_AL_EE, /* alloc ee */ + DRBD_FAULT_MD_RD = 1, /* read */ + DRBD_FAULT_RS_WR = 2, /* resync */ + DRBD_FAULT_RS_RD = 3, + DRBD_FAULT_DT_WR = 4, /* data */ + DRBD_FAULT_DT_RD = 5, + DRBD_FAULT_DT_RA = 6, /* data read ahead */ + DRBD_FAULT_BM_ALLOC = 7, /* bitmap allocation */ + DRBD_FAULT_AL_EE = 8, /* alloc ee */ DRBD_FAULT_MAX, }; @@ -332,6 +316,10 @@ static inline void bm_xfer_ctx_bit_to_word_offset(struct bm_xfer_ctx *c) #endif } +#ifndef __packed +#define __packed __attribute__((packed)) +#endif + /* This is the layout for a packet on the wire. * The byteorder is the network byte order. * (except block_id and barrier fields. @@ -543,6 +531,7 @@ struct p_compressed_bm { u8 code[0]; } __packed; +/* DCBP: Drbd Compressed Bitmap Packet ... */ static inline enum drbd_bitmap_code DCBP_get_code(struct p_compressed_bm *p) { @@ -795,6 +784,8 @@ enum { * but worker thread is still handling the cleanup. * reconfiguring (nl_disk_conf, nl_net_conf) is dissalowed, * while this is set. */ + RESIZE_PENDING, /* Size change detected locally, waiting for the response from + * the peer, if it changed there as well. */ }; struct drbd_bitmap; /* opaque for drbd_conf */ @@ -946,12 +937,16 @@ struct drbd_conf { unsigned long rs_mark_time; /* skipped because csum was equeal [unit BM_BLOCK_SIZE] */ unsigned long rs_same_csum; + + /* where does the admin want us to start? (sector) */ + sector_t ov_start_sector; + /* where are we now? (sector) */ sector_t ov_position; - /* Start sector of out of sync range. */ + /* Start sector of out of sync range (to merge printk reporting). */ sector_t ov_last_oos_start; /* size of out-of-sync range in sectors. */ sector_t ov_last_oos_size; - unsigned long ov_left; + unsigned long ov_left; /* in bits */ struct crypto_hash *csums_tfm; struct crypto_hash *verify_tfm; @@ -991,7 +986,7 @@ struct drbd_conf { atomic_t pp_in_use; wait_queue_head_t ee_wait; struct page *md_io_page; /* one page buffer for md_io */ - struct page *md_io_tmpp; /* for hardsect_size != 512 [s390 only?] */ + struct page *md_io_tmpp; /* for logical_block_size != 512 */ struct mutex md_io_mutex; /* protects the md_io_buffer */ spinlock_t al_lock; wait_queue_head_t al_wait; @@ -1103,7 +1098,7 @@ extern int drbd_send_protocol(struct drbd_conf *mdev); extern int drbd_send_uuids(struct drbd_conf *mdev); extern int drbd_send_uuids_skip_initial_sync(struct drbd_conf *mdev); extern int drbd_send_sync_uuid(struct drbd_conf *mdev, u64 val); -extern int drbd_send_sizes(struct drbd_conf *mdev); +extern int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply); extern int _drbd_send_state(struct drbd_conf *mdev); extern int drbd_send_state(struct drbd_conf *mdev); extern int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock, @@ -1127,8 +1122,6 @@ extern int drbd_send_ack_dp(struct drbd_conf *mdev, enum drbd_packets cmd, struct p_data *dp); extern int drbd_send_ack_ex(struct drbd_conf *mdev, enum drbd_packets cmd, sector_t sector, int blksize, u64 block_id); -extern int _drbd_send_page(struct drbd_conf *mdev, struct page *page, - int offset, size_t size); extern int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd, struct drbd_epoch_entry *e); extern int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req); @@ -1348,7 +1341,9 @@ extern int drbd_bm_count_bits(struct drbd_conf *mdev, const unsigned long s, con /* drbd_main.c */ extern struct kmem_cache *drbd_request_cache; -extern struct kmem_cache *drbd_ee_cache; +extern struct kmem_cache *drbd_ee_cache; /* epoch entries */ +extern struct kmem_cache *drbd_bm_ext_cache; /* bitmap extents */ +extern struct kmem_cache *drbd_al_ext_cache; /* activity log extents */ extern mempool_t *drbd_request_mempool; extern mempool_t *drbd_ee_mempool; @@ -1388,7 +1383,7 @@ extern int drbd_khelper(struct drbd_conf *mdev, char *cmd); /* drbd_worker.c */ extern int drbd_worker(struct drbd_thread *thi); -extern void drbd_alter_sa(struct drbd_conf *mdev, int na); +extern int drbd_alter_sa(struct drbd_conf *mdev, int na); extern void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side); extern void resume_next_sg(struct drbd_conf *mdev); extern void suspend_other_sg(struct drbd_conf *mdev); @@ -1409,7 +1404,7 @@ static inline void ov_oos_print(struct drbd_conf *mdev) } -void drbd_csum(struct drbd_conf *, struct crypto_hash *, struct bio *, void *); +extern void drbd_csum(struct drbd_conf *, struct crypto_hash *, struct bio *, void *); /* worker callbacks */ extern int w_req_cancel_conflict(struct drbd_conf *, struct drbd_work *, int); extern int w_read_retry_remote(struct drbd_conf *, struct drbd_work *, int); @@ -1704,9 +1699,11 @@ static inline sector_t drbd_md_last_sector(struct drbd_backing_dev *bdev) } } +/* Returns the number of 512 byte sectors of the device */ static inline sector_t drbd_get_capacity(struct block_device *bdev) { - return bdev ? get_capacity(bdev->bd_disk) : 0; + /* return bdev ? get_capacity(bdev->bd_disk) : 0; */ + return bdev ? bdev->bd_inode->i_size >> 9 : 0; } /** diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index ad296842b960..73c6a9da7645 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -26,7 +26,7 @@ #include <linux/autoconf.h> #include <linux/module.h> #include <linux/version.h> - +#include <linux/drbd.h> #include <asm/uaccess.h> #include <asm/types.h> #include <net/sock.h> @@ -37,7 +37,6 @@ #include <linux/proc_fs.h> #include <linux/init.h> #include <linux/mm.h> -#include <linux/drbd_config.h> #include <linux/memcontrol.h> #include <linux/mm_inline.h> #include <linux/slab.h> @@ -50,7 +49,6 @@ #include <linux/unistd.h> #include <linux/vmalloc.h> -#include <linux/drbd.h> #include <linux/drbd_limits.h> #include "drbd_int.h" #include "drbd_tracing.h" @@ -73,12 +71,12 @@ int drbd_asender(struct drbd_thread *); int drbd_init(void); static int drbd_open(struct block_device *bdev, fmode_t mode); static int drbd_release(struct gendisk *gd, fmode_t mode); -STATIC int w_after_state_ch(struct drbd_conf *mdev, struct drbd_work *w, int unused); -STATIC void after_state_ch(struct drbd_conf *mdev, union drbd_state os, +static int w_after_state_ch(struct drbd_conf *mdev, struct drbd_work *w, int unused); +static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, union drbd_state ns, enum chg_state_flags flags); -STATIC int w_md_sync(struct drbd_conf *mdev, struct drbd_work *w, int unused); -STATIC void md_sync_timer_fn(unsigned long data); -STATIC int w_bitmap_io(struct drbd_conf *mdev, struct drbd_work *w, int unused); +static int w_md_sync(struct drbd_conf *mdev, struct drbd_work *w, int unused); +static void md_sync_timer_fn(unsigned long data); +static int w_bitmap_io(struct drbd_conf *mdev, struct drbd_work *w, int unused); DEFINE_TRACE(drbd_unplug); DEFINE_TRACE(drbd_uuid); @@ -95,6 +93,7 @@ DEFINE_TRACE(drbd_req); MODULE_AUTHOR("Philipp Reisner <phil@linbit.com>, " "Lars Ellenberg <lars@linbit.com>"); MODULE_DESCRIPTION("drbd - Distributed Replicated Block Device v" REL_VERSION); +MODULE_VERSION(REL_VERSION); MODULE_LICENSE("GPL"); MODULE_PARM_DESC(minor_count, "Maximum number of drbd devices (1-255)"); MODULE_ALIAS_BLOCKDEV_MAJOR(DRBD_MAJOR); @@ -110,7 +109,7 @@ module_param(allow_oos, bool, 0); module_param(cn_idx, uint, 0444); module_param(proc_details, int, 0644); -#ifdef DRBD_ENABLE_FAULTS +#ifdef CONFIG_DRBD_FAULT_INJECTION int enable_faults; int fault_rate; static int fault_count; @@ -144,7 +143,9 @@ module_param_string(usermode_helper, usermode_helper, sizeof(usermode_helper), 0 struct drbd_conf **minor_table; struct kmem_cache *drbd_request_cache; -struct kmem_cache *drbd_ee_cache; +struct kmem_cache *drbd_ee_cache; /* epoch entries */ +struct kmem_cache *drbd_bm_ext_cache; /* bitmap extents */ +struct kmem_cache *drbd_al_ext_cache; /* activity log extents */ mempool_t *drbd_request_mempool; mempool_t *drbd_ee_mempool; @@ -161,7 +162,7 @@ wait_queue_head_t drbd_pp_wait; DEFINE_RATELIMIT_STATE(drbd_ratelimit_state, 5 * HZ, 5); -STATIC struct block_device_operations drbd_ops = { +static struct block_device_operations drbd_ops = { .owner = THIS_MODULE, .open = drbd_open, .release = drbd_release, @@ -198,10 +199,11 @@ int _get_ldev_if_state(struct drbd_conf *mdev, enum drbd_disk_state mins) * Each &struct drbd_tl_epoch has a circular double linked list of requests * attached. */ -STATIC int tl_init(struct drbd_conf *mdev) +static int tl_init(struct drbd_conf *mdev) { struct drbd_tl_epoch *b; + /* during device minor initialization, we may well use GFP_KERNEL */ b = kmalloc(sizeof(struct drbd_tl_epoch), GFP_KERNEL); if (!b) return 0; @@ -222,7 +224,7 @@ STATIC int tl_init(struct drbd_conf *mdev) return 1; } -STATIC void tl_cleanup(struct drbd_conf *mdev) +static void tl_cleanup(struct drbd_conf *mdev) { D_ASSERT(mdev->oldest_tle == mdev->newest_tle); D_ASSERT(list_empty(&mdev->out_of_sequence_requests)); @@ -472,7 +474,7 @@ int drbd_io_error(struct drbd_conf *mdev, int force_detach) * @os: old (current) state. * @ns: new (wanted) state. */ -STATIC int cl_wide_st_chg(struct drbd_conf *mdev, +static int cl_wide_st_chg(struct drbd_conf *mdev, union drbd_state os, union drbd_state ns) { return (os.conn >= C_CONNECTED && ns.conn >= C_CONNECTED && @@ -513,15 +515,15 @@ void drbd_force_state(struct drbd_conf *mdev, drbd_change_state(mdev, CS_HARD, mask, val); } -STATIC int is_valid_state(struct drbd_conf *mdev, union drbd_state ns); -STATIC int is_valid_state_transition(struct drbd_conf *, +static int is_valid_state(struct drbd_conf *mdev, union drbd_state ns); +static int is_valid_state_transition(struct drbd_conf *, union drbd_state, union drbd_state); -STATIC union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state os, +static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state os, union drbd_state ns, int *warn_sync_abort); int drbd_send_state_req(struct drbd_conf *, union drbd_state, union drbd_state); -STATIC enum drbd_state_ret_codes _req_st_cond(struct drbd_conf *mdev, +static enum drbd_state_ret_codes _req_st_cond(struct drbd_conf *mdev, union drbd_state mask, union drbd_state val) { union drbd_state os, ns; @@ -565,7 +567,7 @@ STATIC enum drbd_state_ret_codes _req_st_cond(struct drbd_conf *mdev, * Should not be called directly, use drbd_request_state() or * _drbd_request_state(). */ -STATIC int drbd_req_state(struct drbd_conf *mdev, +static int drbd_req_state(struct drbd_conf *mdev, union drbd_state mask, union drbd_state val, enum chg_state_flags f) { @@ -658,7 +660,7 @@ int _drbd_request_state(struct drbd_conf *mdev, union drbd_state mask, return rv; } -STATIC void print_st(struct drbd_conf *mdev, char *name, union drbd_state ns) +static void print_st(struct drbd_conf *mdev, char *name, union drbd_state ns) { dev_err(DEV, " %s = { cs:%s ro:%s/%s ds:%s/%s %c%c%c%c }\n", name, @@ -705,7 +707,7 @@ void print_st_err(struct drbd_conf *mdev, * @mdev: DRBD device. * @ns: State to consider. */ -STATIC int is_valid_state(struct drbd_conf *mdev, union drbd_state ns) +static int is_valid_state(struct drbd_conf *mdev, union drbd_state ns) { /* See drbd_state_sw_errors in drbd_strings.c */ @@ -740,11 +742,11 @@ STATIC int is_valid_state(struct drbd_conf *mdev, union drbd_state ns) else if (ns.role == R_PRIMARY && ns.disk <= D_INCONSISTENT && ns.pdsk <= D_INCONSISTENT) rv = SS_NO_UP_TO_DATE_DISK; - else if (ns.conn > C_CONNECTED && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE) - rv = SS_BOTH_INCONSISTENT; + else if (ns.conn > C_CONNECTED && ns.disk < D_INCONSISTENT) + rv = SS_NO_LOCAL_DISK; - else if (ns.conn > C_CONNECTED && (ns.disk == D_DISKLESS || ns.pdsk == D_DISKLESS)) - rv = SS_SYNCING_DISKLESS; + else if (ns.conn > C_CONNECTED && ns.pdsk < D_INCONSISTENT) + rv = SS_NO_REMOTE_DISK; else if ((ns.conn == C_CONNECTED || ns.conn == C_WF_BITMAP_S || @@ -770,7 +772,7 @@ STATIC int is_valid_state(struct drbd_conf *mdev, union drbd_state ns) * @ns: new state. * @os: old state. */ -STATIC int is_valid_state_transition(struct drbd_conf *mdev, +static int is_valid_state_transition(struct drbd_conf *mdev, union drbd_state ns, union drbd_state os) { int rv = SS_SUCCESS; @@ -821,7 +823,7 @@ STATIC int is_valid_state_transition(struct drbd_conf *mdev, * When we loose connection, we have to set the state of the peers disk (pdsk) * to D_UNKNOWN. This rule and many more along those lines are in this function. */ -STATIC union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state os, +static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state os, union drbd_state ns, int *warn_sync_abort) { enum drbd_fencing_p fp; @@ -948,6 +950,25 @@ STATIC union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state return ns; } +/* helper for __drbd_set_state */ +static void set_ov_position(struct drbd_conf *mdev, enum drbd_conns cs) +{ + if (cs == C_VERIFY_T) { + /* starting online verify from an arbitrary position + * does not fit well into the existion protocol. + * on C_VERIFY_T, we initialize ov_left and friends + * implicitly in receive_DataRequest once the + * first P_OV_REQUEST is received */ + mdev->ov_start_sector = ~(sector_t)0; + } else { + unsigned long bit = BM_SECT_TO_BIT(mdev->ov_start_sector); + if (bit >= mdev->rs_total) + mdev->ov_start_sector = + BM_BIT_TO_SECT(mdev->rs_total - 1); + mdev->ov_position = mdev->ov_start_sector; + } +} + /** * __drbd_set_state() - Set a new DRBD state * @mdev: DRBD device. @@ -1043,6 +1064,15 @@ int __drbd_set_state(struct drbd_conf *mdev, mod_timer(&mdev->resync_timer, jiffies); } + /* aborted verify run. log the last position */ + if ((os.conn == C_VERIFY_S || os.conn == C_VERIFY_T) && + ns.conn < C_CONNECTED) { + mdev->ov_start_sector = + BM_BIT_TO_SECT(mdev->rs_total - mdev->ov_left); + dev_info(DEV, "Online Verify reached sector %llu\n", + (unsigned long long)mdev->ov_start_sector); + } + if ((os.conn == C_PAUSED_SYNC_T || os.conn == C_PAUSED_SYNC_S) && (ns.conn == C_SYNC_TARGET || ns.conn == C_SYNC_SOURCE)) { dev_info(DEV, "Syncer continues.\n"); @@ -1068,16 +1098,24 @@ int __drbd_set_state(struct drbd_conf *mdev, if (os.conn == C_CONNECTED && (ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T)) { mdev->ov_position = 0; - mdev->ov_left = mdev->rs_total = mdev->rs_mark_left = drbd_bm_bits(mdev); + if (mdev->agreed_pro_version >= 90) + set_ov_position(mdev, ns.conn); + else + mdev->ov_start_sector = 0; + mdev->ov_left = mdev->rs_total + - BM_SECT_TO_BIT(mdev->ov_position); mdev->rs_start = mdev->rs_mark_time = jiffies; mdev->ov_last_oos_size = 0; mdev->ov_last_oos_start = 0; - if (ns.conn == C_VERIFY_S) + if (ns.conn == C_VERIFY_S) { + dev_info(DEV, "Starting Online Verify from sector %llu\n", + (unsigned long long)mdev->ov_position); mod_timer(&mdev->resync_timer, jiffies); + } } if (get_ldev(mdev)) { @@ -1140,7 +1178,7 @@ int __drbd_set_state(struct drbd_conf *mdev, return rv; } -STATIC int w_after_state_ch(struct drbd_conf *mdev, struct drbd_work *w, int unused) +static int w_after_state_ch(struct drbd_conf *mdev, struct drbd_work *w, int unused) { struct after_state_chg_work *ascw; @@ -1180,7 +1218,7 @@ static void abw_start_sync(struct drbd_conf *mdev, int rv) * @ns: new state. * @flags: Flags */ -STATIC void after_state_ch(struct drbd_conf *mdev, union drbd_state os, +static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, union drbd_state ns, enum chg_state_flags flags) { enum drbd_fencing_p fp; @@ -1260,7 +1298,7 @@ STATIC void after_state_ch(struct drbd_conf *mdev, union drbd_state os, os.disk == D_ATTACHING && ns.disk == D_NEGOTIATING) { kfree(mdev->p_uuid); /* We expect to receive up-to-date UUIDs soon. */ mdev->p_uuid = NULL; /* ...to not use the old ones in the mean time */ - drbd_send_sizes(mdev); /* to start sync... */ + drbd_send_sizes(mdev, 0); /* to start sync... */ drbd_send_uuids(mdev); drbd_send_state(mdev); } @@ -1327,7 +1365,7 @@ STATIC void after_state_ch(struct drbd_conf *mdev, union drbd_state os, (os.user_isp && !ns.user_isp)) resume_next_sg(mdev); - /* Upon network connection, we need to start the received */ + /* Upon network connection, we need to start the receiver */ if (os.conn == C_STANDALONE && ns.conn == C_UNCONNECTED) drbd_thread_start(&mdev->receiver); @@ -1347,7 +1385,7 @@ STATIC void after_state_ch(struct drbd_conf *mdev, union drbd_state os, } -STATIC int drbd_thread_setup(void *arg) +static int drbd_thread_setup(void *arg) { struct drbd_thread *thi = (struct drbd_thread *) arg; struct drbd_conf *mdev = thi->mdev; @@ -1389,7 +1427,7 @@ restart: return retval; } -STATIC void drbd_thread_init(struct drbd_conf *mdev, struct drbd_thread *thi, +static void drbd_thread_init(struct drbd_conf *mdev, struct drbd_thread *thi, int (*func) (struct drbd_thread *)) { spin_lock_init(&thi->t_lock); @@ -1466,6 +1504,7 @@ int drbd_thread_start(struct drbd_thread *thi) void _drbd_thread_stop(struct drbd_thread *thi, int restart, int wait) { unsigned long flags; + enum drbd_thread_state ns = restart ? Restarting : Exiting; /* may be called from state engine, holding the req lock irqsave */ @@ -1685,7 +1724,9 @@ int drbd_send_protocol(struct drbd_conf *mdev) if (mdev->agreed_pro_version >= 87) size += strlen(mdev->net_conf->integrity_alg) + 1; - p = kmalloc(size, GFP_KERNEL); + /* we must not recurse into our own queue, + * as that is blocked during handshake */ + p = kmalloc(size, GFP_NOIO); if (p == NULL) return 0; @@ -1750,7 +1791,7 @@ int drbd_send_sync_uuid(struct drbd_conf *mdev, u64 val) (struct p_header *)&p, sizeof(p)); } -int drbd_send_sizes(struct drbd_conf *mdev) +int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply) { struct p_sizes p; sector_t d_size, u_size; @@ -1772,8 +1813,8 @@ int drbd_send_sizes(struct drbd_conf *mdev) p.d_size = cpu_to_be64(d_size); p.u_size = cpu_to_be64(u_size); - p.c_size = cpu_to_be64(drbd_get_capacity(mdev->this_bdev)); - p.max_segment_size = cpu_to_be32(mdev->rq_queue->max_segment_size); + p.c_size = cpu_to_be64(trigger_reply ? 0 : drbd_get_capacity(mdev->this_bdev)); + p.max_segment_size = cpu_to_be32(queue_max_segment_size(mdev->rq_queue)); p.queue_order_type = cpu_to_be32(q_order_type); ok = drbd_send_cmd(mdev, USE_DATA_SOCKET, P_SIZES, @@ -1846,7 +1887,7 @@ int fill_bitmap_rle_bits(struct drbd_conf *mdev, int bits; /* may we use this feature? */ - if ((mdev->sync_conf.use_rle_encoding == 0) || + if ((mdev->sync_conf.use_rle == 0) || (mdev->agreed_pro_version < 90)) return 0; @@ -2057,7 +2098,7 @@ int drbd_send_b_ack(struct drbd_conf *mdev, u32 barrier_nr, u32 set_size) * @blksize: size in byte, needs to be in big endian byte order * @block_id: Id, big endian byte order */ -STATIC int _drbd_send_ack(struct drbd_conf *mdev, enum drbd_packets cmd, +static int _drbd_send_ack(struct drbd_conf *mdev, enum drbd_packets cmd, u64 sector, u32 blksize, u64 block_id) @@ -2179,7 +2220,7 @@ int drbd_send_ov_request(struct drbd_conf *mdev, sector_t sector, int size) * returns FALSE if we should retry, * TRUE if we think connection is dead */ -STATIC int we_should_drop_the_connection(struct drbd_conf *mdev, struct socket *sock) +static int we_should_drop_the_connection(struct drbd_conf *mdev, struct socket *sock) { int drop_it; /* long elapsed = (long)(jiffies - mdev->last_received); */ @@ -2223,7 +2264,7 @@ STATIC int we_should_drop_the_connection(struct drbd_conf *mdev, struct socket * * As a workaround, we disable sendpage on pages * with page_count == 0 or PageSlab. */ -STATIC int _drbd_no_send_page(struct drbd_conf *mdev, struct page *page, +static int _drbd_no_send_page(struct drbd_conf *mdev, struct page *page, int offset, size_t size) { int sent = drbd_send(mdev, mdev->data.socket, kmap(page) + offset, size, 0); @@ -2233,7 +2274,7 @@ STATIC int _drbd_no_send_page(struct drbd_conf *mdev, struct page *page, return sent == size; } -int _drbd_send_page(struct drbd_conf *mdev, struct page *page, +static int _drbd_send_page(struct drbd_conf *mdev, struct page *page, int offset, size_t size) { mm_segment_t oldfs = get_fs(); @@ -2527,7 +2568,7 @@ static int drbd_release(struct gendisk *gd, fmode_t mode) return 0; } -STATIC void drbd_unplug_fn(struct request_queue *q) +static void drbd_unplug_fn(struct request_queue *q) { struct drbd_conf *mdev = q->queuedata; @@ -2558,7 +2599,7 @@ STATIC void drbd_unplug_fn(struct request_queue *q) drbd_kick_lo(mdev); } -STATIC void drbd_set_defaults(struct drbd_conf *mdev) +static void drbd_set_defaults(struct drbd_conf *mdev) { mdev->sync_conf.after = DRBD_AFTER_DEF; mdev->sync_conf.rate = DRBD_RATE_DEF; @@ -2697,7 +2738,7 @@ void drbd_mdev_cleanup(struct drbd_conf *mdev) } -STATIC void drbd_destroy_mempools(void) +static void drbd_destroy_mempools(void) { struct page *page; @@ -2718,16 +2759,22 @@ STATIC void drbd_destroy_mempools(void) kmem_cache_destroy(drbd_ee_cache); if (drbd_request_cache) kmem_cache_destroy(drbd_request_cache); + if (drbd_bm_ext_cache) + kmem_cache_destroy(drbd_bm_ext_cache); + if (drbd_al_ext_cache) + kmem_cache_destroy(drbd_al_ext_cache); drbd_ee_mempool = NULL; drbd_request_mempool = NULL; drbd_ee_cache = NULL; drbd_request_cache = NULL; + drbd_bm_ext_cache = NULL; + drbd_al_ext_cache = NULL; return; } -STATIC int drbd_create_mempools(void) +static int drbd_create_mempools(void) { struct page *page; const int number = (DRBD_MAX_SEGMENT_SIZE/PAGE_SIZE) * minor_count; @@ -2737,19 +2784,31 @@ STATIC int drbd_create_mempools(void) drbd_request_mempool = NULL; drbd_ee_cache = NULL; drbd_request_cache = NULL; + drbd_bm_ext_cache = NULL; + drbd_al_ext_cache = NULL; drbd_pp_pool = NULL; /* caches */ drbd_request_cache = kmem_cache_create( - "drbd_req_cache", sizeof(struct drbd_request), 0, 0, NULL); + "drbd_req", sizeof(struct drbd_request), 0, 0, NULL); if (drbd_request_cache == NULL) goto Enomem; drbd_ee_cache = kmem_cache_create( - "drbd_ee_cache", sizeof(struct drbd_epoch_entry), 0, 0, NULL); + "drbd_ee", sizeof(struct drbd_epoch_entry), 0, 0, NULL); if (drbd_ee_cache == NULL) goto Enomem; + drbd_bm_ext_cache = kmem_cache_create( + "drbd_bm", sizeof(struct bm_extent), 0, 0, NULL); + if (drbd_bm_ext_cache == NULL) + goto Enomem; + + drbd_al_ext_cache = kmem_cache_create( + "drbd_al", sizeof(struct lc_element), 0, 0, NULL); + if (drbd_al_ext_cache == NULL) + goto Enomem; + /* mempools */ drbd_request_mempool = mempool_create(number, mempool_alloc_slab, mempool_free_slab, drbd_request_cache); @@ -2780,7 +2839,7 @@ Enomem: return -ENOMEM; } -STATIC int drbd_notify_sys(struct notifier_block *this, unsigned long code, +static int drbd_notify_sys(struct notifier_block *this, unsigned long code, void *unused) { /* just so we have it. you never know what interessting things we @@ -2790,7 +2849,7 @@ STATIC int drbd_notify_sys(struct notifier_block *this, unsigned long code, return NOTIFY_DONE; } -STATIC struct notifier_block drbd_notifier = { +static struct notifier_block drbd_notifier = { .notifier_call = drbd_notify_sys, }; @@ -2836,7 +2895,7 @@ static void drbd_delete_device(unsigned int minor) ERR_IF (!list_empty(&mdev->data.work.q)) { struct list_head *lp; list_for_each(lp, &mdev->data.work.q) { - DUMPP(lp); + dev_err(DEV, "lp = %p\n", lp); } }; /* end paranoia asserts */ @@ -2876,7 +2935,7 @@ static void drbd_delete_device(unsigned int minor) drbd_free_mdev(mdev); } -STATIC void drbd_cleanup(void) +static void drbd_cleanup(void) { unsigned int i; @@ -2958,7 +3017,7 @@ struct drbd_conf *drbd_new_device(unsigned int minor) goto out_no_q; mdev->rq_queue = q; q->queuedata = mdev; - q->max_segment_size = DRBD_MAX_SEGMENT_SIZE; + blk_queue_max_segment_size(q, DRBD_MAX_SEGMENT_SIZE); disk = alloc_disk(1); if (!disk) @@ -2994,7 +3053,7 @@ struct drbd_conf *drbd_new_device(unsigned int minor) if (drbd_bm_init(mdev)) goto out_no_bitmap; - /* no need to lock access, we are still initializing the module. */ + /* no need to lock access, we are still initializing this minor device. */ if (!tl_init(mdev)) goto out_no_tl; @@ -3143,10 +3202,12 @@ void drbd_free_bc(struct drbd_backing_dev *ldev) void drbd_free_sock(struct drbd_conf *mdev) { if (mdev->data.socket) { + kernel_sock_shutdown(mdev->data.socket, SHUT_RDWR); sock_release(mdev->data.socket); mdev->data.socket = NULL; } if (mdev->meta.socket) { + kernel_sock_shutdown(mdev->meta.socket, SHUT_RDWR); sock_release(mdev->meta.socket); mdev->meta.socket = NULL; } @@ -3344,7 +3405,7 @@ void drbd_md_mark_dirty(struct drbd_conf *mdev) } -STATIC void drbd_uuid_move_history(struct drbd_conf *mdev) __must_hold(local) +static void drbd_uuid_move_history(struct drbd_conf *mdev) __must_hold(local) { int i; @@ -3472,7 +3533,7 @@ int drbd_bmio_clear_n_write(struct drbd_conf *mdev) return rv; } -STATIC int w_bitmap_io(struct drbd_conf *mdev, struct drbd_work *w, int unused) +static int w_bitmap_io(struct drbd_conf *mdev, struct drbd_work *w, int unused) { struct bm_io_work *work = (struct bm_io_work *)w; int rv; @@ -3581,14 +3642,14 @@ int drbd_md_test_flag(struct drbd_backing_dev *bdev, int flag) return (bdev->md.flags & flag) != 0; } -STATIC void md_sync_timer_fn(unsigned long data) +static void md_sync_timer_fn(unsigned long data) { struct drbd_conf *mdev = (struct drbd_conf *) data; drbd_queue_work_front(&mdev->data.work, &mdev->md_sync_work); } -STATIC int w_md_sync(struct drbd_conf *mdev, struct drbd_work *w, int unused) +static int w_md_sync(struct drbd_conf *mdev, struct drbd_work *w, int unused) { dev_warn(DEV, "md_sync_timer expired! Worker calls drbd_md_sync().\n"); drbd_md_sync(mdev); @@ -3596,7 +3657,7 @@ STATIC int w_md_sync(struct drbd_conf *mdev, struct drbd_work *w, int unused) return 1; } -#ifdef DRBD_ENABLE_FAULTS +#ifdef CONFIG_DRBD_FAULT_INJECTION /* Fault insertion support including random number generator shamelessly * stolen from kernel/rcutorture.c */ struct fault_random_state { @@ -3612,7 +3673,7 @@ struct fault_random_state { * Crude but fast random-number generator. Uses a linear congruential * generator, with occasional help from get_random_bytes(). */ -STATIC unsigned long +static unsigned long _drbd_fault_random(struct fault_random_state *rsp) { long refresh; @@ -3626,18 +3687,18 @@ _drbd_fault_random(struct fault_random_state *rsp) return swahw32(rsp->state); } -STATIC char * +static char * _drbd_fault_str(unsigned int type) { static char *_faults[] = { - "Meta-data write", - "Meta-data read", - "Resync write", - "Resync read", - "Data write", - "Data read", - "Data read ahead", - "BM allocation", - "EE allocation" + [DRBD_FAULT_MD_WR] = "Meta-data write", + [DRBD_FAULT_MD_RD] = "Meta-data read", + [DRBD_FAULT_RS_WR] = "Resync write", + [DRBD_FAULT_RS_RD] = "Resync read", + [DRBD_FAULT_DT_WR] = "Data write", + [DRBD_FAULT_DT_RD] = "Data read", + [DRBD_FAULT_DT_RA] = "Data read ahead", + [DRBD_FAULT_BM_ALLOC] = "BM allocation", + [DRBD_FAULT_AL_EE] = "EE allocation" }; return (type < DRBD_FAULT_MAX) ? _faults[type] : "**Unknown**"; @@ -3665,5 +3726,22 @@ _drbd_insert_fault(struct drbd_conf *mdev, unsigned int type) } #endif +const char *drbd_buildtag(void) +{ + /* DRBD built from external sources has here a reference to the + git hash of the source code. */ + + static char buildtag[38] = "\0uilt-in"; + + if (buildtag[0] == 0) { + if (THIS_MODULE != NULL) + sprintf(buildtag, "srcversion: %-24s", THIS_MODULE->srcversion); + else + buildtag[0] = 'b'; + } + + return buildtag; +} + module_init(drbd_init) module_exit(drbd_cleanup) diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index c6217d6a2465..c3d438ccd408 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -25,34 +25,40 @@ #include <linux/autoconf.h> #include <linux/module.h> +#include <linux/drbd.h> #include <linux/in.h> #include <linux/fs.h> #include <linux/file.h> #include <linux/slab.h> #include <linux/connector.h> -#include <linux/drbd_config.h> -#include <linux/drbd.h> #include <linux/blkpg.h> #include <linux/cpumask.h> #include "drbd_int.h" #include "drbd_tracing.h" #include "drbd_wrappers.h" +#include <asm/unaligned.h> #include <linux/drbd_tag_magic.h> #include <linux/drbd_limits.h> +static unsigned short *tl_add_blob(unsigned short *, enum drbd_tags, const void *, int); +static unsigned short *tl_add_str(unsigned short *, enum drbd_tags, const char *); +static unsigned short *tl_add_int(unsigned short *, enum drbd_tags, const void *); + /* see get_sb_bdev and bd_claim */ static char *drbd_m_holder = "Hands off! this is DRBD's meta data device."; /* Generate the tag_list to struct functions */ #define NL_PACKET(name, number, fields) \ -STATIC int name ## _from_tags(struct drbd_conf *mdev, \ +static int name ## _from_tags(struct drbd_conf *mdev, \ + unsigned short *tags, struct name *arg) __attribute__ ((unused)); \ +static int name ## _from_tags(struct drbd_conf *mdev, \ unsigned short *tags, struct name *arg) \ { \ int tag; \ int dlen; \ \ - while ((tag = *tags++) != TT_END) { \ - dlen = *tags++; \ + while ((tag = get_unaligned(tags++)) != TT_END) { \ + dlen = get_unaligned(tags++); \ switch (tag_number(tag)) { \ fields \ default: \ @@ -67,16 +73,16 @@ STATIC int name ## _from_tags(struct drbd_conf *mdev, \ } #define NL_INTEGER(pn, pr, member) \ case pn: /* D_ASSERT( tag_type(tag) == TT_INTEGER ); */ \ - arg->member = *(int *)(tags); \ - break; + arg->member = get_unaligned((int *)(tags)); \ + break; #define NL_INT64(pn, pr, member) \ case pn: /* D_ASSERT( tag_type(tag) == TT_INT64 ); */ \ - arg->member = *(u64 *)(tags); \ - break; + arg->member = get_unaligned((u64 *)(tags)); \ + break; #define NL_BIT(pn, pr, member) \ case pn: /* D_ASSERT( tag_type(tag) == TT_BIT ); */ \ - arg->member = *(char *)(tags) ? 1 : 0; \ - break; + arg->member = *(char *)(tags) ? 1 : 0; \ + break; #define NL_STRING(pn, pr, member, len) \ case pn: /* D_ASSERT( tag_type(tag) == TT_STRING ); */ \ if (dlen > len) { \ @@ -91,7 +97,10 @@ STATIC int name ## _from_tags(struct drbd_conf *mdev, \ /* Generate the struct to tag_list functions */ #define NL_PACKET(name, number, fields) \ -STATIC unsigned short* \ +static unsigned short* \ +name ## _to_tags(struct drbd_conf *mdev, \ + struct name *arg, unsigned short *tags) __attribute__ ((unused)); \ +static unsigned short* \ name ## _to_tags(struct drbd_conf *mdev, \ struct name *arg, unsigned short *tags) \ { \ @@ -100,23 +109,23 @@ name ## _to_tags(struct drbd_conf *mdev, \ } #define NL_INTEGER(pn, pr, member) \ - *tags++ = pn | pr | TT_INTEGER; \ - *tags++ = sizeof(int); \ - *(int *)tags = arg->member; \ + put_unaligned(pn | pr | TT_INTEGER, tags++); \ + put_unaligned(sizeof(int), tags++); \ + put_unaligned(arg->member, (int *)tags); \ tags = (unsigned short *)((char *)tags+sizeof(int)); #define NL_INT64(pn, pr, member) \ - *tags++ = pn | pr | TT_INT64; \ - *tags++ = sizeof(u64); \ - *(u64 *)tags = arg->member; \ + put_unaligned(pn | pr | TT_INT64, tags++); \ + put_unaligned(sizeof(u64), tags++); \ + put_unaligned(arg->member, (u64 *)tags); \ tags = (unsigned short *)((char *)tags+sizeof(u64)); #define NL_BIT(pn, pr, member) \ - *tags++ = pn | pr | TT_BIT; \ - *tags++ = sizeof(char); \ + put_unaligned(pn | pr | TT_BIT, tags++); \ + put_unaligned(sizeof(char), tags++); \ *(char *)tags = arg->member; \ tags = (unsigned short *)((char *)tags+sizeof(char)); #define NL_STRING(pn, pr, member, len) \ - *tags++ = pn | pr | TT_STRING; \ - *tags++ = arg->member ## _len; \ + put_unaligned(pn | pr | TT_STRING, tags++); \ + put_unaligned(arg->member ## _len, tags++); \ memcpy(tags, arg->member, arg->member ## _len); \ tags = (unsigned short *)((char *)tags + arg->member ## _len); #include "linux/drbd_nl.h" @@ -126,16 +135,42 @@ void drbd_nl_send_reply(struct cn_msg *, int); int drbd_khelper(struct drbd_conf *mdev, char *cmd) { - char mb[12]; + char *envp[] = { "HOME=/", + "TERM=linux", + "PATH=/sbin:/usr/sbin:/bin:/usr/bin", + NULL, /* Will be set to address family */ + NULL, /* Will be set to address */ + NULL }; + + char mb[12], af[20], ad[60], *afs; char *argv[] = {usermode_helper, cmd, mb, NULL }; int ret; - static char *envp[] = { "HOME=/", - "TERM=linux", - "PATH=/sbin:/usr/sbin:/bin:/usr/bin", - NULL }; snprintf(mb, 12, "minor-%d", mdev_to_minor(mdev)); + if (get_net_conf(mdev)) { + switch (((struct sockaddr *)mdev->net_conf->peer_addr)->sa_family) { + case AF_INET6: + afs = "ipv6"; + snprintf(ad, 60, "DRBD_PEER_ADDRESS=%pI6", + &((struct sockaddr_in6 *)mdev->net_conf->peer_addr)->sin6_addr); + break; + case AF_INET: + afs = "ipv4"; + snprintf(ad, 60, "DRBD_PEER_ADDRESS=%pI4", + &((struct sockaddr_in *)mdev->net_conf->peer_addr)->sin_addr); + break; + default: + afs = "ssocks"; + snprintf(ad, 60, "DRBD_PEER_ADDRESS=%pI4", + &((struct sockaddr_in *)mdev->net_conf->peer_addr)->sin_addr); + } + snprintf(af, 20, "DRBD_PEER_AF=%s", afs); + envp[3]=af; + envp[4]=ad; + put_net_conf(mdev); + } + dev_info(DEV, "helper command: %s %s %s\n", usermode_helper, cmd, mb); drbd_bcast_ev_helper(mdev, cmd); @@ -354,7 +389,7 @@ int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) } -STATIC int drbd_nl_primary(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, +static int drbd_nl_primary(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { struct primary primary_args; @@ -371,7 +406,7 @@ STATIC int drbd_nl_primary(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, return 0; } -STATIC int drbd_nl_secondary(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, +static int drbd_nl_secondary(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { reply->ret_code = drbd_set_role(mdev, R_SECONDARY, 0); @@ -381,7 +416,7 @@ STATIC int drbd_nl_secondary(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp /* initializes the md.*_offset members, so we are able to find * the on disk meta data */ -STATIC void drbd_md_set_sector_offsets(struct drbd_conf *mdev, +static void drbd_md_set_sector_offsets(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) { sector_t md_size_sect = 0; @@ -533,15 +568,12 @@ enum determine_dev_size drbd_determin_dev_size(struct drbd_conf *mdev) __must_ho md_moved = prev_first_sect != drbd_md_first_sector(mdev->ldev) || prev_size != mdev->ldev->md.md_size_sect; - if (md_moved) { - dev_warn(DEV, "Moving meta-data.\n"); - /* assert: (flexible) internal meta data */ - } - if (la_size_changed || md_moved) { drbd_al_shrink(mdev); /* All extents inactive. */ - dev_info(DEV, "Writing the whole bitmap, size changed\n"); - rv = drbd_bitmap_io(mdev, &drbd_bm_write, "size changed"); + dev_info(DEV, "Writing the whole bitmap, %s\n", + la_size_changed && md_moved ? "size changed and md moved" : + la_size_changed ? "size changed" : "md moved"); + rv = drbd_bitmap_io(mdev, &drbd_bm_write, "size changed"); /* does drbd_resume_io() ! */ drbd_md_mark_dirty(mdev); } @@ -607,7 +639,7 @@ drbd_new_dev_size(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) * failed, and 0 on success. You should call drbd_md_sync() after you called * this function. */ -STATIC int drbd_check_al_size(struct drbd_conf *mdev) +static int drbd_check_al_size(struct drbd_conf *mdev) { struct lru_cache *n, *t; struct lc_element *e; @@ -623,8 +655,8 @@ STATIC int drbd_check_al_size(struct drbd_conf *mdev) in_use = 0; t = mdev->act_log; - n = lc_create("act_log", mdev->sync_conf.al_extents, - sizeof(struct lc_element), 0); + n = lc_create("act_log", drbd_al_ext_cache, + mdev->sync_conf.al_extents, sizeof(struct lc_element), 0); if (n == NULL) { dev_err(DEV, "Cannot allocate act_log lru!\n"); @@ -659,31 +691,25 @@ void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int max_seg_s) __mu { struct request_queue * const q = mdev->rq_queue; struct request_queue * const b = mdev->ldev->backing_bdev->bd_disk->queue; - /* unsigned int old_max_seg_s = q->max_segment_size; */ int max_segments = mdev->ldev->dc.max_bio_bvecs; if (b->merge_bvec_fn && !mdev->ldev->dc.use_bmbv) max_seg_s = PAGE_SIZE; - max_seg_s = min(b->max_sectors * b->hardsect_size, max_seg_s); + max_seg_s = min(queue_max_sectors(b) * queue_logical_block_size(b), max_seg_s); - q->max_sectors = max_seg_s >> 9; - if (max_segments) { - q->max_phys_segments = max_segments; - q->max_hw_segments = max_segments; - } else { - q->max_phys_segments = MAX_PHYS_SEGMENTS; - q->max_hw_segments = MAX_HW_SEGMENTS; - } - q->max_segment_size = max_seg_s; - q->hardsect_size = 512; - q->seg_boundary_mask = PAGE_SIZE-1; + blk_queue_max_sectors(q, max_seg_s >> 9); + blk_queue_max_phys_segments(q, max_segments ? max_segments : MAX_PHYS_SEGMENTS); + blk_queue_max_hw_segments(q, max_segments ? max_segments : MAX_HW_SEGMENTS); + blk_queue_max_segment_size(q, max_seg_s); + blk_queue_logical_block_size(q, 512); + blk_queue_segment_boundary(q, PAGE_SIZE-1); blk_queue_stack_limits(q, b); if (b->merge_bvec_fn) dev_warn(DEV, "Backing device's merge_bvec_fn() = %p\n", b->merge_bvec_fn); - dev_info(DEV, "max_segment_size ( = BIO size ) = %u\n", q->max_segment_size); + dev_info(DEV, "max_segment_size ( = BIO size ) = %u\n", queue_max_segment_size(q)); if (q->backing_dev_info.ra_pages != b->backing_dev_info.ra_pages) { dev_info(DEV, "Adjusting my ra_pages to backing device's (%lu -> %lu)\n", @@ -725,7 +751,7 @@ static void drbd_reconfig_done(struct drbd_conf *mdev) /* does always return 0; * interesting return code is in reply->ret_code */ -STATIC int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, +static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { enum drbd_ret_codes retcode; @@ -738,7 +764,7 @@ STATIC int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp union drbd_state ns, os; int rv; int cp_discovered = 0; - int hardsect_size; + int logical_block_size; drbd_reconfig_start(mdev); @@ -748,14 +774,13 @@ STATIC int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp goto fail; } - nbc = kmalloc(sizeof(struct drbd_backing_dev), GFP_KERNEL); + /* allocation not in the IO path, cqueue thread context */ + nbc = kzalloc(sizeof(struct drbd_backing_dev), GFP_KERNEL); if (!nbc) { retcode = ERR_NOMEM; goto fail; } - memset(&nbc->md, 0, sizeof(struct drbd_md)); - memset(&nbc->dc, 0, sizeof(struct disk_conf)); nbc->dc.disk_size = DRBD_DISK_SIZE_SECT_DEF; nbc->dc.on_io_error = DRBD_ON_IO_ERROR_DEF; nbc->dc.fencing = DRBD_FENCING_DEF; @@ -766,9 +791,6 @@ STATIC int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp goto fail; } - nbc->lo_file = NULL; - nbc->md_file = NULL; - if (nbc->dc.meta_dev_idx < DRBD_MD_INDEX_FLEX_INT) { retcode = ERR_MD_IDX_INVALID; goto fail; @@ -817,18 +839,24 @@ STATIC int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp goto fail; } - resync_lru = lc_create("resync", 61, sizeof(struct bm_extent), + resync_lru = lc_create("resync", drbd_bm_ext_cache, + 61, sizeof(struct bm_extent), offsetof(struct bm_extent, lce)); if (!resync_lru) { retcode = ERR_NOMEM; goto release_bdev_fail; } + /* meta_dev_idx >= 0: external fixed size, + * possibly multiple drbd sharing one meta device. + * TODO in that case, paranoia check that [md_bdev, meta_dev_idx] is + * not yet used by some other drbd minor! + * (if you use drbd.conf + drbdadm, + * that should check it for you already; but if you don't, or someone + * fooled it, we need to double check here) */ nbc->md_bdev = inode2->i_bdev; - if (bd_claim(nbc->md_bdev, - (nbc->dc.meta_dev_idx == DRBD_MD_INDEX_INTERNAL || - nbc->dc.meta_dev_idx == DRBD_MD_INDEX_FLEX_INT) ? - (void *)mdev : (void *) drbd_m_holder)) { + if (bd_claim(nbc->md_bdev, (nbc->dc.meta_dev_idx < 0) ? (void *)mdev + : (void *) drbd_m_holder)) { retcode = ERR_BDCLAIM_MD_DISK; goto release_bdev_fail; } @@ -936,19 +964,19 @@ STATIC int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp goto force_diskless_dec; } - /* allocate a second IO page if hardsect_size != 512 */ - hardsect_size = drbd_get_hardsect_size(nbc->md_bdev); - if (hardsect_size == 0) - hardsect_size = MD_SECTOR_SIZE; + /* allocate a second IO page if logical_block_size != 512 */ + logical_block_size = bdev_logical_block_size(nbc->md_bdev); + if (logical_block_size == 0) + logical_block_size = MD_SECTOR_SIZE; - if (hardsect_size != MD_SECTOR_SIZE) { + if (logical_block_size != MD_SECTOR_SIZE) { if (!mdev->md_io_tmpp) { struct page *page = alloc_page(GFP_NOIO); if (!page) goto force_diskless_dec; - dev_warn(DEV, "Meta data's bdev hardsect_size = %d != %d\n", - hardsect_size, MD_SECTOR_SIZE); + dev_warn(DEV, "Meta data's bdev logical_block_size = %d != %d\n", + logical_block_size, MD_SECTOR_SIZE); dev_warn(DEV, "Workaround engaged (has performace impact).\n"); mdev->md_io_tmpp = page; @@ -1122,14 +1150,14 @@ STATIC int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp return 0; } -STATIC int drbd_nl_detach(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, +static int drbd_nl_detach(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { reply->ret_code = drbd_request_state(mdev, NS(disk, D_DISKLESS)); return 0; } -STATIC int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, +static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { int i, ns; @@ -1154,6 +1182,7 @@ STATIC int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, goto fail; } + /* allocation not in the IO path, cqueue thread context */ new_conf = kmalloc(sizeof(struct net_conf), GFP_KERNEL); if (!new_conf) { retcode = ERR_NOMEM; @@ -1168,6 +1197,7 @@ STATIC int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, new_conf->max_buffers = DRBD_MAX_BUFFERS_DEF; new_conf->unplug_watermark = DRBD_UNPLUG_WATERMARK_DEF; new_conf->sndbuf_size = DRBD_SNDBUF_SIZE_DEF; + new_conf->rcvbuf_size = DRBD_RCVBUF_SIZE_DEF; new_conf->ko_count = DRBD_KO_COUNT_DEF; new_conf->after_sb_0p = DRBD_AFTER_SB_0P_DEF; new_conf->after_sb_1p = DRBD_AFTER_SB_1P_DEF; @@ -1184,7 +1214,7 @@ STATIC int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, } if (new_conf->two_primaries - && (new_conf->wire_protocol != DRBD_PROT_C)) { + && (new_conf->wire_protocol != DRBD_PROT_C)) { retcode = ERR_NOT_PROTO_C; goto fail; }; @@ -1366,7 +1396,7 @@ fail: return 0; } -STATIC int drbd_nl_disconnect(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, +static int drbd_nl_disconnect(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { int retcode; @@ -1427,7 +1457,7 @@ void resync_after_online_grow(struct drbd_conf *mdev) _drbd_request_state(mdev, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE + CS_SERIALIZE); } -STATIC int drbd_nl_resize(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, +static int drbd_nl_resize(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { struct resize rs; @@ -1472,10 +1502,11 @@ STATIC int drbd_nl_resize(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, } if (mdev->state.conn == C_CONNECTED && (dd != unchanged || ldsc)) { - drbd_send_uuids(mdev); - drbd_send_sizes(mdev); if (dd == grew) - resync_after_online_grow(mdev); + set_bit(RESIZE_PENDING, &mdev->flags); + + drbd_send_uuids(mdev); + drbd_send_sizes(mdev, 1); } fail: @@ -1483,14 +1514,13 @@ STATIC int drbd_nl_resize(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, return 0; } -STATIC int drbd_nl_syncer_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, +static int drbd_nl_syncer_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { int retcode = NO_ERROR; int err; int ovr; /* online verify running */ int rsr; /* re-sync running */ - struct drbd_conf *odev; struct crypto_hash *verify_tfm = NULL; struct crypto_hash *csums_tfm = NULL; struct syncer_conf sc; @@ -1510,23 +1540,6 @@ STATIC int drbd_nl_syncer_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *n goto fail; } - if (sc.after != -1) { - if (sc.after < -1 || minor_to_mdev(sc.after) == NULL) { - retcode = ERR_SYNC_AFTER; - goto fail; - } - odev = minor_to_mdev(sc.after); /* check against loops in */ - while (1) { - if (odev == mdev) { - retcode = ERR_SYNC_AFTER_CYCLE; - goto fail; - } - if (odev->sync_conf.after == -1) - break; /* no cycles. */ - odev = minor_to_mdev(odev->sync_conf.after); - } - } - /* re-sync running */ rsr = ( mdev->state.conn == C_SYNC_SOURCE || mdev->state.conn == C_SYNC_TARGET || @@ -1576,7 +1589,8 @@ STATIC int drbd_nl_syncer_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *n } } - if (sc.cpu_mask[0] != 0) { + /* silently ignore cpu mask on UP kernel */ + if (NR_CPUS > 1 && sc.cpu_mask[0] != 0) { err = __bitmap_parse(sc.cpu_mask, 32, 0, (unsigned long *)&n_cpu_mask, NR_CPUS); if (err) { dev_warn(DEV, "__bitmap_parse() failed with %d\n", err); @@ -1594,8 +1608,16 @@ STATIC int drbd_nl_syncer_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *n } #undef AL_MAX + /* most sanity checks done, try to assign the new sync-after + * dependency. need to hold the global lock in there, + * to avoid a race in the dependency loop check. */ + retcode = drbd_alter_sa(mdev, sc.after); + if (retcode != NO_ERROR) + goto fail; + + /* ok, assign the rest of it as well. + * lock against receive_SyncParam() */ spin_lock(&mdev->peer_seq_lock); - /* lock against receive_SyncParam() */ mdev->sync_conf = sc; if (!rsr) { @@ -1630,8 +1652,6 @@ STATIC int drbd_nl_syncer_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *n if (mdev->state.conn >= C_CONNECTED) drbd_send_sync_param(mdev, &sc); - drbd_alter_sa(mdev, sc.after); - if (!cpus_equal(mdev->cpu_mask, n_cpu_mask)) { mdev->cpu_mask = n_cpu_mask; mdev->cpu_mask = drbd_calc_cpu_mask(mdev); @@ -1648,7 +1668,7 @@ fail: return 0; } -STATIC int drbd_nl_invalidate(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, +static int drbd_nl_invalidate(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { int retcode; @@ -1674,7 +1694,7 @@ STATIC int drbd_nl_invalidate(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl return 0; } -STATIC int drbd_nl_invalidate_peer(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, +static int drbd_nl_invalidate_peer(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { @@ -1683,7 +1703,7 @@ STATIC int drbd_nl_invalidate_peer(struct drbd_conf *mdev, struct drbd_nl_cfg_re return 0; } -STATIC int drbd_nl_pause_sync(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, +static int drbd_nl_pause_sync(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { int retcode = NO_ERROR; @@ -1695,7 +1715,7 @@ STATIC int drbd_nl_pause_sync(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl return 0; } -STATIC int drbd_nl_resume_sync(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, +static int drbd_nl_resume_sync(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { int retcode = NO_ERROR; @@ -1707,7 +1727,7 @@ STATIC int drbd_nl_resume_sync(struct drbd_conf *mdev, struct drbd_nl_cfg_req *n return 0; } -STATIC int drbd_nl_suspend_io(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, +static int drbd_nl_suspend_io(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { reply->ret_code = drbd_request_state(mdev, NS(susp, 1)); @@ -1715,21 +1735,21 @@ STATIC int drbd_nl_suspend_io(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl return 0; } -STATIC int drbd_nl_resume_io(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, +static int drbd_nl_resume_io(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { reply->ret_code = drbd_request_state(mdev, NS(susp, 0)); return 0; } -STATIC int drbd_nl_outdate(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, +static int drbd_nl_outdate(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { reply->ret_code = drbd_request_state(mdev, NS(disk, D_OUTDATED)); return 0; } -STATIC int drbd_nl_get_config(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, +static int drbd_nl_get_config(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { unsigned short *tl; @@ -1747,12 +1767,12 @@ STATIC int drbd_nl_get_config(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl } tl = syncer_conf_to_tags(mdev, &mdev->sync_conf, tl); - *tl++ = TT_END; /* Close the tag list */ + put_unaligned(TT_END, tl++); /* Close the tag list */ return (int)((char *)tl - (char *)reply->tag_list); } -STATIC int drbd_nl_get_state(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, +static int drbd_nl_get_state(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { unsigned short *tl = reply->tag_list; @@ -1766,19 +1786,16 @@ STATIC int drbd_nl_get_state(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp if (s.conn >= C_SYNC_SOURCE && s.conn <= C_PAUSED_SYNC_T) { if (get_ldev(mdev)) { drbd_get_syncer_progress(mdev, &rs_left, &res); - *tl++ = T_sync_progress; - *tl++ = sizeof(int); - memcpy(tl, &res, sizeof(int)); - tl = (unsigned short *)((char *)tl + sizeof(int)); + tl = tl_add_int(tl, T_sync_progress, &res); put_ldev(mdev); } } - *tl++ = TT_END; /* Close the tag list */ + put_unaligned(TT_END, tl++); /* Close the tag list */ return (int)((char *)tl - (char *)reply->tag_list); } -STATIC int drbd_nl_get_uuids(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, +static int drbd_nl_get_uuids(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { unsigned short *tl; @@ -1786,18 +1803,11 @@ STATIC int drbd_nl_get_uuids(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp tl = reply->tag_list; if (get_ldev(mdev)) { - /* This is a hand crafted add tag ;) */ - *tl++ = T_uuids; - *tl++ = UI_SIZE*sizeof(u64); - memcpy(tl, mdev->ldev->md.uuid, UI_SIZE*sizeof(u64)); - tl = (unsigned short *)((char *)tl + UI_SIZE*sizeof(u64)); - *tl++ = T_uuids_flags; - *tl++ = sizeof(int); - memcpy(tl, &mdev->ldev->md.flags, sizeof(int)); - tl = (unsigned short *)((char *)tl + sizeof(int)); + tl = tl_add_blob(tl, T_uuids, mdev->ldev->md.uuid, UI_SIZE*sizeof(u64)); + tl = tl_add_int(tl, T_uuids_flags, &mdev->ldev->md.flags); put_ldev(mdev); } - *tl++ = TT_END; /* Close the tag list */ + put_unaligned(TT_END, tl++); /* Close the tag list */ return (int)((char *)tl - (char *)reply->tag_list); } @@ -1808,7 +1818,7 @@ STATIC int drbd_nl_get_uuids(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp * @nlp: Netlink/connector packet from drbdsetup * @reply: Reply packet for drbdsetup */ -STATIC int drbd_nl_get_timeout_flag(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, +static int drbd_nl_get_timeout_flag(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { unsigned short *tl; @@ -1819,26 +1829,31 @@ STATIC int drbd_nl_get_timeout_flag(struct drbd_conf *mdev, struct drbd_nl_cfg_r rv = mdev->state.pdsk == D_OUTDATED ? UT_PEER_OUTDATED : test_bit(USE_DEGR_WFC_T, &mdev->flags) ? UT_DEGRADED : UT_DEFAULT; - /* This is a hand crafted add tag ;) */ - *tl++ = T_use_degraded; - *tl++ = sizeof(char); - *((char *)tl) = rv; - tl = (unsigned short *)((char *)tl + sizeof(char)); - *tl++ = TT_END; + tl = tl_add_blob(tl, T_use_degraded, &rv, sizeof(rv)); + put_unaligned(TT_END, tl++); /* Close the tag list */ return (int)((char *)tl - (char *)reply->tag_list); } -STATIC int drbd_nl_start_ov(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, +static int drbd_nl_start_ov(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { - reply->ret_code = drbd_request_state(mdev,NS(conn,C_VERIFY_S)); + /* default to resume from last known position, if possible */ + struct start_ov args = + { .start_sector = mdev->ov_start_sector }; + if (!start_ov_from_tags(mdev, nlp->tag_list, &args)) { + reply->ret_code = ERR_MANDATORY_TAG; + return 0; + } + /* w_make_ov_request expects position to be aligned */ + mdev->ov_start_sector = args.start_sector & ~BM_SECT_PER_BIT; + reply->ret_code = drbd_request_state(mdev,NS(conn,C_VERIFY_S)); return 0; } -STATIC int drbd_nl_new_c_uuid(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, +static int drbd_nl_new_c_uuid(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { int retcode = NO_ERROR; @@ -1865,7 +1880,7 @@ STATIC int drbd_nl_new_c_uuid(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl mdev->ldev->md.uuid[UI_CURRENT] == UUID_JUST_CREATED && args.clear_bm) { dev_info(DEV, "Preparing to skip initial sync\n"); skip_initial_sync = 1; - } else if (mdev->state.conn >= C_CONNECTED) { + } else if (mdev->state.conn != C_STANDALONE) { retcode = ERR_CONNECTED; goto out_dec; } @@ -1899,7 +1914,7 @@ out: return 0; } -STATIC struct drbd_conf *ensure_mdev(struct drbd_nl_cfg_req *nlp) +static struct drbd_conf *ensure_mdev(struct drbd_nl_cfg_req *nlp) { struct drbd_conf *mdev; @@ -1971,7 +1986,7 @@ static struct cn_handler_struct cnd_table[] = { [ P_new_c_uuid ] = { &drbd_nl_new_c_uuid, 0 }, }; -STATIC void drbd_connector_callback(void *data) +static void drbd_connector_callback(void *data) { struct cn_msg *req = data; struct drbd_nl_cfg_req *nlp = (struct drbd_nl_cfg_req *)req->data; @@ -2012,6 +2027,7 @@ STATIC void drbd_connector_callback(void *data) reply_size += cm->reply_body_size; + /* allocation not in the IO path, cqueue thread context */ cn_reply = kmalloc(reply_size, GFP_KERNEL); if (!cn_reply) { retcode = ERR_NOMEM; @@ -2050,18 +2066,13 @@ static atomic_t drbd_nl_seq = ATOMIC_INIT(2); /* two. */ static unsigned short * __tl_add_blob(unsigned short *tl, enum drbd_tags tag, const void *data, - int len, int nul_terminated) + unsigned short len, int nul_terminated) { - int l = tag_descriptions[tag_number(tag)].max_len; - l = (len < l) ? len : l; - *tl++ = tag; - *tl++ = len; + unsigned short l = tag_descriptions[tag_number(tag)].max_len; + len = (len < l) ? len : l; + put_unaligned(tag, tl++); + put_unaligned(len, tl++); memcpy(tl, data, len); - /* TODO - * maybe we need to add some padding to the data stream. - * otherwise we may get strange effects on architectures - * that require certain data types to be strictly aligned, - * because now the next "unsigned short" may be misaligned. */ tl = (unsigned short*)((char*)tl + len); if (nul_terminated) *((char*)tl - 1) = 0; @@ -2083,17 +2094,16 @@ tl_add_str(unsigned short *tl, enum drbd_tags tag, const char *str) static unsigned short * tl_add_int(unsigned short *tl, enum drbd_tags tag, const void *val) { + put_unaligned(tag, tl++); switch(tag_type(tag)) { case TT_INTEGER: - *tl++ = tag; - *tl++ = sizeof(int); - *(int*)tl = *(int*)val; + put_unaligned(sizeof(int), tl++); + put_unaligned(*(int *)val, (int *)tl++); tl = (unsigned short*)((char*)tl+sizeof(int)); break; case TT_INT64: - *tl++ = tag; - *tl++ = sizeof(u64); - *(u64*)tl = *(u64*)val; + put_unaligned(sizeof(u64), tl++); + put_unaligned(*(u64 *)val, (u64 *)tl++); tl = (unsigned short*)((char*)tl+sizeof(u64)); break; default: @@ -2117,7 +2127,8 @@ void drbd_bcast_state(struct drbd_conf *mdev, union drbd_state state) /* dev_warn(DEV, "drbd_bcast_state() got called\n"); */ tl = get_state_to_tags(mdev, (struct get_state *)&state, tl); - *tl++ = TT_END; /* Close the tag list */ + + put_unaligned(TT_END, tl++); /* Close the tag list */ cn_reply->id.idx = CN_IDX_DRBD; cn_reply->id.val = CN_VAL_DRBD; @@ -2146,16 +2157,11 @@ void drbd_bcast_ev_helper(struct drbd_conf *mdev, char *helper_name) struct drbd_nl_cfg_reply *reply = (struct drbd_nl_cfg_reply *)cn_reply->data; unsigned short *tl = reply->tag_list; - int str_len; /* dev_warn(DEV, "drbd_bcast_state() got called\n"); */ - str_len = strlen(helper_name)+1; - *tl++ = T_helper; - *tl++ = str_len; - memcpy(tl, helper_name, str_len); - tl = (unsigned short *)((char *)tl + str_len); - *tl++ = TT_END; /* Close the tag list */ + tl = tl_add_str(tl, T_helper, helper_name); + put_unaligned(TT_END, tl++); /* Close the tag list */ cn_reply->id.idx = CN_IDX_DRBD; cn_reply->id.val = CN_VAL_DRBD; @@ -2193,12 +2199,15 @@ void drbd_bcast_ee(struct drbd_conf *mdev, /* aparently we have to memcpy twice, first to prepare the data for the * struct cn_msg, then within cn_netlink_send from the cn_msg to the * netlink skb. */ + /* receiver thread context, which is not in the writeout path (of this node), + * but may be in the writeout path of the _other_ node. + * GFP_NOIO to avoid potential "distributed deadlock". */ cn_reply = kmalloc( sizeof(struct cn_msg)+ sizeof(struct drbd_nl_cfg_reply)+ sizeof(struct dump_ee_tag_len_struct)+ - sizeof(short int) - , GFP_KERNEL); + sizeof(short int), + GFP_NOIO); if (!cn_reply) { dev_err(DEV, "could not kmalloc buffer for drbd_bcast_ee, sector %llu, size %u\n", @@ -2215,8 +2224,8 @@ void drbd_bcast_ee(struct drbd_conf *mdev, tl = tl_add_int(tl, T_ee_sector, &e->sector); tl = tl_add_int(tl, T_ee_block_id, &e->block_id); - *tl++ = T_ee_data; - *tl++ = e->size; + put_unaligned(T_ee_data, tl++); + put_unaligned(e->size, tl++); __bio_for_each_segment(bvec, e->private_bio, i, 0) { void *d = kmap(bvec->bv_page); @@ -2224,7 +2233,7 @@ void drbd_bcast_ee(struct drbd_conf *mdev, kunmap(bvec->bv_page); tl=(unsigned short*)((char*)tl + bvec->bv_len); } - *tl++ = TT_END; /* Close the tag list */ + put_unaligned(TT_END, tl++); /* Close the tag list */ cn_reply->id.idx = CN_IDX_DRBD; cn_reply->id.val = CN_VAL_DRBD; @@ -2263,11 +2272,8 @@ void drbd_bcast_sync_progress(struct drbd_conf *mdev) drbd_get_syncer_progress(mdev, &rs_left, &res); put_ldev(mdev); - *tl++ = T_sync_progress; - *tl++ = sizeof(int); - memcpy(tl, &res, sizeof(int)); - tl = (unsigned short *)((char *)tl + sizeof(int)); - *tl++ = TT_END; /* Close the tag list */ + tl = tl_add_int(tl, T_sync_progress, &res); + put_unaligned(TT_END, tl++); /* Close the tag list */ cn_reply->id.idx = CN_IDX_DRBD; cn_reply->id.val = CN_VAL_DRBD; diff --git a/drivers/block/drbd/drbd_proc.c b/drivers/block/drbd/drbd_proc.c index b59b9d9f078c..432a7dd39f7c 100644 --- a/drivers/block/drbd/drbd_proc.c +++ b/drivers/block/drbd/drbd_proc.c @@ -32,11 +32,10 @@ #include <linux/slab.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> -#include <linux/drbd_config.h> #include <linux/drbd.h> #include "drbd_int.h" -STATIC int drbd_proc_open(struct inode *inode, struct file *file); +static int drbd_proc_open(struct inode *inode, struct file *file); struct proc_dir_entry *drbd_proc; @@ -55,7 +54,7 @@ struct file_operations drbd_proc_fops = { * [=====>..............] 33.5% (23456/123456) * finish: 2:20:20 speed: 6,345 (6,456) K/sec */ -STATIC void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq) +static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq) { unsigned long db, dt, dbdt, rt, rs_left; unsigned int res; @@ -134,7 +133,7 @@ STATIC void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq) seq_printf(seq, " K/sec\n"); } -STATIC void resync_dump_detail(struct seq_file *seq, struct lc_element *e) +static void resync_dump_detail(struct seq_file *seq, struct lc_element *e) { struct bm_extent *bme = lc_entry(e, struct bm_extent, lce); @@ -144,7 +143,7 @@ STATIC void resync_dump_detail(struct seq_file *seq, struct lc_element *e) ); } -STATIC int drbd_seq_show(struct seq_file *seq, void *v) +static int drbd_seq_show(struct seq_file *seq, void *v) { int i, hole = 0; const char *sn; @@ -259,7 +258,7 @@ STATIC int drbd_seq_show(struct seq_file *seq, void *v) return 0; } -STATIC int drbd_proc_open(struct inode *inode, struct file *file) +static int drbd_proc_open(struct inode *inode, struct file *file) { return single_open(file, drbd_seq_show, PDE(inode)->data); } diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 24dc84698de7..b222b24ddc51 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -30,11 +30,11 @@ #include <net/sock.h> #include <linux/version.h> +#include <linux/drbd.h> #include <linux/fs.h> #include <linux/file.h> #include <linux/in.h> #include <linux/mm.h> -#include <linux/drbd_config.h> #include <linux/memcontrol.h> #include <linux/mm_inline.h> #include <linux/slab.h> @@ -47,7 +47,6 @@ #include <linux/mm.h> #include <linux/string.h> #include <linux/scatterlist.h> -#include <linux/drbd.h> #include "drbd_int.h" #include "drbd_tracing.h" #include "drbd_req.h" @@ -65,11 +64,11 @@ enum finish_epoch { FE_RECYCLED, }; -STATIC int drbd_do_handshake(struct drbd_conf *mdev); -STATIC int drbd_do_auth(struct drbd_conf *mdev); +static int drbd_do_handshake(struct drbd_conf *mdev); +static int drbd_do_auth(struct drbd_conf *mdev); -STATIC enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *, struct drbd_epoch *, enum epoch_event); -STATIC int e_end_block(struct drbd_conf *, struct drbd_work *, int); +static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *, struct drbd_epoch *, enum epoch_event); +static int e_end_block(struct drbd_conf *, struct drbd_work *, int); static struct drbd_epoch *previous_epoch(struct drbd_conf *mdev, struct drbd_epoch *epoch) { @@ -93,7 +92,7 @@ static struct drbd_epoch *previous_epoch(struct drbd_conf *mdev, struct drbd_epo * allocation would go beyond the max_buffers setting, this function sleeps * until DRBD frees a page somewhere else. */ -STATIC struct page *drbd_pp_alloc(struct drbd_conf *mdev, gfp_t gfp_mask) +static struct page *drbd_pp_alloc(struct drbd_conf *mdev, gfp_t gfp_mask) { unsigned long flags = 0; struct page *page; @@ -162,7 +161,7 @@ STATIC struct page *drbd_pp_alloc(struct drbd_conf *mdev, gfp_t gfp_mask) return page; } -STATIC void drbd_pp_free(struct drbd_conf *mdev, struct page *page) +static void drbd_pp_free(struct drbd_conf *mdev, struct page *page) { unsigned long flags = 0; int free_it; @@ -260,10 +259,10 @@ struct drbd_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev, } /* dump more of the bio. */ - DUMPI(bio->bi_max_vecs); - DUMPI(bio->bi_vcnt); - DUMPI(bio->bi_size); - DUMPI(bio->bi_phys_segments); + dev_err(DEV, "bio->bi_max_vecs = %d\n", bio->bi_max_vecs); + dev_err(DEV, "bio->bi_vcnt = %d\n", bio->bi_vcnt); + dev_err(DEV, "bio->bi_size = %d\n", bio->bi_size); + dev_err(DEV, "bio->bi_phys_segments = %d\n", bio->bi_phys_segments); goto fail2; break; @@ -339,7 +338,7 @@ int drbd_release_ee(struct drbd_conf *mdev, struct list_head *list) } -STATIC void reclaim_net_ee(struct drbd_conf *mdev) +static void reclaim_net_ee(struct drbd_conf *mdev) { struct drbd_epoch_entry *e; struct list_head *le, *tle; @@ -368,7 +367,7 @@ STATIC void reclaim_net_ee(struct drbd_conf *mdev) * Grab done_ee, call all callbacks, free the entries. * The callbacks typically send out ACKs. */ -STATIC int drbd_process_done_ee(struct drbd_conf *mdev) +static int drbd_process_done_ee(struct drbd_conf *mdev) { LIST_HEAD(work_list); struct drbd_epoch_entry *e, *t; @@ -458,7 +457,7 @@ void drbd_wait_ee_list_empty(struct drbd_conf *mdev, struct list_head *head) /* see also kernel_accept; which is only present since 2.6.18. * also we want to log which part of it failed, exactly */ -STATIC int drbd_accept(struct drbd_conf *mdev, const char **what, +static int drbd_accept(struct drbd_conf *mdev, const char **what, struct socket *sock, struct socket **newsock) { struct sock *sk = sock->sk; @@ -488,7 +487,7 @@ out: return err; } -STATIC int drbd_recv_short(struct drbd_conf *mdev, struct socket *sock, +static int drbd_recv_short(struct drbd_conf *mdev, struct socket *sock, void *buf, size_t size, int flags) { mm_segment_t oldfs; @@ -511,7 +510,7 @@ STATIC int drbd_recv_short(struct drbd_conf *mdev, struct socket *sock, return rv; } -STATIC int drbd_recv(struct drbd_conf *mdev, void *buf, size_t size) +static int drbd_recv(struct drbd_conf *mdev, void *buf, size_t size) { mm_segment_t oldfs; struct kvec iov = { @@ -564,7 +563,7 @@ STATIC int drbd_recv(struct drbd_conf *mdev, void *buf, size_t size) return rv; } -STATIC struct socket *drbd_try_connect(struct drbd_conf *mdev) +static struct socket *drbd_try_connect(struct drbd_conf *mdev) { const char *what; struct socket *sock; @@ -640,7 +639,7 @@ out: return sock; } -STATIC struct socket *drbd_wait_for_connect(struct drbd_conf *mdev) +static struct socket *drbd_wait_for_connect(struct drbd_conf *mdev) { int timeo, err; struct socket *s_estab = NULL, *s_listen; @@ -687,7 +686,7 @@ out: return s_estab; } -STATIC int drbd_send_fp(struct drbd_conf *mdev, +static int drbd_send_fp(struct drbd_conf *mdev, struct socket *sock, enum drbd_packets cmd) { struct p_header *h = (struct p_header *) &mdev->data.sbuf.header; @@ -695,7 +694,7 @@ STATIC int drbd_send_fp(struct drbd_conf *mdev, return _drbd_send_cmd(mdev, sock, cmd, h, sizeof(*h), 0); } -STATIC enum drbd_packets drbd_recv_fp(struct drbd_conf *mdev, struct socket *sock) +static enum drbd_packets drbd_recv_fp(struct drbd_conf *mdev, struct socket *sock) { struct p_header *h = (struct p_header *) &mdev->data.sbuf.header; int rr; @@ -740,7 +739,7 @@ static int drbd_socket_okay(struct drbd_conf *mdev, struct socket **sock) * no point in trying again, please go standalone. * -2 We do not have a network config... */ -STATIC int drbd_connect(struct drbd_conf *mdev) +static int drbd_connect(struct drbd_conf *mdev) { struct socket *s, *sock, *msock; int try, h, ok; @@ -856,8 +855,12 @@ retry: if (mdev->net_conf->sndbuf_size) { sock->sk->sk_sndbuf = mdev->net_conf->sndbuf_size; - sock->sk->sk_rcvbuf = mdev->net_conf->sndbuf_size; - sock->sk->sk_userlocks |= SOCK_SNDBUF_LOCK | SOCK_RCVBUF_LOCK; + sock->sk->sk_userlocks |= SOCK_SNDBUF_LOCK; + } + + if (mdev->net_conf->rcvbuf_size) { + sock->sk->sk_rcvbuf = mdev->net_conf->rcvbuf_size; + sock->sk->sk_userlocks |= SOCK_RCVBUF_LOCK; } /* NOT YET ... @@ -906,15 +909,16 @@ retry: drbd_send_protocol(mdev); drbd_send_sync_param(mdev, &mdev->sync_conf); - drbd_send_sizes(mdev); + drbd_send_sizes(mdev, 0); drbd_send_uuids(mdev); drbd_send_state(mdev); clear_bit(USE_DEGR_WFC_T, &mdev->flags); + clear_bit(RESIZE_PENDING, &mdev->flags); return 1; } -STATIC int drbd_recv_header(struct drbd_conf *mdev, struct p_header *h) +static int drbd_recv_header(struct drbd_conf *mdev, struct p_header *h) { int r; @@ -937,7 +941,7 @@ STATIC int drbd_recv_header(struct drbd_conf *mdev, struct p_header *h) return TRUE; } -STATIC enum finish_epoch drbd_flush_after_epoch(struct drbd_conf *mdev, struct drbd_epoch *epoch) +static enum finish_epoch drbd_flush_after_epoch(struct drbd_conf *mdev, struct drbd_epoch *epoch) { int rv; @@ -956,7 +960,7 @@ STATIC enum finish_epoch drbd_flush_after_epoch(struct drbd_conf *mdev, struct d return drbd_may_finish_epoch(mdev, epoch, EV_BARRIER_DONE); } -STATIC int w_flush(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +static int w_flush(struct drbd_conf *mdev, struct drbd_work *w, int cancel) { struct flush_work *fw = (struct flush_work *)w; struct drbd_epoch *epoch = fw->epoch; @@ -978,7 +982,7 @@ STATIC int w_flush(struct drbd_conf *mdev, struct drbd_work *w, int cancel) * @epoch: Epoch object. * @ev: Epoch event. */ -STATIC enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *mdev, +static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *mdev, struct drbd_epoch *epoch, enum epoch_event ev) { @@ -1173,7 +1177,7 @@ int w_e_reissue(struct drbd_conf *mdev, struct drbd_work *w, int cancel) __relea return 1; } -STATIC int receive_Barrier(struct drbd_conf *mdev, struct p_header *h) +static int receive_Barrier(struct drbd_conf *mdev, struct p_header *h) { int rv, issue_flush; struct p_barrier *p = (struct p_barrier *)h; @@ -1219,7 +1223,9 @@ STATIC int receive_Barrier(struct drbd_conf *mdev, struct p_header *h) break; } - epoch = kmalloc(sizeof(struct drbd_epoch), GFP_KERNEL); + /* receiver context, in the writeout path of the other node. + * avoid potential distributed deadlock */ + epoch = kmalloc(sizeof(struct drbd_epoch), GFP_NOIO); if (!epoch) { dev_warn(DEV, "Allocation of an epoch failed, slowing down\n"); issue_flush = !test_and_set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags); @@ -1256,7 +1262,7 @@ STATIC int receive_Barrier(struct drbd_conf *mdev, struct p_header *h) /* used from receive_RSDataReply (recv_resync_read) * and from receive_Data */ -STATIC struct drbd_epoch_entry * +static struct drbd_epoch_entry * read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, int data_size) __must_hold(local) { struct drbd_epoch_entry *e; @@ -1319,7 +1325,7 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, int data_size) __ /* drbd_drain_block() just takes a data block * out of the socket input buffer, and discards it. */ -STATIC int drbd_drain_block(struct drbd_conf *mdev, int data_size) +static int drbd_drain_block(struct drbd_conf *mdev, int data_size) { struct page *page; int rr, rv = 1; @@ -1352,7 +1358,7 @@ static void maybe_kick_lo(struct drbd_conf *mdev) drbd_kick_lo(mdev); } -STATIC int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req, +static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req, sector_t sector, int data_size) { struct bio_vec *bvec; @@ -1407,7 +1413,7 @@ STATIC int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req, /* e_end_resync_block() is called via * drbd_process_done_ee() by asender only */ -STATIC int e_end_resync_block(struct drbd_conf *mdev, struct drbd_work *w, int unused) +static int e_end_resync_block(struct drbd_conf *mdev, struct drbd_work *w, int unused) { struct drbd_epoch_entry *e = (struct drbd_epoch_entry *)w; sector_t sector = e->sector; @@ -1430,7 +1436,7 @@ STATIC int e_end_resync_block(struct drbd_conf *mdev, struct drbd_work *w, int u return ok; } -STATIC int recv_resync_read(struct drbd_conf *mdev, sector_t sector, int data_size) __releases(local) +static int recv_resync_read(struct drbd_conf *mdev, sector_t sector, int data_size) __releases(local) { struct drbd_epoch_entry *e; @@ -1463,7 +1469,7 @@ STATIC int recv_resync_read(struct drbd_conf *mdev, sector_t sector, int data_si return TRUE; } -STATIC int receive_DataReply(struct drbd_conf *mdev, struct p_header *h) +static int receive_DataReply(struct drbd_conf *mdev, struct p_header *h) { struct drbd_request *req; sector_t sector; @@ -1503,7 +1509,7 @@ STATIC int receive_DataReply(struct drbd_conf *mdev, struct p_header *h) return ok; } -STATIC int receive_RSDataReply(struct drbd_conf *mdev, struct p_header *h) +static int receive_RSDataReply(struct drbd_conf *mdev, struct p_header *h) { sector_t sector; unsigned int header_size, data_size; @@ -1541,7 +1547,7 @@ STATIC int receive_RSDataReply(struct drbd_conf *mdev, struct p_header *h) /* e_end_block() is called via drbd_process_done_ee(). * this means this function only runs in the asender thread */ -STATIC int e_end_block(struct drbd_conf *mdev, struct drbd_work *w, int unused) +static int e_end_block(struct drbd_conf *mdev, struct drbd_work *w, int unused) { struct drbd_epoch_entry *e = (struct drbd_epoch_entry *)w; sector_t sector = e->sector; @@ -1590,7 +1596,7 @@ STATIC int e_end_block(struct drbd_conf *mdev, struct drbd_work *w, int unused) return ok; } -STATIC int e_send_discard_ack(struct drbd_conf *mdev, struct drbd_work *w, int unused) +static int e_send_discard_ack(struct drbd_conf *mdev, struct drbd_work *w, int unused) { struct drbd_epoch_entry *e = (struct drbd_epoch_entry *)w; int ok = 1; @@ -1662,7 +1668,7 @@ static int drbd_wait_peer_seq(struct drbd_conf *mdev, const u32 packet_seq) } /* mirrored write */ -STATIC int receive_Data(struct drbd_conf *mdev, struct p_header *h) +static int receive_Data(struct drbd_conf *mdev, struct p_header *h) { sector_t sector; struct drbd_epoch_entry *e; @@ -1918,7 +1924,7 @@ out_interrupted: return FALSE; } -STATIC int receive_DataRequest(struct drbd_conf *mdev, struct p_header *h) +static int receive_DataRequest(struct drbd_conf *mdev, struct p_header *h) { sector_t sector; const sector_t capacity = drbd_get_capacity(mdev->this_bdev); @@ -1992,7 +1998,7 @@ STATIC int receive_DataRequest(struct drbd_conf *mdev, struct p_header *h) case P_CSUM_RS_REQUEST: fault_type = DRBD_FAULT_RS_RD; digest_size = h->length - brps ; - di = kmalloc(sizeof(*di) + digest_size, GFP_KERNEL); + di = kmalloc(sizeof(*di) + digest_size, GFP_NOIO); if (!di) { put_ldev(mdev); drbd_free_ee(mdev, e); @@ -2030,6 +2036,18 @@ STATIC int receive_DataRequest(struct drbd_conf *mdev, struct p_header *h) break; case P_OV_REQUEST: + if (mdev->state.conn >= C_CONNECTED && + mdev->state.conn != C_VERIFY_T) + dev_warn(DEV, "ASSERT FAILED: got P_OV_REQUEST while being %s\n", + conns_to_name(mdev->state.conn)); + if (mdev->ov_start_sector == ~(sector_t)0 && + mdev->agreed_pro_version >= 90) { + mdev->ov_start_sector = sector; + mdev->ov_position = sector; + mdev->ov_left = mdev->rs_total - BM_SECT_TO_BIT(sector); + dev_info(DEV, "Online Verify start sector: %llu\n", + (unsigned long long)sector); + } e->w.cb = w_e_end_ov_req; fault_type = DRBD_FAULT_RS_RD; /* Eventually this should become asynchrously. Currently it @@ -2068,7 +2086,7 @@ STATIC int receive_DataRequest(struct drbd_conf *mdev, struct p_header *h) return TRUE; } -STATIC int drbd_asb_recover_0p(struct drbd_conf *mdev) __must_hold(local) +static int drbd_asb_recover_0p(struct drbd_conf *mdev) __must_hold(local) { int self, peer, rv = -100; unsigned long ch_self, ch_peer; @@ -2140,7 +2158,7 @@ STATIC int drbd_asb_recover_0p(struct drbd_conf *mdev) __must_hold(local) return rv; } -STATIC int drbd_asb_recover_1p(struct drbd_conf *mdev) __must_hold(local) +static int drbd_asb_recover_1p(struct drbd_conf *mdev) __must_hold(local) { int self, peer, hg, rv = -100; @@ -2173,6 +2191,10 @@ STATIC int drbd_asb_recover_1p(struct drbd_conf *mdev) __must_hold(local) hg = drbd_asb_recover_0p(mdev); if (hg == -1 && mdev->state.role == R_PRIMARY) { self = drbd_set_role(mdev, R_SECONDARY, 0); + /* drbd_change_state() does not sleep while in SS_IN_TRANSIENT_STATE, + * we might be here in C_WF_REPORT_PARAMS which is transient. + * we do not need to wait for the after state change work either. */ + self = drbd_change_state(mdev, CS_VERBOSE, NS(role, R_SECONDARY)); if (self != SS_SUCCESS) { drbd_khelper(mdev, "pri-lost-after-sb"); } else { @@ -2186,7 +2208,7 @@ STATIC int drbd_asb_recover_1p(struct drbd_conf *mdev) __must_hold(local) return rv; } -STATIC int drbd_asb_recover_2p(struct drbd_conf *mdev) __must_hold(local) +static int drbd_asb_recover_2p(struct drbd_conf *mdev) __must_hold(local) { int self, peer, hg, rv = -100; @@ -2211,7 +2233,10 @@ STATIC int drbd_asb_recover_2p(struct drbd_conf *mdev) __must_hold(local) case ASB_CALL_HELPER: hg = drbd_asb_recover_0p(mdev); if (hg == -1) { - self = drbd_set_role(mdev, R_SECONDARY, 0); + /* drbd_change_state() does not sleep while in SS_IN_TRANSIENT_STATE, + * we might be here in C_WF_REPORT_PARAMS which is transient. + * we do not need to wait for the after state change work either. */ + self = drbd_change_state(mdev, CS_VERBOSE, NS(role, R_SECONDARY)); if (self != SS_SUCCESS) { drbd_khelper(mdev, "pri-lost-after-sb"); } else { @@ -2225,7 +2250,7 @@ STATIC int drbd_asb_recover_2p(struct drbd_conf *mdev) __must_hold(local) return rv; } -STATIC void drbd_uuid_dump(struct drbd_conf *mdev, char *text, u64 *uuid, +static void drbd_uuid_dump(struct drbd_conf *mdev, char *text, u64 *uuid, u64 bits, u64 flags) { if (!uuid) { @@ -2252,7 +2277,7 @@ STATIC void drbd_uuid_dump(struct drbd_conf *mdev, char *text, u64 *uuid, -100 after split brain, disconnect -1000 unrelated data */ -STATIC int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(local) +static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(local) { u64 self, peer; int i, j; @@ -2326,7 +2351,7 @@ STATIC int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(l *rule_nr = 10; for (i = UI_HISTORY_START; i <= UI_HISTORY_END; i++) { - self = mdev->p_uuid[i] & ~((u64)1); + self = mdev->ldev->md.uuid[i] & ~((u64)1); for (j = UI_HISTORY_START; j <= UI_HISTORY_END; j++) { peer = mdev->p_uuid[j] & ~((u64)1); if (self == peer) @@ -2340,7 +2365,7 @@ STATIC int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(l /* drbd_sync_handshake() returns the new conn state on success, or CONN_MASK (-1) on failure. */ -STATIC enum drbd_conns drbd_sync_handshake(struct drbd_conf *mdev, enum drbd_role peer_role, +static enum drbd_conns drbd_sync_handshake(struct drbd_conf *mdev, enum drbd_role peer_role, enum drbd_disk_state peer_disk) __must_hold(local) { int hg, rule_nr; @@ -2465,7 +2490,7 @@ STATIC enum drbd_conns drbd_sync_handshake(struct drbd_conf *mdev, enum drbd_rol } /* returns 1 if invalid */ -STATIC int cmp_after_sb(enum drbd_after_sb_p peer, enum drbd_after_sb_p self) +static int cmp_after_sb(enum drbd_after_sb_p peer, enum drbd_after_sb_p self) { /* ASB_DISCARD_REMOTE - ASB_DISCARD_LOCAL is valid */ if ((peer == ASB_DISCARD_REMOTE && self == ASB_DISCARD_LOCAL) || @@ -2485,7 +2510,7 @@ STATIC int cmp_after_sb(enum drbd_after_sb_p peer, enum drbd_after_sb_p self) return 1; } -STATIC int receive_protocol(struct drbd_conf *mdev, struct p_header *h) +static int receive_protocol(struct drbd_conf *mdev, struct p_header *h) { struct p_protocol *p = (struct p_protocol *)h; int header_size, data_size; @@ -2577,7 +2602,7 @@ struct crypto_hash *drbd_crypto_alloc_digest_safe(const struct drbd_conf *mdev, alg, name, PTR_ERR(tfm)); return tfm; } - if (crypto_tfm_alg_type(crypto_hash_tfm(tfm)) != CRYPTO_ALG_TYPE_DIGEST) { + if (!drbd_crypto_is_hash(crypto_hash_tfm(tfm))) { crypto_free_hash(tfm); dev_err(DEV, "\"%s\" is not a digest (%s)\n", alg, name); return ERR_PTR(-EINVAL); @@ -2585,7 +2610,7 @@ struct crypto_hash *drbd_crypto_alloc_digest_safe(const struct drbd_conf *mdev, return tfm; } -STATIC int receive_SyncParam(struct drbd_conf *mdev, struct p_header *h) +static int receive_SyncParam(struct drbd_conf *mdev, struct p_header *h) { int ok = TRUE; struct p_rs_param_89 *p = (struct p_rs_param_89 *)h; @@ -2656,8 +2681,10 @@ STATIC int receive_SyncParam(struct drbd_conf *mdev, struct p_header *h) } verify_tfm = drbd_crypto_alloc_digest_safe(mdev, p->verify_alg, "verify-alg"); - if (IS_ERR(verify_tfm)) + if (IS_ERR(verify_tfm)) { + verify_tfm = NULL; goto disconnect; + } } if (apv >= 89 && strcmp(mdev->sync_conf.csums_alg, p->csums_alg)) { @@ -2668,8 +2695,10 @@ STATIC int receive_SyncParam(struct drbd_conf *mdev, struct p_header *h) } csums_tfm = drbd_crypto_alloc_digest_safe(mdev, p->csums_alg, "csums-alg"); - if (IS_ERR(csums_tfm)) + if (IS_ERR(csums_tfm)) { + csums_tfm = NULL; goto disconnect; + } } @@ -2694,12 +2723,16 @@ STATIC int receive_SyncParam(struct drbd_conf *mdev, struct p_header *h) return ok; disconnect: + /* just for completeness: actually not needed, + * as this is not reached if csums_tfm was ok. */ + crypto_free_hash(csums_tfm); + /* but free the verify_tfm again, if csums_tfm did not work out */ crypto_free_hash(verify_tfm); drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); return FALSE; } -STATIC void drbd_setup_order_type(struct drbd_conf *mdev, int peer) +static void drbd_setup_order_type(struct drbd_conf *mdev, int peer) { /* sorry, we currently have no working implementation * of distributed TCQ */ @@ -2718,7 +2751,7 @@ static void warn_if_differ_considerably(struct drbd_conf *mdev, (unsigned long long)a, (unsigned long long)b); } -STATIC int receive_sizes(struct drbd_conf *mdev, struct p_header *h) +static int receive_sizes(struct drbd_conf *mdev, struct p_header *h) { struct p_sizes *p = (struct p_sizes *)h; enum determine_dev_size dd = unchanged; @@ -2815,7 +2848,7 @@ STATIC int receive_sizes(struct drbd_conf *mdev, struct p_header *h) } max_seg_s = be32_to_cpu(p->max_segment_size); - if (max_seg_s != mdev->rq_queue->max_segment_size) + if (max_seg_s != queue_max_segment_size(mdev->rq_queue)) drbd_setup_queue_param(mdev, max_seg_s); drbd_setup_order_type(mdev, be32_to_cpu(p->queue_order_type)); @@ -2827,9 +2860,10 @@ STATIC int receive_sizes(struct drbd_conf *mdev, struct p_header *h) drbd_get_capacity(mdev->this_bdev) || ldsc) { /* we have different sizes, probabely peer * needs to know my new size... */ - drbd_send_sizes(mdev); + drbd_send_sizes(mdev, 0); } - if (dd == grew && mdev->state.conn == C_CONNECTED) { + if (test_and_clear_bit(RESIZE_PENDING, &mdev->flags) || + (dd == grew && mdev->state.conn == C_CONNECTED)) { if (mdev->state.pdsk >= D_INCONSISTENT && mdev->state.disk >= D_INCONSISTENT) resync_after_online_grow(mdev); @@ -2841,7 +2875,7 @@ STATIC int receive_sizes(struct drbd_conf *mdev, struct p_header *h) return TRUE; } -STATIC int receive_uuids(struct drbd_conf *mdev, struct p_header *h) +static int receive_uuids(struct drbd_conf *mdev, struct p_header *h) { struct p_uuids *p = (struct p_uuids *)h; u64 *p_uuid; @@ -2851,7 +2885,7 @@ STATIC int receive_uuids(struct drbd_conf *mdev, struct p_header *h) if (drbd_recv(mdev, h->payload, h->length) != h->length) return FALSE; - p_uuid = kmalloc(sizeof(u64)*UI_EXTENDED_SIZE, GFP_KERNEL); + p_uuid = kmalloc(sizeof(u64)*UI_EXTENDED_SIZE, GFP_NOIO); for (i = UI_CURRENT; i < UI_EXTENDED_SIZE; i++) p_uuid[i] = be64_to_cpu(p->uuid[i]); @@ -2903,7 +2937,7 @@ STATIC int receive_uuids(struct drbd_conf *mdev, struct p_header *h) * convert_state() - Converts the peer's view of the cluster state to our point of view * @ps: The state as seen by the peer. */ -STATIC union drbd_state convert_state(union drbd_state ps) +static union drbd_state convert_state(union drbd_state ps) { union drbd_state ms; @@ -2929,7 +2963,7 @@ STATIC union drbd_state convert_state(union drbd_state ps) return ms; } -STATIC int receive_req_state(struct drbd_conf *mdev, struct p_header *h) +static int receive_req_state(struct drbd_conf *mdev, struct p_header *h) { struct p_req_state *p = (struct p_req_state *)h; union drbd_state mask, val; @@ -2959,7 +2993,7 @@ STATIC int receive_req_state(struct drbd_conf *mdev, struct p_header *h) return TRUE; } -STATIC int receive_state(struct drbd_conf *mdev, struct p_header *h) +static int receive_state(struct drbd_conf *mdev, struct p_header *h) { struct p_state *p = (struct p_state *)h; enum drbd_conns nconn, oconn; @@ -2993,12 +3027,21 @@ STATIC int receive_state(struct drbd_conf *mdev, struct p_header *h) get_ldev_if_state(mdev, D_NEGOTIATING)) { int cr; /* consider resync */ + /* if we established a new connection */ cr = (oconn < C_CONNECTED); + /* if we had an established connection + * and one of the nodes newly attaches a disk */ cr |= (oconn == C_CONNECTED && (peer_state.disk == D_NEGOTIATING || mdev->state.disk == D_NEGOTIATING)); - cr |= test_bit(CONSIDER_RESYNC, &mdev->flags); /* peer forced */ - cr |= (oconn == C_CONNECTED && peer_state.conn > C_CONNECTED); + /* if we have both been inconsistent, and the peer has been + * forced to be UpToDate with --overwrite-data */ + cr |= test_bit(CONSIDER_RESYNC, &mdev->flags); + /* if we had been plain connected, and the admin requested to + * start a sync by "invalidate" or "invalidate-remote" */ + cr |= (oconn == C_CONNECTED && + (peer_state.conn >= C_STARTING_SYNC_S && + peer_state.conn <= C_WF_BITMAP_T)); if (cr) nconn = drbd_sync_handshake(mdev, peer_state.role, real_peer_disk); @@ -3058,7 +3101,7 @@ STATIC int receive_state(struct drbd_conf *mdev, struct p_header *h) return TRUE; } -STATIC int receive_sync_uuid(struct drbd_conf *mdev, struct p_header *h) +static int receive_sync_uuid(struct drbd_conf *mdev, struct p_header *h) { struct p_rs_uuid *p = (struct p_rs_uuid *)h; @@ -3233,7 +3276,7 @@ void INFO_bm_xfer_stats(struct drbd_conf *mdev, in order to be agnostic to the 32 vs 64 bits issue. returns 0 on failure, 1 if we suceessfully received it. */ -STATIC int receive_bitmap(struct drbd_conf *mdev, struct p_header *h) +static int receive_bitmap(struct drbd_conf *mdev, struct p_header *h) { struct bm_xfer_ctx c; void *buffer; @@ -3321,7 +3364,7 @@ STATIC int receive_bitmap(struct drbd_conf *mdev, struct p_header *h) return ok; } -STATIC int receive_skip(struct drbd_conf *mdev, struct p_header *h) +static int receive_skip(struct drbd_conf *mdev, struct p_header *h) { /* TODO zero copy sink :) */ static char sink[128]; @@ -3340,7 +3383,7 @@ STATIC int receive_skip(struct drbd_conf *mdev, struct p_header *h) return size == 0; } -STATIC int receive_UnplugRemote(struct drbd_conf *mdev, struct p_header *h) +static int receive_UnplugRemote(struct drbd_conf *mdev, struct p_header *h) { if (mdev->state.disk >= D_INCONSISTENT) drbd_kick_lo(mdev); @@ -3383,7 +3426,7 @@ static drbd_cmd_handler_f drbd_default_handler[] = { static drbd_cmd_handler_f *drbd_cmd_handler = drbd_default_handler; static drbd_cmd_handler_f *drbd_opt_cmd_handler; -STATIC void drbdd(struct drbd_conf *mdev) +static void drbdd(struct drbd_conf *mdev) { drbd_cmd_handler_f handler; struct p_header *header = &mdev->data.rbuf.header; @@ -3421,7 +3464,7 @@ STATIC void drbdd(struct drbd_conf *mdev) } } -STATIC void drbd_fail_pending_reads(struct drbd_conf *mdev) +static void drbd_fail_pending_reads(struct drbd_conf *mdev) { struct hlist_head *slot; struct hlist_node *pos; @@ -3454,7 +3497,7 @@ STATIC void drbd_fail_pending_reads(struct drbd_conf *mdev) spin_unlock_irq(&mdev->req_lock); } -STATIC void drbd_disconnect(struct drbd_conf *mdev) +static void drbd_disconnect(struct drbd_conf *mdev) { struct drbd_work prev_work_done; enum drbd_fencing_p fp; @@ -3611,7 +3654,7 @@ STATIC void drbd_disconnect(struct drbd_conf *mdev) * * for now, they are expected to be zero, but ignored. */ -STATIC int drbd_send_handshake(struct drbd_conf *mdev) +static int drbd_send_handshake(struct drbd_conf *mdev) { /* ASSERT current == mdev->receiver ... */ struct p_handshake *p = &mdev->data.sbuf.handshake; @@ -3761,7 +3804,7 @@ int drbd_do_auth(struct drbd_conf *mdev) goto fail; } - peers_ch = kmalloc(p.length, GFP_KERNEL); + peers_ch = kmalloc(p.length, GFP_NOIO); if (peers_ch == NULL) { dev_err(DEV, "kmalloc of peers_ch failed\n"); rv = 0; @@ -3777,7 +3820,7 @@ int drbd_do_auth(struct drbd_conf *mdev) } resp_size = crypto_hash_digestsize(mdev->cram_hmac_tfm); - response = kmalloc(resp_size, GFP_KERNEL); + response = kmalloc(resp_size, GFP_NOIO); if (response == NULL) { dev_err(DEV, "kmalloc of response failed\n"); rv = 0; @@ -3823,7 +3866,7 @@ int drbd_do_auth(struct drbd_conf *mdev) goto fail; } - right_response = kmalloc(resp_size, GFP_KERNEL); + right_response = kmalloc(resp_size, GFP_NOIO); if (response == NULL) { dev_err(DEV, "kmalloc of right_response failed\n"); rv = 0; @@ -3854,7 +3897,7 @@ int drbd_do_auth(struct drbd_conf *mdev) } #endif -STATIC int drbdd_init(struct drbd_thread *thi) +int drbdd_init(struct drbd_thread *thi) { struct drbd_conf *mdev = thi->mdev; unsigned int minor = mdev_to_minor(mdev); @@ -3892,7 +3935,7 @@ STATIC int drbdd_init(struct drbd_thread *thi) /* ********* acknowledge sender ******** */ -STATIC int got_RqSReply(struct drbd_conf *mdev, struct p_header *h) +static int got_RqSReply(struct drbd_conf *mdev, struct p_header *h) { struct p_req_state_reply *p = (struct p_req_state_reply *)h; @@ -3910,13 +3953,13 @@ STATIC int got_RqSReply(struct drbd_conf *mdev, struct p_header *h) return TRUE; } -STATIC int got_Ping(struct drbd_conf *mdev, struct p_header *h) +static int got_Ping(struct drbd_conf *mdev, struct p_header *h) { return drbd_send_ping_ack(mdev); } -STATIC int got_PingAck(struct drbd_conf *mdev, struct p_header *h) +static int got_PingAck(struct drbd_conf *mdev, struct p_header *h) { /* restore idle timeout */ mdev->meta.socket->sk->sk_rcvtimeo = mdev->net_conf->ping_int*HZ; @@ -3924,7 +3967,7 @@ STATIC int got_PingAck(struct drbd_conf *mdev, struct p_header *h) return TRUE; } -STATIC int got_IsInSync(struct drbd_conf *mdev, struct p_header *h) +static int got_IsInSync(struct drbd_conf *mdev, struct p_header *h) { struct p_block_ack *p = (struct p_block_ack *)h; sector_t sector = be64_to_cpu(p->sector); @@ -3969,7 +4012,7 @@ static struct drbd_request *_ack_id_to_req(struct drbd_conf *mdev, return NULL; } -STATIC int got_BlockAck(struct drbd_conf *mdev, struct p_header *h) +static int got_BlockAck(struct drbd_conf *mdev, struct p_header *h) { struct drbd_request *req; struct p_block_ack *p = (struct p_block_ack *)h; @@ -4021,7 +4064,7 @@ STATIC int got_BlockAck(struct drbd_conf *mdev, struct p_header *h) return TRUE; } -STATIC int got_NegAck(struct drbd_conf *mdev, struct p_header *h) +static int got_NegAck(struct drbd_conf *mdev, struct p_header *h) { struct p_block_ack *p = (struct p_block_ack *)h; sector_t sector = be64_to_cpu(p->sector); @@ -4055,7 +4098,7 @@ STATIC int got_NegAck(struct drbd_conf *mdev, struct p_header *h) return TRUE; } -STATIC int got_NegDReply(struct drbd_conf *mdev, struct p_header *h) +static int got_NegDReply(struct drbd_conf *mdev, struct p_header *h) { struct drbd_request *req; struct p_block_ack *p = (struct p_block_ack *)h; @@ -4080,7 +4123,7 @@ STATIC int got_NegDReply(struct drbd_conf *mdev, struct p_header *h) return TRUE; } -STATIC int got_NegRSDReply(struct drbd_conf *mdev, struct p_header *h) +static int got_NegRSDReply(struct drbd_conf *mdev, struct p_header *h) { sector_t sector; int size; @@ -4103,7 +4146,7 @@ STATIC int got_NegRSDReply(struct drbd_conf *mdev, struct p_header *h) return TRUE; } -STATIC int got_BarrierAck(struct drbd_conf *mdev, struct p_header *h) +static int got_BarrierAck(struct drbd_conf *mdev, struct p_header *h) { struct p_barrier_ack *p = (struct p_barrier_ack *)h; @@ -4112,7 +4155,7 @@ STATIC int got_BarrierAck(struct drbd_conf *mdev, struct p_header *h) return TRUE; } -STATIC int got_OVResult(struct drbd_conf *mdev, struct p_header *h) +static int got_OVResult(struct drbd_conf *mdev, struct p_header *h) { struct p_block_ack *p = (struct p_block_ack *)h; struct drbd_work *w; @@ -4133,12 +4176,13 @@ STATIC int got_OVResult(struct drbd_conf *mdev, struct p_header *h) dec_rs_pending(mdev); if (--mdev->ov_left == 0) { - w = kmalloc(sizeof(*w), GFP_KERNEL); + w = kmalloc(sizeof(*w), GFP_NOIO); if (w) { w->cb = w_ov_finished; drbd_queue_work_front(&mdev->data.work, w); } else { dev_err(DEV, "kmalloc(w) failed."); + ov_oos_print(mdev); drbd_resync_finished(mdev); } } @@ -4165,16 +4209,18 @@ static struct asender_cmd *get_asender_cmd(int cmd) [P_NEG_ACK] = { sizeof(struct p_block_ack), got_NegAck }, [P_NEG_DREPLY] = { sizeof(struct p_block_ack), got_NegDReply }, [P_NEG_RS_DREPLY] = { sizeof(struct p_block_ack), got_NegRSDReply}, + [P_OV_RESULT] = { sizeof(struct p_block_ack), got_OVResult }, [P_BARRIER_ACK] = { sizeof(struct p_barrier_ack), got_BarrierAck }, [P_STATE_CHG_REPLY] = { sizeof(struct p_req_state_reply), got_RqSReply }, [P_RS_IS_IN_SYNC] = { sizeof(struct p_block_ack), got_IsInSync }, + [P_MAX_CMD] = { 0, NULL }, }; - if (cmd > P_MAX_CMD) + if (cmd > P_MAX_CMD || asender_tbl[cmd].process == NULL) return NULL; return &asender_tbl[cmd]; } -STATIC int drbd_asender(struct drbd_thread *thi) +int drbd_asender(struct drbd_thread *thi) { struct drbd_conf *mdev = thi->mdev; struct p_header *h = &mdev->meta.rbuf.header; @@ -4285,7 +4331,6 @@ STATIC int drbd_asender(struct drbd_thread *thi) expect = cmd->pkt_size; ERR_IF(len != expect-sizeof(struct p_header)) { trace_drbd_packet(mdev, mdev->meta.socket, 1, (void *)h, __FILE__, __LINE__); - DUMPI(expect); goto reconnect; } } diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 5c4039ad052e..d2b941cbc0a0 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -121,8 +121,8 @@ static void _req_is_done(struct drbd_conf *mdev, struct drbd_request *req, const list_empty(&req->w.list))) { /* DEBUG ASSERT only; if this triggers, we * probably corrupt the worker list here */ - DUMPP(req->w.list.next); - DUMPP(req->w.list.prev); + dev_err(DEV, "req->w.list.next = %p\n", req->w.list.next); + dev_err(DEV, "req->w.list.prev = %p\n", req->w.list.prev); } req->w.cb = w_io_error; drbd_queue_work(&mdev->data.work, &req->w); @@ -326,7 +326,7 @@ void _req_may_be_done(struct drbd_request *req, int error) * second hlist_for_each_entry becomes a noop. This is even simpler than to * grab a reference on the net_conf, and check for the two_primaries flag... */ -STATIC int _req_conflicts(struct drbd_request *req) +static int _req_conflicts(struct drbd_request *req) { struct drbd_conf *mdev = req->mdev; const sector_t sector = req->sector; @@ -689,7 +689,7 @@ void _req_mod(struct drbd_request *req, enum drbd_req_event what, int error) * since size may be bigger than BM_BLOCK_SIZE, * we may need to check several bits. */ -STATIC int drbd_may_do_local_read(struct drbd_conf *mdev, sector_t sector, int size) +static int drbd_may_do_local_read(struct drbd_conf *mdev, sector_t sector, int size) { unsigned long sbnr, ebnr; sector_t esector, nr_sectors; @@ -713,7 +713,7 @@ STATIC int drbd_may_do_local_read(struct drbd_conf *mdev, sector_t sector, int s return 0 == drbd_bm_count_bits(mdev, sbnr, ebnr); } -STATIC int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio) +static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio) { const int rw = bio_rw(bio); const int size = bio->bi_size; diff --git a/drivers/block/drbd/drbd_strings.c b/drivers/block/drbd/drbd_strings.c index b230693f35e6..09922d2d5bf9 100644 --- a/drivers/block/drbd/drbd_strings.c +++ b/drivers/block/drbd/drbd_strings.c @@ -71,13 +71,13 @@ static const char *drbd_disk_s_names[] = { static const char *drbd_state_sw_errors[] = { [-SS_TWO_PRIMARIES] = "Multiple primaries not allowed by config", [-SS_NO_UP_TO_DATE_DISK] = "Refusing to be Primary without at least one UpToDate disk", - [-SS_BOTH_INCONSISTENT] = "Refusing to be inconsistent on both nodes", - [-SS_SYNCING_DISKLESS] = "Refusing to be syncing and diskless", + [-SS_NO_LOCAL_DISK] = "Can not resync without local disk", + [-SS_NO_REMOTE_DISK] = "Can not resync without remote disk", [-SS_CONNECTED_OUTDATES] = "Refusing to be Outdated while Connected", [-SS_PRIMARY_NOP] = "Refusing to be Primary while peer is not outdated", [-SS_RESYNC_RUNNING] = "Can not start OV/resync since it is already active", [-SS_ALREADY_STANDALONE] = "Can not disconnect a StandAlone device", - [-SS_CW_FAILED_BY_PEER] = "State changed was refused by peer node", + [-SS_CW_FAILED_BY_PEER] = "State change was refused by peer node", [-SS_IS_DISKLESS] = "Device is diskless, the requesed operation requires a disk", [-SS_DEVICE_IN_USE] = "Device is held open by someone", [-SS_NO_NET_CONFIG] = "Have no net/connection configuration", diff --git a/drivers/block/drbd/drbd_tracing.c b/drivers/block/drbd/drbd_tracing.c index b467e92dda76..f2827209ca34 100644 --- a/drivers/block/drbd/drbd_tracing.c +++ b/drivers/block/drbd/drbd_tracing.c @@ -71,7 +71,7 @@ enum dbg_print_flags { }; /* Macro stuff */ -STATIC char *nl_packet_name(int packet_type) +static char *nl_packet_name(int packet_type) { /* Generate packet type strings */ #define NL_PACKET(name, number, fields) \ @@ -371,7 +371,7 @@ static void probe_drbd_resync(struct drbd_conf *mdev, int level, const char *fmt static void probe_drbd_bio(struct drbd_conf *mdev, const char *pfx, struct bio *bio, int complete, struct drbd_request *r) { -#ifdef CONFIG_LBD +#if defined(CONFIG_LBDAF) || defined(CONFIG_LBD) #define SECTOR_FORMAT "%Lx" #else #define SECTOR_FORMAT "%lx" @@ -387,7 +387,7 @@ static void probe_drbd_bio(struct drbd_conf *mdev, const char *pfx, struct bio * const int rw = bio->bi_rw; const int biorw = (rw & (RW_MASK|RWA_MASK)); const int biobarrier = (rw & (1<<BIO_RW_BARRIER)); - const int biosync = (rw & ((1<<BIO_RW_UNPLUG) | (1<<BIO_RW_SYNCIO))); + const int biosync = (rw & ((1<<BIO_RW_UNPLUG) | (1<<BIO_RW_SYNCIO))); if (!is_mdev_trace(mdev, TRACE_LVL_ALWAYS)) return; @@ -504,7 +504,7 @@ do { \ } \ } while (0) -STATIC char *dump_st(char *p, int len, union drbd_state mask, union drbd_state val) +static char *dump_st(char *p, int len, union drbd_state mask, union drbd_state val) { char *op = p; *p = '\0'; @@ -531,7 +531,7 @@ do { \ } \ } while (0) -STATIC char *_dump_block_id(u64 block_id, char *buff) +static char *_dump_block_id(u64 block_id, char *buff) { if (is_syncer_block_id(block_id)) strcpy(buff, "SyncerId"); diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 96065835fb69..29c5bba88998 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -26,12 +26,11 @@ #include <linux/autoconf.h> #include <linux/module.h> #include <linux/version.h> - +#include <linux/drbd.h> #include <linux/sched.h> #include <linux/smp_lock.h> #include <linux/wait.h> #include <linux/mm.h> -#include <linux/drbd_config.h> #include <linux/memcontrol.h> #include <linux/mm_inline.h> #include <linux/slab.h> @@ -40,14 +39,13 @@ #include <linux/string.h> #include <linux/scatterlist.h> -#include <linux/drbd.h> #include "drbd_int.h" #include "drbd_req.h" #include "drbd_tracing.h" #define SLEEP_TIME (HZ/10) -STATIC int w_make_ov_request(struct drbd_conf *mdev, struct drbd_work *w, int cancel); +static int w_make_ov_request(struct drbd_conf *mdev, struct drbd_work *w, int cancel); @@ -293,7 +291,7 @@ int w_resync_inactive(struct drbd_conf *mdev, struct drbd_work *w, int cancel) return 1; /* Simply ignore this! */ } -STATIC void drbd_csum(struct drbd_conf *mdev, struct crypto_hash *tfm, struct bio *bio, void *digest) +void drbd_csum(struct drbd_conf *mdev, struct crypto_hash *tfm, struct bio *bio, void *digest) { struct hash_desc desc; struct scatterlist sg; @@ -313,7 +311,7 @@ STATIC void drbd_csum(struct drbd_conf *mdev, struct crypto_hash *tfm, struct bi crypto_hash_final(&desc, digest); } -STATIC int w_e_send_csum(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +static int w_e_send_csum(struct drbd_conf *mdev, struct drbd_work *w, int cancel) { struct drbd_epoch_entry *e = (struct drbd_epoch_entry *)w; int digest_size; @@ -329,7 +327,7 @@ STATIC int w_e_send_csum(struct drbd_conf *mdev, struct drbd_work *w, int cancel if (likely(drbd_bio_uptodate(e->private_bio))) { digest_size = crypto_hash_digestsize(mdev->csums_tfm); - digest = kmalloc(digest_size, GFP_KERNEL); + digest = kmalloc(digest_size, GFP_NOIO); if (digest) { drbd_csum(mdev, mdev->csums_tfm, e->private_bio, digest); @@ -359,7 +357,7 @@ STATIC int w_e_send_csum(struct drbd_conf *mdev, struct drbd_work *w, int cancel #define GFP_TRY (__GFP_HIGHMEM | __GFP_NOWARN) -STATIC int read_for_csum(struct drbd_conf *mdev, sector_t sector, int size) +static int read_for_csum(struct drbd_conf *mdev, sector_t sector, int size) { struct drbd_epoch_entry *e; @@ -421,9 +419,9 @@ int w_make_resync_request(struct drbd_conf *mdev, unsigned long bit; sector_t sector; const sector_t capacity = drbd_get_capacity(mdev->this_bdev); - int max_segment_size = mdev->rq_queue->max_segment_size; - int number, i, size; - int align; + int max_segment_size = queue_max_segment_size(mdev->rq_queue); + int number, i, size, pe, mx; + int align, queued, sndbuf; if (unlikely(cancel)) return 1; @@ -446,15 +444,40 @@ int w_make_resync_request(struct drbd_conf *mdev, mdev->resync_work.cb = w_resync_inactive; return 1; } - /* All goto requeses have to happend after this block: get_ldev() */ - number = SLEEP_TIME*mdev->sync_conf.rate / ((BM_BLOCK_SIZE/1024)*HZ); + number = SLEEP_TIME * mdev->sync_conf.rate / ((BM_BLOCK_SIZE/1024)*HZ); + pe = atomic_read(&mdev->rs_pending_cnt); - if (atomic_read(&mdev->rs_pending_cnt) > number) - goto requeue; - number -= atomic_read(&mdev->rs_pending_cnt); + mutex_lock(&mdev->data.mutex); + if (mdev->data.socket) + mx = mdev->data.socket->sk->sk_rcvbuf / sizeof(struct p_block_req); + else + mx = 1; + mutex_unlock(&mdev->data.mutex); + + /* For resync rates >160MB/sec, allow more pending RS requests */ + if (number > mx) + mx = number; + + /* Limit the nunber of pending RS requests to no more than the peer's receive buffer */ + if ((pe + number) > mx) { + number = mx - pe; + } for (i = 0; i < number; i++) { + /* Stop generating RS requests, when half of the sendbuffer is filled */ + mutex_lock(&mdev->data.mutex); + if (mdev->data.socket) { + queued = mdev->data.socket->sk->sk_wmem_queued; + sndbuf = mdev->data.socket->sk->sk_sndbuf; + } else { + queued = 1; + sndbuf = 0; + } + mutex_unlock(&mdev->data.mutex); + if (queued > sndbuf / 2) + goto requeue; + next_sector: size = BM_BLOCK_SIZE; bit = drbd_bm_find_next(mdev, mdev->bm_resync_fo); @@ -589,6 +612,11 @@ int w_make_ov_request(struct drbd_conf *mdev, struct drbd_work *w, int cancel) sector = mdev->ov_position; for (i = 0; i < number; i++) { + if (sector >= capacity) { + mdev->resync_work.cb = w_resync_inactive; + return 1; + } + size = BM_BLOCK_SIZE; if (drbd_try_rs_begin_io(mdev, sector)) { @@ -605,11 +633,6 @@ int w_make_ov_request(struct drbd_conf *mdev, struct drbd_work *w, int cancel) return 0; } sector += BM_SECT_PER_BIT; - if (sector >= capacity) { - mdev->resync_work.cb = w_resync_inactive; - - return 1; - } } mdev->ov_position = sector; @@ -628,7 +651,7 @@ int w_ov_finished(struct drbd_conf *mdev, struct drbd_work *w, int cancel) return 1; } -STATIC int w_resync_finished(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +static int w_resync_finished(struct drbd_conf *mdev, struct drbd_work *w, int cancel) { kfree(w); @@ -766,6 +789,7 @@ out: mdev->rs_total = 0; mdev->rs_failed = 0; mdev->rs_paused = 0; + mdev->ov_start_sector = 0; if (test_and_clear_bit(WRITE_BM_AFTER_RESYNC, &mdev->flags)) { dev_warn(DEV, "Writing the whole bitmap, due to failed kmalloc\n"); @@ -911,7 +935,7 @@ int w_e_end_csum_rs_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) if (mdev->csums_tfm) { digest_size = crypto_hash_digestsize(mdev->csums_tfm); D_ASSERT(digest_size == di->digest_size); - digest = kmalloc(digest_size, GFP_KERNEL); + digest = kmalloc(digest_size, GFP_NOIO); } if (digest) { drbd_csum(mdev, mdev->csums_tfm, e->private_bio, digest); @@ -967,13 +991,15 @@ int w_e_end_ov_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) goto out; digest_size = crypto_hash_digestsize(mdev->verify_tfm); - digest = kmalloc(digest_size, GFP_KERNEL); + /* FIXME if this allocation fails, online verify will not terminate! */ + digest = kmalloc(digest_size, GFP_NOIO); if (digest) { drbd_csum(mdev, mdev->verify_tfm, e->private_bio, digest); + inc_rs_pending(mdev); ok = drbd_send_drequest_csum(mdev, e->sector, e->size, digest, digest_size, P_OV_REPLY); - if (ok) - inc_rs_pending(mdev); + if (!ok) + dec_rs_pending(mdev); kfree(digest); } @@ -1021,7 +1047,7 @@ int w_e_end_ov_reply(struct drbd_conf *mdev, struct drbd_work *w, int cancel) if (likely(drbd_bio_uptodate(e->private_bio))) { digest_size = crypto_hash_digestsize(mdev->verify_tfm); - digest = kmalloc(digest_size, GFP_KERNEL); + digest = kmalloc(digest_size, GFP_NOIO); if (digest) { drbd_csum(mdev, mdev->verify_tfm, e->private_bio, digest); @@ -1157,7 +1183,7 @@ int w_send_read_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) return ok; } -STATIC int _drbd_may_sync_now(struct drbd_conf *mdev) +static int _drbd_may_sync_now(struct drbd_conf *mdev) { struct drbd_conf *odev = mdev; @@ -1180,7 +1206,7 @@ STATIC int _drbd_may_sync_now(struct drbd_conf *mdev) * * Called from process context only (admin command and after_state_ch). */ -STATIC int _drbd_pause_after(struct drbd_conf *mdev) +static int _drbd_pause_after(struct drbd_conf *mdev) { struct drbd_conf *odev; int i, rv = 0; @@ -1205,7 +1231,7 @@ STATIC int _drbd_pause_after(struct drbd_conf *mdev) * * Called from process context only (admin command and worker). */ -STATIC int _drbd_resume_next(struct drbd_conf *mdev) +static int _drbd_resume_next(struct drbd_conf *mdev) { struct drbd_conf *odev; int i, rv = 0; @@ -1240,19 +1266,46 @@ void suspend_other_sg(struct drbd_conf *mdev) write_unlock_irq(&global_state_lock); } -void drbd_alter_sa(struct drbd_conf *mdev, int na) +static int sync_after_error(struct drbd_conf *mdev, int o_minor) { - int changes; + struct drbd_conf *odev; - write_lock_irq(&global_state_lock); - mdev->sync_conf.after = na; + if (o_minor == -1) + return NO_ERROR; + if (o_minor < -1 || minor_to_mdev(o_minor) == NULL) + return ERR_SYNC_AFTER; + + /* check for loops */ + odev = minor_to_mdev(o_minor); + while (1) { + if (odev == mdev) + return ERR_SYNC_AFTER_CYCLE; - do { - changes = _drbd_pause_after(mdev); - changes |= _drbd_resume_next(mdev); - } while (changes); + /* dependency chain ends here, no cycles. */ + if (odev->sync_conf.after == -1) + return NO_ERROR; + /* follow the dependency chain */ + odev = minor_to_mdev(odev->sync_conf.after); + } +} + +int drbd_alter_sa(struct drbd_conf *mdev, int na) +{ + int changes; + int retcode; + + write_lock_irq(&global_state_lock); + retcode = sync_after_error(mdev, na); + if (retcode == NO_ERROR) { + mdev->sync_conf.after = na; + do { + changes = _drbd_pause_after(mdev); + changes |= _drbd_resume_next(mdev); + } while (changes); + } write_unlock_irq(&global_state_lock); + return retcode; } /** @@ -1268,6 +1321,11 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side) union drbd_state ns; int r; + if (mdev->state.conn >= C_SYNC_SOURCE) { + dev_err(DEV, "Resync already running!\n"); + return; + } + trace_drbd_resync(mdev, TRACE_LVL_SUMMARY, "Resync starting: side=%s\n", side == C_SYNC_TARGET ? "SyncTarget" : "SyncSource"); diff --git a/drivers/block/drbd/drbd_wrappers.h b/drivers/block/drbd/drbd_wrappers.h index 724fb44aad06..f93fa111ce50 100644 --- a/drivers/block/drbd/drbd_wrappers.h +++ b/drivers/block/drbd/drbd_wrappers.h @@ -7,11 +7,6 @@ /* see get_sb_bdev and bd_claim */ extern char *drbd_sec_holder; -static inline sector_t drbd_get_hardsect_size(struct block_device *bdev) -{ - return bdev->bd_disk->queue->hardsect_size; -} - /* sets the number of 512 byte sectors of our virtual device */ static inline void drbd_set_my_capacity(struct drbd_conf *mdev, sector_t size) |