summaryrefslogtreecommitdiff
path: root/drivers/block
diff options
context:
space:
mode:
authorPhilipp Reisner <philipp.reisner@linbit.com>2009-06-25 15:57:22 +0200
committerPhilipp Reisner <philipp.reisner@linbit.com>2009-07-29 10:45:13 +0200
commit65b0b44dbf9dfec3f78ded84ee22b0a0a1bf82bf (patch)
treef3d14a3f200594b94717657e682a0a79a33499ef /drivers/block
parentb8e44af93cf7dd81fa1ead3e96b16df843fd99aa (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/Kconfig32
-rw-r--r--drivers/block/drbd/Makefile2
-rw-r--r--drivers/block/drbd/drbd_actlog.c65
-rw-r--r--drivers/block/drbd/drbd_bitmap.c35
-rw-r--r--drivers/block/drbd/drbd_buildtag.c7
-rw-r--r--drivers/block/drbd/drbd_int.h65
-rw-r--r--drivers/block/drbd/drbd_main.c222
-rw-r--r--drivers/block/drbd/drbd_nl.c362
-rw-r--r--drivers/block/drbd/drbd_proc.c11
-rw-r--r--drivers/block/drbd/drbd_receiver.c235
-rw-r--r--drivers/block/drbd/drbd_req.c10
-rw-r--r--drivers/block/drbd/drbd_strings.c6
-rw-r--r--drivers/block/drbd/drbd_tracing.c10
-rw-r--r--drivers/block/drbd/drbd_worker.c134
-rw-r--r--drivers/block/drbd/drbd_wrappers.h5
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)