You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'for-3.17/drivers' of git://git.kernel.dk/linux-block
Pull block driver changes from Jens Axboe:
"Nothing out of the ordinary here, this pull request contains:
- A big round of fixes for bcache from Kent Overstreet, Slava Pestov,
and Surbhi Palande. No new features, just a lot of fixes.
- The usual round of drbd updates from Andreas Gruenbacher, Lars
Ellenberg, and Philipp Reisner.
- virtio_blk was converted to blk-mq back in 3.13, but now Ming Lei
has taken it one step further and added support for actually using
more than one queue.
- Addition of an explicit SG_FLAG_Q_AT_HEAD for block/bsg, to
compliment the the default behavior of adding to the tail of the
queue. From Douglas Gilbert"
* 'for-3.17/drivers' of git://git.kernel.dk/linux-block: (86 commits)
bcache: Drop unneeded blk_sync_queue() calls
bcache: add mutex lock for bch_is_open
bcache: Correct printing of btree_gc_max_duration_ms
bcache: try to set b->parent properly
bcache: fix memory corruption in init error path
bcache: fix crash with incomplete cache set
bcache: Fix more early shutdown bugs
bcache: fix use-after-free in btree_gc_coalesce()
bcache: Fix an infinite loop in journal replay
bcache: fix crash in bcache_btree_node_alloc_fail tracepoint
bcache: bcache_write tracepoint was crashing
bcache: fix typo in bch_bkey_equal_header
bcache: Allocate bounce buffers with GFP_NOWAIT
bcache: Make sure to pass GFP_WAIT to mempool_alloc()
bcache: fix uninterruptible sleep in writeback thread
bcache: wait for buckets when allocating new btree root
bcache: fix crash on shutdown in passthrough mode
bcache: fix lockdep warnings on shutdown
bcache allocator: send discards with correct size
bcache: Fix to remove the rcu_sched stalls.
...
This commit is contained in:
@@ -3,5 +3,6 @@ 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
|
||||
drbd-y += drbd_interval.o drbd_state.o
|
||||
drbd-y += drbd_nla.o
|
||||
drbd-$(CONFIG_DEBUG_FS) += drbd_debugfs.o
|
||||
|
||||
obj-$(CONFIG_BLK_DEV_DRBD) += drbd.o
|
||||
|
||||
+202
-320
File diff suppressed because it is too large
Load Diff
@@ -22,6 +22,8 @@
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/string.h>
|
||||
@@ -353,9 +355,8 @@ static void bm_free_pages(struct page **pages, unsigned long number)
|
||||
|
||||
for (i = 0; i < number; i++) {
|
||||
if (!pages[i]) {
|
||||
printk(KERN_ALERT "drbd: bm_free_pages tried to free "
|
||||
"a NULL pointer; i=%lu n=%lu\n",
|
||||
i, number);
|
||||
pr_alert("bm_free_pages tried to free a NULL pointer; i=%lu n=%lu\n",
|
||||
i, number);
|
||||
continue;
|
||||
}
|
||||
__free_page(pages[i]);
|
||||
@@ -592,7 +593,7 @@ static void bm_memset(struct drbd_bitmap *b, size_t offset, int c, size_t len)
|
||||
end = offset + len;
|
||||
|
||||
if (end > b->bm_words) {
|
||||
printk(KERN_ALERT "drbd: bm_memset end > bm_words\n");
|
||||
pr_alert("bm_memset end > bm_words\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -602,7 +603,7 @@ static void bm_memset(struct drbd_bitmap *b, size_t offset, int c, size_t len)
|
||||
p_addr = bm_map_pidx(b, idx);
|
||||
bm = p_addr + MLPP(offset);
|
||||
if (bm+do_now > p_addr + LWPP) {
|
||||
printk(KERN_ALERT "drbd: BUG BUG BUG! p_addr:%p bm:%p do_now:%d\n",
|
||||
pr_alert("BUG BUG BUG! p_addr:%p bm:%p do_now:%d\n",
|
||||
p_addr, bm, (int)do_now);
|
||||
} else
|
||||
memset(bm, c, do_now * sizeof(long));
|
||||
@@ -927,22 +928,14 @@ void drbd_bm_clear_all(struct drbd_device *device)
|
||||
spin_unlock_irq(&b->bm_lock);
|
||||
}
|
||||
|
||||
struct bm_aio_ctx {
|
||||
struct drbd_device *device;
|
||||
atomic_t in_flight;
|
||||
unsigned int done;
|
||||
unsigned flags;
|
||||
#define BM_AIO_COPY_PAGES 1
|
||||
#define BM_AIO_WRITE_HINTED 2
|
||||
#define BM_WRITE_ALL_PAGES 4
|
||||
int error;
|
||||
struct kref kref;
|
||||
};
|
||||
|
||||
static void bm_aio_ctx_destroy(struct kref *kref)
|
||||
static void drbd_bm_aio_ctx_destroy(struct kref *kref)
|
||||
{
|
||||
struct bm_aio_ctx *ctx = container_of(kref, struct bm_aio_ctx, kref);
|
||||
struct drbd_bm_aio_ctx *ctx = container_of(kref, struct drbd_bm_aio_ctx, kref);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ctx->device->resource->req_lock, flags);
|
||||
list_del(&ctx->list);
|
||||
spin_unlock_irqrestore(&ctx->device->resource->req_lock, flags);
|
||||
put_ldev(ctx->device);
|
||||
kfree(ctx);
|
||||
}
|
||||
@@ -950,7 +943,7 @@ static void bm_aio_ctx_destroy(struct kref *kref)
|
||||
/* bv_page may be a copy, or may be the original */
|
||||
static void bm_async_io_complete(struct bio *bio, int error)
|
||||
{
|
||||
struct bm_aio_ctx *ctx = bio->bi_private;
|
||||
struct drbd_bm_aio_ctx *ctx = bio->bi_private;
|
||||
struct drbd_device *device = ctx->device;
|
||||
struct drbd_bitmap *b = device->bitmap;
|
||||
unsigned int idx = bm_page_to_idx(bio->bi_io_vec[0].bv_page);
|
||||
@@ -993,17 +986,18 @@ static void bm_async_io_complete(struct bio *bio, int error)
|
||||
if (atomic_dec_and_test(&ctx->in_flight)) {
|
||||
ctx->done = 1;
|
||||
wake_up(&device->misc_wait);
|
||||
kref_put(&ctx->kref, &bm_aio_ctx_destroy);
|
||||
kref_put(&ctx->kref, &drbd_bm_aio_ctx_destroy);
|
||||
}
|
||||
}
|
||||
|
||||
static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must_hold(local)
|
||||
static void bm_page_io_async(struct drbd_bm_aio_ctx *ctx, int page_nr) __must_hold(local)
|
||||
{
|
||||
struct bio *bio = bio_alloc_drbd(GFP_NOIO);
|
||||
struct drbd_device *device = ctx->device;
|
||||
struct drbd_bitmap *b = device->bitmap;
|
||||
struct page *page;
|
||||
unsigned int len;
|
||||
unsigned int rw = (ctx->flags & BM_AIO_READ) ? READ : WRITE;
|
||||
|
||||
sector_t on_disk_sector =
|
||||
device->ldev->md.md_offset + device->ldev->md.bm_offset;
|
||||
@@ -1049,9 +1043,9 @@ static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must
|
||||
/*
|
||||
* bm_rw: read/write the whole bitmap from/to its on disk location.
|
||||
*/
|
||||
static int bm_rw(struct drbd_device *device, int rw, unsigned flags, unsigned lazy_writeout_upper_idx) __must_hold(local)
|
||||
static int bm_rw(struct drbd_device *device, const unsigned int flags, unsigned lazy_writeout_upper_idx) __must_hold(local)
|
||||
{
|
||||
struct bm_aio_ctx *ctx;
|
||||
struct drbd_bm_aio_ctx *ctx;
|
||||
struct drbd_bitmap *b = device->bitmap;
|
||||
int num_pages, i, count = 0;
|
||||
unsigned long now;
|
||||
@@ -1067,12 +1061,13 @@ static int bm_rw(struct drbd_device *device, int rw, unsigned flags, unsigned la
|
||||
* as we submit copies of pages anyways.
|
||||
*/
|
||||
|
||||
ctx = kmalloc(sizeof(struct bm_aio_ctx), GFP_NOIO);
|
||||
ctx = kmalloc(sizeof(struct drbd_bm_aio_ctx), GFP_NOIO);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
*ctx = (struct bm_aio_ctx) {
|
||||
*ctx = (struct drbd_bm_aio_ctx) {
|
||||
.device = device,
|
||||
.start_jif = jiffies,
|
||||
.in_flight = ATOMIC_INIT(1),
|
||||
.done = 0,
|
||||
.flags = flags,
|
||||
@@ -1080,15 +1075,21 @@ static int bm_rw(struct drbd_device *device, int rw, unsigned flags, unsigned la
|
||||
.kref = { ATOMIC_INIT(2) },
|
||||
};
|
||||
|
||||
if (!get_ldev_if_state(device, D_ATTACHING)) { /* put is in bm_aio_ctx_destroy() */
|
||||
if (!get_ldev_if_state(device, D_ATTACHING)) { /* put is in drbd_bm_aio_ctx_destroy() */
|
||||
drbd_err(device, "ASSERT FAILED: get_ldev_if_state() == 1 in bm_rw()\n");
|
||||
kfree(ctx);
|
||||
return -ENODEV;
|
||||
}
|
||||
/* Here D_ATTACHING is sufficient since drbd_bm_read() is called only from
|
||||
drbd_adm_attach(), after device->ldev was assigned. */
|
||||
|
||||
if (!ctx->flags)
|
||||
if (0 == (ctx->flags & ~BM_AIO_READ))
|
||||
WARN_ON(!(BM_LOCKED_MASK & b->bm_flags));
|
||||
|
||||
spin_lock_irq(&device->resource->req_lock);
|
||||
list_add_tail(&ctx->list, &device->pending_bitmap_io);
|
||||
spin_unlock_irq(&device->resource->req_lock);
|
||||
|
||||
num_pages = b->bm_number_of_pages;
|
||||
|
||||
now = jiffies;
|
||||
@@ -1098,13 +1099,13 @@ static int bm_rw(struct drbd_device *device, int rw, unsigned flags, unsigned la
|
||||
/* ignore completely unchanged pages */
|
||||
if (lazy_writeout_upper_idx && i == lazy_writeout_upper_idx)
|
||||
break;
|
||||
if (rw & WRITE) {
|
||||
if (!(flags & BM_AIO_READ)) {
|
||||
if ((flags & BM_AIO_WRITE_HINTED) &&
|
||||
!test_and_clear_bit(BM_PAGE_HINT_WRITEOUT,
|
||||
&page_private(b->bm_pages[i])))
|
||||
continue;
|
||||
|
||||
if (!(flags & BM_WRITE_ALL_PAGES) &&
|
||||
if (!(flags & BM_AIO_WRITE_ALL_PAGES) &&
|
||||
bm_test_page_unchanged(b->bm_pages[i])) {
|
||||
dynamic_drbd_dbg(device, "skipped bm write for idx %u\n", i);
|
||||
continue;
|
||||
@@ -1118,7 +1119,7 @@ static int bm_rw(struct drbd_device *device, int rw, unsigned flags, unsigned la
|
||||
}
|
||||
}
|
||||
atomic_inc(&ctx->in_flight);
|
||||
bm_page_io_async(ctx, i, rw);
|
||||
bm_page_io_async(ctx, i);
|
||||
++count;
|
||||
cond_resched();
|
||||
}
|
||||
@@ -1134,12 +1135,12 @@ static int bm_rw(struct drbd_device *device, int rw, unsigned flags, unsigned la
|
||||
if (!atomic_dec_and_test(&ctx->in_flight))
|
||||
wait_until_done_or_force_detached(device, device->ldev, &ctx->done);
|
||||
else
|
||||
kref_put(&ctx->kref, &bm_aio_ctx_destroy);
|
||||
kref_put(&ctx->kref, &drbd_bm_aio_ctx_destroy);
|
||||
|
||||
/* summary for global bitmap IO */
|
||||
if (flags == 0)
|
||||
drbd_info(device, "bitmap %s of %u pages took %lu jiffies\n",
|
||||
rw == WRITE ? "WRITE" : "READ",
|
||||
(flags & BM_AIO_READ) ? "READ" : "WRITE",
|
||||
count, jiffies - now);
|
||||
|
||||
if (ctx->error) {
|
||||
@@ -1152,20 +1153,18 @@ static int bm_rw(struct drbd_device *device, int rw, unsigned flags, unsigned la
|
||||
err = -EIO; /* Disk timeout/force-detach during IO... */
|
||||
|
||||
now = jiffies;
|
||||
if (rw == WRITE) {
|
||||
drbd_md_flush(device);
|
||||
} else /* rw == READ */ {
|
||||
if (flags & BM_AIO_READ) {
|
||||
b->bm_set = bm_count_bits(b);
|
||||
drbd_info(device, "recounting of set bits took additional %lu jiffies\n",
|
||||
jiffies - now);
|
||||
}
|
||||
now = b->bm_set;
|
||||
|
||||
if (flags == 0)
|
||||
if ((flags & ~BM_AIO_READ) == 0)
|
||||
drbd_info(device, "%s (%lu bits) marked out-of-sync by on disk bit-map.\n",
|
||||
ppsize(ppb, now << (BM_BLOCK_SHIFT-10)), now);
|
||||
|
||||
kref_put(&ctx->kref, &bm_aio_ctx_destroy);
|
||||
kref_put(&ctx->kref, &drbd_bm_aio_ctx_destroy);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -1175,7 +1174,7 @@ static int bm_rw(struct drbd_device *device, int rw, unsigned flags, unsigned la
|
||||
*/
|
||||
int drbd_bm_read(struct drbd_device *device) __must_hold(local)
|
||||
{
|
||||
return bm_rw(device, READ, 0, 0);
|
||||
return bm_rw(device, BM_AIO_READ, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1186,7 +1185,7 @@ int drbd_bm_read(struct drbd_device *device) __must_hold(local)
|
||||
*/
|
||||
int drbd_bm_write(struct drbd_device *device) __must_hold(local)
|
||||
{
|
||||
return bm_rw(device, WRITE, 0, 0);
|
||||
return bm_rw(device, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1197,7 +1196,17 @@ int drbd_bm_write(struct drbd_device *device) __must_hold(local)
|
||||
*/
|
||||
int drbd_bm_write_all(struct drbd_device *device) __must_hold(local)
|
||||
{
|
||||
return bm_rw(device, WRITE, BM_WRITE_ALL_PAGES, 0);
|
||||
return bm_rw(device, BM_AIO_WRITE_ALL_PAGES, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* drbd_bm_write_lazy() - Write bitmap pages 0 to @upper_idx-1, if they have changed.
|
||||
* @device: DRBD device.
|
||||
* @upper_idx: 0: write all changed pages; +ve: page index to stop scanning for changed pages
|
||||
*/
|
||||
int drbd_bm_write_lazy(struct drbd_device *device, unsigned upper_idx) __must_hold(local)
|
||||
{
|
||||
return bm_rw(device, BM_AIO_COPY_PAGES, upper_idx);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1213,7 +1222,7 @@ int drbd_bm_write_all(struct drbd_device *device) __must_hold(local)
|
||||
*/
|
||||
int drbd_bm_write_copy_pages(struct drbd_device *device) __must_hold(local)
|
||||
{
|
||||
return bm_rw(device, WRITE, BM_AIO_COPY_PAGES, 0);
|
||||
return bm_rw(device, BM_AIO_COPY_PAGES, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1222,62 +1231,7 @@ int drbd_bm_write_copy_pages(struct drbd_device *device) __must_hold(local)
|
||||
*/
|
||||
int drbd_bm_write_hinted(struct drbd_device *device) __must_hold(local)
|
||||
{
|
||||
return bm_rw(device, WRITE, BM_AIO_WRITE_HINTED | BM_AIO_COPY_PAGES, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* drbd_bm_write_page() - Writes a PAGE_SIZE aligned piece of bitmap
|
||||
* @device: DRBD device.
|
||||
* @idx: bitmap page index
|
||||
*
|
||||
* We don't want to special case on logical_block_size of the backend device,
|
||||
* so we submit PAGE_SIZE aligned pieces.
|
||||
* Note that on "most" systems, PAGE_SIZE is 4k.
|
||||
*
|
||||
* In case this becomes an issue on systems with larger PAGE_SIZE,
|
||||
* we may want to change this again to write 4k aligned 4k pieces.
|
||||
*/
|
||||
int drbd_bm_write_page(struct drbd_device *device, unsigned int idx) __must_hold(local)
|
||||
{
|
||||
struct bm_aio_ctx *ctx;
|
||||
int err;
|
||||
|
||||
if (bm_test_page_unchanged(device->bitmap->bm_pages[idx])) {
|
||||
dynamic_drbd_dbg(device, "skipped bm page write for idx %u\n", idx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ctx = kmalloc(sizeof(struct bm_aio_ctx), GFP_NOIO);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
*ctx = (struct bm_aio_ctx) {
|
||||
.device = device,
|
||||
.in_flight = ATOMIC_INIT(1),
|
||||
.done = 0,
|
||||
.flags = BM_AIO_COPY_PAGES,
|
||||
.error = 0,
|
||||
.kref = { ATOMIC_INIT(2) },
|
||||
};
|
||||
|
||||
if (!get_ldev_if_state(device, D_ATTACHING)) { /* put is in bm_aio_ctx_destroy() */
|
||||
drbd_err(device, "ASSERT FAILED: get_ldev_if_state() == 1 in drbd_bm_write_page()\n");
|
||||
kfree(ctx);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
bm_page_io_async(ctx, idx, WRITE_SYNC);
|
||||
wait_until_done_or_force_detached(device, device->ldev, &ctx->done);
|
||||
|
||||
if (ctx->error)
|
||||
drbd_chk_io_error(device, 1, DRBD_META_IO_ERROR);
|
||||
/* that causes us to detach, so the in memory bitmap will be
|
||||
* gone in a moment as well. */
|
||||
|
||||
device->bm_writ_cnt++;
|
||||
err = atomic_read(&ctx->in_flight) ? -EIO : ctx->error;
|
||||
kref_put(&ctx->kref, &bm_aio_ctx_destroy);
|
||||
return err;
|
||||
return bm_rw(device, BM_AIO_WRITE_HINTED | BM_AIO_COPY_PAGES, 0);
|
||||
}
|
||||
|
||||
/* NOTE
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,39 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/debugfs.h>
|
||||
|
||||
#include "drbd_int.h"
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
int __init drbd_debugfs_init(void);
|
||||
void drbd_debugfs_cleanup(void);
|
||||
|
||||
void drbd_debugfs_resource_add(struct drbd_resource *resource);
|
||||
void drbd_debugfs_resource_cleanup(struct drbd_resource *resource);
|
||||
|
||||
void drbd_debugfs_connection_add(struct drbd_connection *connection);
|
||||
void drbd_debugfs_connection_cleanup(struct drbd_connection *connection);
|
||||
|
||||
void drbd_debugfs_device_add(struct drbd_device *device);
|
||||
void drbd_debugfs_device_cleanup(struct drbd_device *device);
|
||||
|
||||
void drbd_debugfs_peer_device_add(struct drbd_peer_device *peer_device);
|
||||
void drbd_debugfs_peer_device_cleanup(struct drbd_peer_device *peer_device);
|
||||
#else
|
||||
|
||||
static inline int __init drbd_debugfs_init(void) { return -ENODEV; }
|
||||
static inline void drbd_debugfs_cleanup(void) { }
|
||||
|
||||
static inline void drbd_debugfs_resource_add(struct drbd_resource *resource) { }
|
||||
static inline void drbd_debugfs_resource_cleanup(struct drbd_resource *resource) { }
|
||||
|
||||
static inline void drbd_debugfs_connection_add(struct drbd_connection *connection) { }
|
||||
static inline void drbd_debugfs_connection_cleanup(struct drbd_connection *connection) { }
|
||||
|
||||
static inline void drbd_debugfs_device_add(struct drbd_device *device) { }
|
||||
static inline void drbd_debugfs_device_cleanup(struct drbd_device *device) { }
|
||||
|
||||
static inline void drbd_debugfs_peer_device_add(struct drbd_peer_device *peer_device) { }
|
||||
static inline void drbd_debugfs_peer_device_cleanup(struct drbd_peer_device *peer_device) { }
|
||||
|
||||
#endif
|
||||
+258
-137
File diff suppressed because it is too large
Load Diff
@@ -10,7 +10,9 @@ struct drbd_interval {
|
||||
unsigned int size; /* size in bytes */
|
||||
sector_t end; /* highest interval end in subtree */
|
||||
int local:1 /* local or remote request? */;
|
||||
int waiting:1;
|
||||
int waiting:1; /* someone is waiting for this to complete */
|
||||
int completed:1; /* this has been completed already;
|
||||
* ignore for conflict detection */
|
||||
};
|
||||
|
||||
static inline void drbd_clear_interval(struct drbd_interval *i)
|
||||
|
||||
+126
-178
File diff suppressed because it is too large
Load Diff
@@ -23,6 +23,8 @@
|
||||
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/drbd.h>
|
||||
#include <linux/in.h>
|
||||
@@ -85,7 +87,7 @@ static void drbd_adm_send_reply(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
genlmsg_end(skb, genlmsg_data(nlmsg_data(nlmsg_hdr(skb))));
|
||||
if (genlmsg_reply(skb, info))
|
||||
printk(KERN_ERR "drbd: error sending genl reply\n");
|
||||
pr_err("error sending genl reply\n");
|
||||
}
|
||||
|
||||
/* Used on a fresh "drbd_adm_prepare"d reply_skb, this cannot fail: The only
|
||||
@@ -558,8 +560,10 @@ void conn_try_outdate_peer_async(struct drbd_connection *connection)
|
||||
}
|
||||
|
||||
enum drbd_state_rv
|
||||
drbd_set_role(struct drbd_device *device, enum drbd_role new_role, int force)
|
||||
drbd_set_role(struct drbd_device *const device, enum drbd_role new_role, int force)
|
||||
{
|
||||
struct drbd_peer_device *const peer_device = first_peer_device(device);
|
||||
struct drbd_connection *const connection = peer_device ? peer_device->connection : NULL;
|
||||
const int max_tries = 4;
|
||||
enum drbd_state_rv rv = SS_UNKNOWN_ERROR;
|
||||
struct net_conf *nc;
|
||||
@@ -607,7 +611,7 @@ drbd_set_role(struct drbd_device *device, enum drbd_role new_role, int force)
|
||||
device->state.disk == D_CONSISTENT && mask.pdsk == 0) {
|
||||
D_ASSERT(device, device->state.pdsk == D_UNKNOWN);
|
||||
|
||||
if (conn_try_outdate_peer(first_peer_device(device)->connection)) {
|
||||
if (conn_try_outdate_peer(connection)) {
|
||||
val.disk = D_UP_TO_DATE;
|
||||
mask.disk = D_MASK;
|
||||
}
|
||||
@@ -617,7 +621,7 @@ drbd_set_role(struct drbd_device *device, enum drbd_role new_role, int force)
|
||||
if (rv == SS_NOTHING_TO_DO)
|
||||
goto out;
|
||||
if (rv == SS_PRIMARY_NOP && mask.pdsk == 0) {
|
||||
if (!conn_try_outdate_peer(first_peer_device(device)->connection) && force) {
|
||||
if (!conn_try_outdate_peer(connection) && force) {
|
||||
drbd_warn(device, "Forced into split brain situation!\n");
|
||||
mask.pdsk = D_MASK;
|
||||
val.pdsk = D_OUTDATED;
|
||||
@@ -630,7 +634,7 @@ drbd_set_role(struct drbd_device *device, enum drbd_role new_role, int force)
|
||||
retry at most once more in this case. */
|
||||
int timeo;
|
||||
rcu_read_lock();
|
||||
nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
|
||||
nc = rcu_dereference(connection->net_conf);
|
||||
timeo = nc ? (nc->ping_timeo + 1) * HZ / 10 : 1;
|
||||
rcu_read_unlock();
|
||||
schedule_timeout_interruptible(timeo);
|
||||
@@ -659,19 +663,17 @@ drbd_set_role(struct drbd_device *device, enum drbd_role new_role, int force)
|
||||
/* FIXME also wait for all pending P_BARRIER_ACK? */
|
||||
|
||||
if (new_role == R_SECONDARY) {
|
||||
set_disk_ro(device->vdisk, true);
|
||||
if (get_ldev(device)) {
|
||||
device->ldev->md.uuid[UI_CURRENT] &= ~(u64)1;
|
||||
put_ldev(device);
|
||||
}
|
||||
} else {
|
||||
/* Called from drbd_adm_set_role only.
|
||||
* We are still holding the conf_update mutex. */
|
||||
nc = first_peer_device(device)->connection->net_conf;
|
||||
mutex_lock(&device->resource->conf_update);
|
||||
nc = connection->net_conf;
|
||||
if (nc)
|
||||
nc->discard_my_data = 0; /* without copy; single bit op is atomic */
|
||||
mutex_unlock(&device->resource->conf_update);
|
||||
|
||||
set_disk_ro(device->vdisk, false);
|
||||
if (get_ldev(device)) {
|
||||
if (((device->state.conn < C_CONNECTED ||
|
||||
device->state.pdsk <= D_FAILED)
|
||||
@@ -689,12 +691,12 @@ drbd_set_role(struct drbd_device *device, enum drbd_role new_role, int force)
|
||||
if (device->state.conn >= C_WF_REPORT_PARAMS) {
|
||||
/* if this was forced, we should consider sync */
|
||||
if (forced)
|
||||
drbd_send_uuids(first_peer_device(device));
|
||||
drbd_send_current_state(first_peer_device(device));
|
||||
drbd_send_uuids(peer_device);
|
||||
drbd_send_current_state(peer_device);
|
||||
}
|
||||
|
||||
drbd_md_sync(device);
|
||||
|
||||
set_disk_ro(device->vdisk, new_role == R_SECONDARY);
|
||||
kobject_uevent(&disk_to_dev(device->vdisk)->kobj, KOBJ_CHANGE);
|
||||
out:
|
||||
mutex_unlock(device->state_mutex);
|
||||
@@ -891,7 +893,7 @@ drbd_determine_dev_size(struct drbd_device *device, enum dds_flags flags, struct
|
||||
* still lock the act_log to not trigger ASSERTs there.
|
||||
*/
|
||||
drbd_suspend_io(device);
|
||||
buffer = drbd_md_get_buffer(device); /* Lock meta-data IO */
|
||||
buffer = drbd_md_get_buffer(device, __func__); /* Lock meta-data IO */
|
||||
if (!buffer) {
|
||||
drbd_resume_io(device);
|
||||
return DS_ERROR;
|
||||
@@ -971,6 +973,10 @@ drbd_determine_dev_size(struct drbd_device *device, enum dds_flags flags, struct
|
||||
if (la_size_changed || md_moved || rs) {
|
||||
u32 prev_flags;
|
||||
|
||||
/* We do some synchronous IO below, which may take some time.
|
||||
* Clear the timer, to avoid scary "timer expired!" messages,
|
||||
* "Superblock" is written out at least twice below, anyways. */
|
||||
del_timer(&device->md_sync_timer);
|
||||
drbd_al_shrink(device); /* All extents inactive. */
|
||||
|
||||
prev_flags = md->flags;
|
||||
@@ -1116,15 +1122,16 @@ static int drbd_check_al_size(struct drbd_device *device, struct disk_conf *dc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void drbd_setup_queue_param(struct drbd_device *device, unsigned int max_bio_size)
|
||||
static void drbd_setup_queue_param(struct drbd_device *device, struct drbd_backing_dev *bdev,
|
||||
unsigned int max_bio_size)
|
||||
{
|
||||
struct request_queue * const q = device->rq_queue;
|
||||
unsigned int max_hw_sectors = max_bio_size >> 9;
|
||||
unsigned int max_segments = 0;
|
||||
struct request_queue *b = NULL;
|
||||
|
||||
if (get_ldev_if_state(device, D_ATTACHING)) {
|
||||
b = device->ldev->backing_bdev->bd_disk->queue;
|
||||
if (bdev) {
|
||||
b = bdev->backing_bdev->bd_disk->queue;
|
||||
|
||||
max_hw_sectors = min(queue_max_hw_sectors(b), max_bio_size >> 9);
|
||||
rcu_read_lock();
|
||||
@@ -1169,11 +1176,10 @@ static void drbd_setup_queue_param(struct drbd_device *device, unsigned int max_
|
||||
b->backing_dev_info.ra_pages);
|
||||
q->backing_dev_info.ra_pages = b->backing_dev_info.ra_pages;
|
||||
}
|
||||
put_ldev(device);
|
||||
}
|
||||
}
|
||||
|
||||
void drbd_reconsider_max_bio_size(struct drbd_device *device)
|
||||
void drbd_reconsider_max_bio_size(struct drbd_device *device, struct drbd_backing_dev *bdev)
|
||||
{
|
||||
unsigned int now, new, local, peer;
|
||||
|
||||
@@ -1181,10 +1187,9 @@ void drbd_reconsider_max_bio_size(struct drbd_device *device)
|
||||
local = device->local_max_bio_size; /* Eventually last known value, from volatile memory */
|
||||
peer = device->peer_max_bio_size; /* Eventually last known value, from meta data */
|
||||
|
||||
if (get_ldev_if_state(device, D_ATTACHING)) {
|
||||
local = queue_max_hw_sectors(device->ldev->backing_bdev->bd_disk->queue) << 9;
|
||||
if (bdev) {
|
||||
local = queue_max_hw_sectors(bdev->backing_bdev->bd_disk->queue) << 9;
|
||||
device->local_max_bio_size = local;
|
||||
put_ldev(device);
|
||||
}
|
||||
local = min(local, DRBD_MAX_BIO_SIZE);
|
||||
|
||||
@@ -1217,7 +1222,7 @@ void drbd_reconsider_max_bio_size(struct drbd_device *device)
|
||||
if (new != now)
|
||||
drbd_info(device, "max BIO size = %u\n", new);
|
||||
|
||||
drbd_setup_queue_param(device, new);
|
||||
drbd_setup_queue_param(device, bdev, new);
|
||||
}
|
||||
|
||||
/* Starts the worker thread */
|
||||
@@ -1299,6 +1304,13 @@ static unsigned int drbd_al_extents_max(struct drbd_backing_dev *bdev)
|
||||
return (al_size_4k - 1) * AL_CONTEXT_PER_TRANSACTION;
|
||||
}
|
||||
|
||||
static bool write_ordering_changed(struct disk_conf *a, struct disk_conf *b)
|
||||
{
|
||||
return a->disk_barrier != b->disk_barrier ||
|
||||
a->disk_flushes != b->disk_flushes ||
|
||||
a->disk_drain != b->disk_drain;
|
||||
}
|
||||
|
||||
int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct drbd_config_context adm_ctx;
|
||||
@@ -1405,7 +1417,8 @@ int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info)
|
||||
else
|
||||
set_bit(MD_NO_FUA, &device->flags);
|
||||
|
||||
drbd_bump_write_ordering(first_peer_device(device)->connection, WO_bdev_flush);
|
||||
if (write_ordering_changed(old_disk_conf, new_disk_conf))
|
||||
drbd_bump_write_ordering(device->resource, NULL, WO_bdev_flush);
|
||||
|
||||
drbd_md_sync(device);
|
||||
|
||||
@@ -1440,6 +1453,8 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct drbd_config_context adm_ctx;
|
||||
struct drbd_device *device;
|
||||
struct drbd_peer_device *peer_device;
|
||||
struct drbd_connection *connection;
|
||||
int err;
|
||||
enum drbd_ret_code retcode;
|
||||
enum determine_dev_size dd;
|
||||
@@ -1462,7 +1477,9 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
device = adm_ctx.device;
|
||||
mutex_lock(&adm_ctx.resource->adm_mutex);
|
||||
conn_reconfig_start(first_peer_device(device)->connection);
|
||||
peer_device = first_peer_device(device);
|
||||
connection = peer_device ? peer_device->connection : NULL;
|
||||
conn_reconfig_start(connection);
|
||||
|
||||
/* if you want to reconfigure, please tear down first */
|
||||
if (device->state.disk > D_DISKLESS) {
|
||||
@@ -1473,7 +1490,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
|
||||
* drbd_ldev_destroy is done already, we may end up here very fast,
|
||||
* e.g. if someone calls attach from the on-io-error handler,
|
||||
* to realize a "hot spare" feature (not that I'd recommend that) */
|
||||
wait_event(device->misc_wait, !atomic_read(&device->local_cnt));
|
||||
wait_event(device->misc_wait, !test_bit(GOING_DISKLESS, &device->flags));
|
||||
|
||||
/* make sure there is no leftover from previous force-detach attempts */
|
||||
clear_bit(FORCE_DETACH, &device->flags);
|
||||
@@ -1529,7 +1546,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
|
||||
goto fail;
|
||||
|
||||
rcu_read_lock();
|
||||
nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
|
||||
nc = rcu_dereference(connection->net_conf);
|
||||
if (nc) {
|
||||
if (new_disk_conf->fencing == FP_STONITH && nc->wire_protocol == DRBD_PROT_A) {
|
||||
rcu_read_unlock();
|
||||
@@ -1649,7 +1666,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
|
||||
*/
|
||||
wait_event(device->misc_wait, !atomic_read(&device->ap_pending_cnt) || drbd_suspended(device));
|
||||
/* and for any other previously queued work */
|
||||
drbd_flush_workqueue(&first_peer_device(device)->connection->sender_work);
|
||||
drbd_flush_workqueue(&connection->sender_work);
|
||||
|
||||
rv = _drbd_request_state(device, NS(disk, D_ATTACHING), CS_VERBOSE);
|
||||
retcode = rv; /* FIXME: Type mismatch. */
|
||||
@@ -1710,7 +1727,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
|
||||
new_disk_conf = NULL;
|
||||
new_plan = NULL;
|
||||
|
||||
drbd_bump_write_ordering(first_peer_device(device)->connection, WO_bdev_flush);
|
||||
drbd_bump_write_ordering(device->resource, device->ldev, WO_bdev_flush);
|
||||
|
||||
if (drbd_md_test_flag(device->ldev, MDF_CRASHED_PRIMARY))
|
||||
set_bit(CRASHED_PRIMARY, &device->flags);
|
||||
@@ -1726,7 +1743,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
|
||||
device->read_cnt = 0;
|
||||
device->writ_cnt = 0;
|
||||
|
||||
drbd_reconsider_max_bio_size(device);
|
||||
drbd_reconsider_max_bio_size(device, device->ldev);
|
||||
|
||||
/* If I am currently not R_PRIMARY,
|
||||
* but meta data primary indicator is set,
|
||||
@@ -1845,7 +1862,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
kobject_uevent(&disk_to_dev(device->vdisk)->kobj, KOBJ_CHANGE);
|
||||
put_ldev(device);
|
||||
conn_reconfig_done(first_peer_device(device)->connection);
|
||||
conn_reconfig_done(connection);
|
||||
mutex_unlock(&adm_ctx.resource->adm_mutex);
|
||||
drbd_adm_finish(&adm_ctx, info, retcode);
|
||||
return 0;
|
||||
@@ -1856,7 +1873,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
|
||||
drbd_force_state(device, NS(disk, D_DISKLESS));
|
||||
drbd_md_sync(device);
|
||||
fail:
|
||||
conn_reconfig_done(first_peer_device(device)->connection);
|
||||
conn_reconfig_done(connection);
|
||||
if (nbc) {
|
||||
if (nbc->backing_bdev)
|
||||
blkdev_put(nbc->backing_bdev,
|
||||
@@ -1888,7 +1905,7 @@ static int adm_detach(struct drbd_device *device, int force)
|
||||
}
|
||||
|
||||
drbd_suspend_io(device); /* so no-one is stuck in drbd_al_begin_io */
|
||||
drbd_md_get_buffer(device); /* make sure there is no in-flight meta-data IO */
|
||||
drbd_md_get_buffer(device, __func__); /* make sure there is no in-flight meta-data IO */
|
||||
retcode = drbd_request_state(device, NS(disk, D_FAILED));
|
||||
drbd_md_put_buffer(device);
|
||||
/* D_FAILED will transition to DISKLESS. */
|
||||
@@ -2654,8 +2671,13 @@ int drbd_adm_invalidate(struct sk_buff *skb, struct genl_info *info)
|
||||
if (retcode != NO_ERROR)
|
||||
goto out;
|
||||
|
||||
mutex_lock(&adm_ctx.resource->adm_mutex);
|
||||
device = adm_ctx.device;
|
||||
if (!get_ldev(device)) {
|
||||
retcode = ERR_NO_DISK;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&adm_ctx.resource->adm_mutex);
|
||||
|
||||
/* If there is still bitmap IO pending, probably because of a previous
|
||||
* resync just being finished, wait for it before requesting a new resync.
|
||||
@@ -2679,6 +2701,7 @@ int drbd_adm_invalidate(struct sk_buff *skb, struct genl_info *info)
|
||||
retcode = drbd_request_state(device, NS(conn, C_STARTING_SYNC_T));
|
||||
drbd_resume_io(device);
|
||||
mutex_unlock(&adm_ctx.resource->adm_mutex);
|
||||
put_ldev(device);
|
||||
out:
|
||||
drbd_adm_finish(&adm_ctx, info, retcode);
|
||||
return 0;
|
||||
@@ -2704,7 +2727,7 @@ out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drbd_bmio_set_susp_al(struct drbd_device *device)
|
||||
static int drbd_bmio_set_susp_al(struct drbd_device *device) __must_hold(local)
|
||||
{
|
||||
int rv;
|
||||
|
||||
@@ -2725,8 +2748,13 @@ int drbd_adm_invalidate_peer(struct sk_buff *skb, struct genl_info *info)
|
||||
if (retcode != NO_ERROR)
|
||||
goto out;
|
||||
|
||||
mutex_lock(&adm_ctx.resource->adm_mutex);
|
||||
device = adm_ctx.device;
|
||||
if (!get_ldev(device)) {
|
||||
retcode = ERR_NO_DISK;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&adm_ctx.resource->adm_mutex);
|
||||
|
||||
/* If there is still bitmap IO pending, probably because of a previous
|
||||
* resync just being finished, wait for it before requesting a new resync.
|
||||
@@ -2753,6 +2781,7 @@ int drbd_adm_invalidate_peer(struct sk_buff *skb, struct genl_info *info)
|
||||
retcode = drbd_request_state(device, NS(conn, C_STARTING_SYNC_S));
|
||||
drbd_resume_io(device);
|
||||
mutex_unlock(&adm_ctx.resource->adm_mutex);
|
||||
put_ldev(device);
|
||||
out:
|
||||
drbd_adm_finish(&adm_ctx, info, retcode);
|
||||
return 0;
|
||||
@@ -2892,7 +2921,7 @@ static struct drbd_connection *the_only_connection(struct drbd_resource *resourc
|
||||
return list_first_entry(&resource->connections, struct drbd_connection, connections);
|
||||
}
|
||||
|
||||
int nla_put_status_info(struct sk_buff *skb, struct drbd_device *device,
|
||||
static int nla_put_status_info(struct sk_buff *skb, struct drbd_device *device,
|
||||
const struct sib_info *sib)
|
||||
{
|
||||
struct drbd_resource *resource = device->resource;
|
||||
@@ -3622,13 +3651,6 @@ void drbd_bcast_event(struct drbd_device *device, const struct sib_info *sib)
|
||||
unsigned seq;
|
||||
int err = -ENOMEM;
|
||||
|
||||
if (sib->sib_reason == SIB_SYNC_PROGRESS) {
|
||||
if (time_after(jiffies, device->rs_last_bcast + HZ))
|
||||
device->rs_last_bcast = jiffies;
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
seq = atomic_inc_return(&drbd_genl_seq);
|
||||
msg = genlmsg_new(NLMSG_GOODSIZE, GFP_NOIO);
|
||||
if (!msg)
|
||||
|
||||
@@ -60,20 +60,65 @@ static void seq_printf_with_thousands_grouping(struct seq_file *seq, long v)
|
||||
seq_printf(seq, "%ld", v);
|
||||
}
|
||||
|
||||
static void drbd_get_syncer_progress(struct drbd_device *device,
|
||||
union drbd_dev_state state, unsigned long *rs_total,
|
||||
unsigned long *bits_left, unsigned int *per_mil_done)
|
||||
{
|
||||
/* this is to break it at compile time when we change that, in case we
|
||||
* want to support more than (1<<32) bits on a 32bit arch. */
|
||||
typecheck(unsigned long, device->rs_total);
|
||||
*rs_total = device->rs_total;
|
||||
|
||||
/* note: both rs_total and rs_left are in bits, i.e. in
|
||||
* units of BM_BLOCK_SIZE.
|
||||
* for the percentage, we don't care. */
|
||||
|
||||
if (state.conn == C_VERIFY_S || state.conn == C_VERIFY_T)
|
||||
*bits_left = device->ov_left;
|
||||
else
|
||||
*bits_left = drbd_bm_total_weight(device) - device->rs_failed;
|
||||
/* >> 10 to prevent overflow,
|
||||
* +1 to prevent division by zero */
|
||||
if (*bits_left > *rs_total) {
|
||||
/* D'oh. Maybe a logic bug somewhere. More likely just a race
|
||||
* between state change and reset of rs_total.
|
||||
*/
|
||||
*bits_left = *rs_total;
|
||||
*per_mil_done = *rs_total ? 0 : 1000;
|
||||
} else {
|
||||
/* Make sure the division happens in long context.
|
||||
* We allow up to one petabyte storage right now,
|
||||
* at a granularity of 4k per bit that is 2**38 bits.
|
||||
* After shift right and multiplication by 1000,
|
||||
* this should still fit easily into a 32bit long,
|
||||
* so we don't need a 64bit division on 32bit arch.
|
||||
* Note: currently we don't support such large bitmaps on 32bit
|
||||
* arch anyways, but no harm done to be prepared for it here.
|
||||
*/
|
||||
unsigned int shift = *rs_total > UINT_MAX ? 16 : 10;
|
||||
unsigned long left = *bits_left >> shift;
|
||||
unsigned long total = 1UL + (*rs_total >> shift);
|
||||
unsigned long tmp = 1000UL - left * 1000UL/total;
|
||||
*per_mil_done = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*lge
|
||||
* progress bars shamelessly adapted from driver/md/md.c
|
||||
* output looks like
|
||||
* [=====>..............] 33.5% (23456/123456)
|
||||
* finish: 2:20:20 speed: 6,345 (6,456) K/sec
|
||||
*/
|
||||
static void drbd_syncer_progress(struct drbd_device *device, struct seq_file *seq)
|
||||
static void drbd_syncer_progress(struct drbd_device *device, struct seq_file *seq,
|
||||
union drbd_dev_state state)
|
||||
{
|
||||
unsigned long db, dt, dbdt, rt, rs_left;
|
||||
unsigned long db, dt, dbdt, rt, rs_total, rs_left;
|
||||
unsigned int res;
|
||||
int i, x, y;
|
||||
int stalled = 0;
|
||||
|
||||
drbd_get_syncer_progress(device, &rs_left, &res);
|
||||
drbd_get_syncer_progress(device, state, &rs_total, &rs_left, &res);
|
||||
|
||||
x = res/50;
|
||||
y = 20-x;
|
||||
@@ -85,21 +130,21 @@ static void drbd_syncer_progress(struct drbd_device *device, struct seq_file *se
|
||||
seq_printf(seq, ".");
|
||||
seq_printf(seq, "] ");
|
||||
|
||||
if (device->state.conn == C_VERIFY_S || device->state.conn == C_VERIFY_T)
|
||||
if (state.conn == C_VERIFY_S || state.conn == C_VERIFY_T)
|
||||
seq_printf(seq, "verified:");
|
||||
else
|
||||
seq_printf(seq, "sync'ed:");
|
||||
seq_printf(seq, "%3u.%u%% ", res / 10, res % 10);
|
||||
|
||||
/* if more than a few GB, display in MB */
|
||||
if (device->rs_total > (4UL << (30 - BM_BLOCK_SHIFT)))
|
||||
if (rs_total > (4UL << (30 - BM_BLOCK_SHIFT)))
|
||||
seq_printf(seq, "(%lu/%lu)M",
|
||||
(unsigned long) Bit2KB(rs_left >> 10),
|
||||
(unsigned long) Bit2KB(device->rs_total >> 10));
|
||||
(unsigned long) Bit2KB(rs_total >> 10));
|
||||
else
|
||||
seq_printf(seq, "(%lu/%lu)K\n\t",
|
||||
(unsigned long) Bit2KB(rs_left),
|
||||
(unsigned long) Bit2KB(device->rs_total));
|
||||
(unsigned long) Bit2KB(rs_total));
|
||||
|
||||
/* see drivers/md/md.c
|
||||
* We do not want to overflow, so the order of operands and
|
||||
@@ -150,13 +195,13 @@ static void drbd_syncer_progress(struct drbd_device *device, struct seq_file *se
|
||||
dt = (jiffies - device->rs_start - device->rs_paused) / HZ;
|
||||
if (dt == 0)
|
||||
dt = 1;
|
||||
db = device->rs_total - rs_left;
|
||||
db = rs_total - rs_left;
|
||||
dbdt = Bit2KB(db/dt);
|
||||
seq_printf_with_thousands_grouping(seq, dbdt);
|
||||
seq_printf(seq, ")");
|
||||
|
||||
if (device->state.conn == C_SYNC_TARGET ||
|
||||
device->state.conn == C_VERIFY_S) {
|
||||
if (state.conn == C_SYNC_TARGET ||
|
||||
state.conn == C_VERIFY_S) {
|
||||
seq_printf(seq, " want: ");
|
||||
seq_printf_with_thousands_grouping(seq, device->c_sync_rate);
|
||||
}
|
||||
@@ -168,8 +213,8 @@ static void drbd_syncer_progress(struct drbd_device *device, struct seq_file *se
|
||||
unsigned long bm_bits = drbd_bm_bits(device);
|
||||
unsigned long bit_pos;
|
||||
unsigned long long stop_sector = 0;
|
||||
if (device->state.conn == C_VERIFY_S ||
|
||||
device->state.conn == C_VERIFY_T) {
|
||||
if (state.conn == C_VERIFY_S ||
|
||||
state.conn == C_VERIFY_T) {
|
||||
bit_pos = bm_bits - device->ov_left;
|
||||
if (verify_can_do_stop_sector(device))
|
||||
stop_sector = device->ov_stop_sector;
|
||||
@@ -188,22 +233,13 @@ static void drbd_syncer_progress(struct drbd_device *device, struct seq_file *se
|
||||
}
|
||||
}
|
||||
|
||||
static void resync_dump_detail(struct seq_file *seq, struct lc_element *e)
|
||||
{
|
||||
struct bm_extent *bme = lc_entry(e, struct bm_extent, lce);
|
||||
|
||||
seq_printf(seq, "%5d %s %s\n", bme->rs_left,
|
||||
bme->flags & BME_NO_WRITES ? "NO_WRITES" : "---------",
|
||||
bme->flags & BME_LOCKED ? "LOCKED" : "------"
|
||||
);
|
||||
}
|
||||
|
||||
static int drbd_seq_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
int i, prev_i = -1;
|
||||
const char *sn;
|
||||
struct drbd_device *device;
|
||||
struct net_conf *nc;
|
||||
union drbd_dev_state state;
|
||||
char wp;
|
||||
|
||||
static char write_ordering_chars[] = {
|
||||
@@ -241,11 +277,12 @@ static int drbd_seq_show(struct seq_file *seq, void *v)
|
||||
seq_printf(seq, "\n");
|
||||
prev_i = i;
|
||||
|
||||
sn = drbd_conn_str(device->state.conn);
|
||||
state = device->state;
|
||||
sn = drbd_conn_str(state.conn);
|
||||
|
||||
if (device->state.conn == C_STANDALONE &&
|
||||
device->state.disk == D_DISKLESS &&
|
||||
device->state.role == R_SECONDARY) {
|
||||
if (state.conn == C_STANDALONE &&
|
||||
state.disk == D_DISKLESS &&
|
||||
state.role == R_SECONDARY) {
|
||||
seq_printf(seq, "%2d: cs:Unconfigured\n", i);
|
||||
} else {
|
||||
/* reset device->congestion_reason */
|
||||
@@ -258,15 +295,15 @@ static int drbd_seq_show(struct seq_file *seq, void *v)
|
||||
" ns:%u nr:%u dw:%u dr:%u al:%u bm:%u "
|
||||
"lo:%d pe:%d ua:%d ap:%d ep:%d wo:%c",
|
||||
i, sn,
|
||||
drbd_role_str(device->state.role),
|
||||
drbd_role_str(device->state.peer),
|
||||
drbd_disk_str(device->state.disk),
|
||||
drbd_disk_str(device->state.pdsk),
|
||||
drbd_role_str(state.role),
|
||||
drbd_role_str(state.peer),
|
||||
drbd_disk_str(state.disk),
|
||||
drbd_disk_str(state.pdsk),
|
||||
wp,
|
||||
drbd_suspended(device) ? 's' : 'r',
|
||||
device->state.aftr_isp ? 'a' : '-',
|
||||
device->state.peer_isp ? 'p' : '-',
|
||||
device->state.user_isp ? 'u' : '-',
|
||||
state.aftr_isp ? 'a' : '-',
|
||||
state.peer_isp ? 'p' : '-',
|
||||
state.user_isp ? 'u' : '-',
|
||||
device->congestion_reason ?: '-',
|
||||
test_bit(AL_SUSPENDED, &device->flags) ? 's' : '-',
|
||||
device->send_cnt/2,
|
||||
@@ -281,17 +318,17 @@ static int drbd_seq_show(struct seq_file *seq, void *v)
|
||||
atomic_read(&device->unacked_cnt),
|
||||
atomic_read(&device->ap_bio_cnt),
|
||||
first_peer_device(device)->connection->epochs,
|
||||
write_ordering_chars[first_peer_device(device)->connection->write_ordering]
|
||||
write_ordering_chars[device->resource->write_ordering]
|
||||
);
|
||||
seq_printf(seq, " oos:%llu\n",
|
||||
Bit2KB((unsigned long long)
|
||||
drbd_bm_total_weight(device)));
|
||||
}
|
||||
if (device->state.conn == C_SYNC_SOURCE ||
|
||||
device->state.conn == C_SYNC_TARGET ||
|
||||
device->state.conn == C_VERIFY_S ||
|
||||
device->state.conn == C_VERIFY_T)
|
||||
drbd_syncer_progress(device, seq);
|
||||
if (state.conn == C_SYNC_SOURCE ||
|
||||
state.conn == C_SYNC_TARGET ||
|
||||
state.conn == C_VERIFY_S ||
|
||||
state.conn == C_VERIFY_T)
|
||||
drbd_syncer_progress(device, seq, state);
|
||||
|
||||
if (proc_details >= 1 && get_ldev_if_state(device, D_FAILED)) {
|
||||
lc_seq_printf_stats(seq, device->resync);
|
||||
@@ -299,12 +336,8 @@ static int drbd_seq_show(struct seq_file *seq, void *v)
|
||||
put_ldev(device);
|
||||
}
|
||||
|
||||
if (proc_details >= 2) {
|
||||
if (device->resync) {
|
||||
lc_seq_dump_details(seq, device->resync, "rs_left",
|
||||
resync_dump_detail);
|
||||
}
|
||||
}
|
||||
if (proc_details >= 2)
|
||||
seq_printf(seq, "\tblocked on activity log: %d\n", atomic_read(&device->ap_actlog_cnt));
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
@@ -316,7 +349,7 @@ static int drbd_proc_open(struct inode *inode, struct file *file)
|
||||
int err;
|
||||
|
||||
if (try_module_get(THIS_MODULE)) {
|
||||
err = single_open(file, drbd_seq_show, PDE_DATA(inode));
|
||||
err = single_open(file, drbd_seq_show, NULL);
|
||||
if (err)
|
||||
module_put(THIS_MODULE);
|
||||
return err;
|
||||
|
||||
+212
-106
File diff suppressed because it is too large
Load Diff
+361
-164
File diff suppressed because it is too large
Load Diff
@@ -288,6 +288,7 @@ extern void complete_master_bio(struct drbd_device *device,
|
||||
extern void request_timer_fn(unsigned long data);
|
||||
extern void tl_restart(struct drbd_connection *connection, enum drbd_req_event what);
|
||||
extern void _tl_restart(struct drbd_connection *connection, enum drbd_req_event what);
|
||||
extern void tl_abort_disk_io(struct drbd_device *device);
|
||||
|
||||
/* this is in drbd_main.c */
|
||||
extern void drbd_restart_request(struct drbd_request *req);
|
||||
|
||||
@@ -410,7 +410,7 @@ _drbd_request_state(struct drbd_device *device, union drbd_state mask,
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void print_st(struct drbd_device *device, char *name, union drbd_state ns)
|
||||
static void print_st(struct drbd_device *device, const char *name, union drbd_state ns)
|
||||
{
|
||||
drbd_err(device, " %s = { cs:%s ro:%s/%s ds:%s/%s %c%c%c%c%c%c }\n",
|
||||
name,
|
||||
@@ -952,11 +952,12 @@ enum drbd_state_rv
|
||||
__drbd_set_state(struct drbd_device *device, union drbd_state ns,
|
||||
enum chg_state_flags flags, struct completion *done)
|
||||
{
|
||||
struct drbd_peer_device *peer_device = first_peer_device(device);
|
||||
struct drbd_connection *connection = peer_device ? peer_device->connection : NULL;
|
||||
union drbd_state os;
|
||||
enum drbd_state_rv rv = SS_SUCCESS;
|
||||
enum sanitize_state_warnings ssw;
|
||||
struct after_state_chg_work *ascw;
|
||||
bool did_remote, should_do_remote;
|
||||
|
||||
os = drbd_read_state(device);
|
||||
|
||||
@@ -978,9 +979,9 @@ __drbd_set_state(struct drbd_device *device, union drbd_state ns,
|
||||
this happen...*/
|
||||
|
||||
if (is_valid_state(device, os) == rv)
|
||||
rv = is_valid_soft_transition(os, ns, first_peer_device(device)->connection);
|
||||
rv = is_valid_soft_transition(os, ns, connection);
|
||||
} else
|
||||
rv = is_valid_soft_transition(os, ns, first_peer_device(device)->connection);
|
||||
rv = is_valid_soft_transition(os, ns, connection);
|
||||
}
|
||||
|
||||
if (rv < SS_SUCCESS) {
|
||||
@@ -997,7 +998,7 @@ __drbd_set_state(struct drbd_device *device, union drbd_state ns,
|
||||
sanitize_state(). Only display it here if we where not called from
|
||||
_conn_request_state() */
|
||||
if (!(flags & CS_DC_SUSP))
|
||||
conn_pr_state_change(first_peer_device(device)->connection, os, ns,
|
||||
conn_pr_state_change(connection, os, ns,
|
||||
(flags & ~CS_DC_MASK) | CS_DC_SUSP);
|
||||
|
||||
/* if we are going -> D_FAILED or D_DISKLESS, grab one extra reference
|
||||
@@ -1008,28 +1009,35 @@ __drbd_set_state(struct drbd_device *device, union drbd_state ns,
|
||||
(os.disk != D_DISKLESS && ns.disk == D_DISKLESS))
|
||||
atomic_inc(&device->local_cnt);
|
||||
|
||||
did_remote = drbd_should_do_remote(device->state);
|
||||
if (!is_sync_state(os.conn) && is_sync_state(ns.conn))
|
||||
clear_bit(RS_DONE, &device->flags);
|
||||
|
||||
/* changes to local_cnt and device flags should be visible before
|
||||
* changes to state, which again should be visible before anything else
|
||||
* depending on that change happens. */
|
||||
smp_wmb();
|
||||
device->state.i = ns.i;
|
||||
should_do_remote = drbd_should_do_remote(device->state);
|
||||
device->resource->susp = ns.susp;
|
||||
device->resource->susp_nod = ns.susp_nod;
|
||||
device->resource->susp_fen = ns.susp_fen;
|
||||
smp_wmb();
|
||||
|
||||
/* put replicated vs not-replicated requests in seperate epochs */
|
||||
if (did_remote != should_do_remote)
|
||||
start_new_tl_epoch(first_peer_device(device)->connection);
|
||||
if (drbd_should_do_remote((union drbd_dev_state)os.i) !=
|
||||
drbd_should_do_remote((union drbd_dev_state)ns.i))
|
||||
start_new_tl_epoch(connection);
|
||||
|
||||
if (os.disk == D_ATTACHING && ns.disk >= D_NEGOTIATING)
|
||||
drbd_print_uuids(device, "attached to UUIDs");
|
||||
|
||||
/* Wake up role changes, that were delayed because of connection establishing */
|
||||
if (os.conn == C_WF_REPORT_PARAMS && ns.conn != C_WF_REPORT_PARAMS &&
|
||||
no_peer_wf_report_params(first_peer_device(device)->connection))
|
||||
clear_bit(STATE_SENT, &first_peer_device(device)->connection->flags);
|
||||
no_peer_wf_report_params(connection))
|
||||
clear_bit(STATE_SENT, &connection->flags);
|
||||
|
||||
wake_up(&device->misc_wait);
|
||||
wake_up(&device->state_wait);
|
||||
wake_up(&first_peer_device(device)->connection->ping_wait);
|
||||
wake_up(&connection->ping_wait);
|
||||
|
||||
/* Aborted verify run, or we reached the stop sector.
|
||||
* Log the last position, unless end-of-device. */
|
||||
@@ -1118,21 +1126,21 @@ __drbd_set_state(struct drbd_device *device, union drbd_state ns,
|
||||
|
||||
/* Receiver should clean up itself */
|
||||
if (os.conn != C_DISCONNECTING && ns.conn == C_DISCONNECTING)
|
||||
drbd_thread_stop_nowait(&first_peer_device(device)->connection->receiver);
|
||||
drbd_thread_stop_nowait(&connection->receiver);
|
||||
|
||||
/* Now the receiver finished cleaning up itself, it should die */
|
||||
if (os.conn != C_STANDALONE && ns.conn == C_STANDALONE)
|
||||
drbd_thread_stop_nowait(&first_peer_device(device)->connection->receiver);
|
||||
drbd_thread_stop_nowait(&connection->receiver);
|
||||
|
||||
/* Upon network failure, we need to restart the receiver. */
|
||||
if (os.conn > C_WF_CONNECTION &&
|
||||
ns.conn <= C_TEAR_DOWN && ns.conn >= C_TIMEOUT)
|
||||
drbd_thread_restart_nowait(&first_peer_device(device)->connection->receiver);
|
||||
drbd_thread_restart_nowait(&connection->receiver);
|
||||
|
||||
/* Resume AL writing if we get a connection */
|
||||
if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) {
|
||||
drbd_resume_al(device);
|
||||
first_peer_device(device)->connection->connect_cnt++;
|
||||
connection->connect_cnt++;
|
||||
}
|
||||
|
||||
/* remember last attach time so request_timer_fn() won't
|
||||
@@ -1150,7 +1158,7 @@ __drbd_set_state(struct drbd_device *device, union drbd_state ns,
|
||||
ascw->w.cb = w_after_state_ch;
|
||||
ascw->device = device;
|
||||
ascw->done = done;
|
||||
drbd_queue_work(&first_peer_device(device)->connection->sender_work,
|
||||
drbd_queue_work(&connection->sender_work,
|
||||
&ascw->w);
|
||||
} else {
|
||||
drbd_err(device, "Could not kmalloc an ascw\n");
|
||||
@@ -1222,13 +1230,16 @@ static void after_state_ch(struct drbd_device *device, union drbd_state os,
|
||||
union drbd_state ns, enum chg_state_flags flags)
|
||||
{
|
||||
struct drbd_resource *resource = device->resource;
|
||||
struct drbd_peer_device *peer_device = first_peer_device(device);
|
||||
struct drbd_connection *connection = peer_device ? peer_device->connection : NULL;
|
||||
struct sib_info sib;
|
||||
|
||||
sib.sib_reason = SIB_STATE_CHANGE;
|
||||
sib.os = os;
|
||||
sib.ns = ns;
|
||||
|
||||
if (os.conn != C_CONNECTED && ns.conn == C_CONNECTED) {
|
||||
if ((os.disk != D_UP_TO_DATE || os.pdsk != D_UP_TO_DATE)
|
||||
&& (ns.disk == D_UP_TO_DATE && ns.pdsk == D_UP_TO_DATE)) {
|
||||
clear_bit(CRASHED_PRIMARY, &device->flags);
|
||||
if (device->p_uuid)
|
||||
device->p_uuid[UI_FLAGS] &= ~((u64)2);
|
||||
@@ -1245,7 +1256,6 @@ static void after_state_ch(struct drbd_device *device, union drbd_state os,
|
||||
state change. This function might sleep */
|
||||
|
||||
if (ns.susp_nod) {
|
||||
struct drbd_connection *connection = first_peer_device(device)->connection;
|
||||
enum drbd_req_event what = NOTHING;
|
||||
|
||||
spin_lock_irq(&device->resource->req_lock);
|
||||
@@ -1267,8 +1277,6 @@ static void after_state_ch(struct drbd_device *device, union drbd_state os,
|
||||
}
|
||||
|
||||
if (ns.susp_fen) {
|
||||
struct drbd_connection *connection = first_peer_device(device)->connection;
|
||||
|
||||
spin_lock_irq(&device->resource->req_lock);
|
||||
if (resource->susp_fen && conn_lowest_conn(connection) >= C_CONNECTED) {
|
||||
/* case2: The connection was established again: */
|
||||
@@ -1294,8 +1302,8 @@ static void after_state_ch(struct drbd_device *device, union drbd_state os,
|
||||
* which is unexpected. */
|
||||
if ((os.conn != C_SYNC_SOURCE && os.conn != C_PAUSED_SYNC_S) &&
|
||||
(ns.conn == C_SYNC_SOURCE || ns.conn == C_PAUSED_SYNC_S) &&
|
||||
first_peer_device(device)->connection->agreed_pro_version >= 96 && get_ldev(device)) {
|
||||
drbd_gen_and_send_sync_uuid(first_peer_device(device));
|
||||
connection->agreed_pro_version >= 96 && get_ldev(device)) {
|
||||
drbd_gen_and_send_sync_uuid(peer_device);
|
||||
put_ldev(device);
|
||||
}
|
||||
|
||||
@@ -1309,8 +1317,8 @@ static void after_state_ch(struct drbd_device *device, union drbd_state os,
|
||||
atomic_set(&device->rs_pending_cnt, 0);
|
||||
drbd_rs_cancel_all(device);
|
||||
|
||||
drbd_send_uuids(first_peer_device(device));
|
||||
drbd_send_state(first_peer_device(device), ns);
|
||||
drbd_send_uuids(peer_device);
|
||||
drbd_send_state(peer_device, ns);
|
||||
}
|
||||
/* No point in queuing send_bitmap if we don't have a connection
|
||||
* anymore, so check also the _current_ state, not only the new state
|
||||
@@ -1335,7 +1343,7 @@ static void after_state_ch(struct drbd_device *device, union drbd_state os,
|
||||
set_bit(NEW_CUR_UUID, &device->flags);
|
||||
} else {
|
||||
drbd_uuid_new_current(device);
|
||||
drbd_send_uuids(first_peer_device(device));
|
||||
drbd_send_uuids(peer_device);
|
||||
}
|
||||
}
|
||||
put_ldev(device);
|
||||
@@ -1346,7 +1354,7 @@ static void after_state_ch(struct drbd_device *device, union drbd_state os,
|
||||
if (os.peer == R_SECONDARY && ns.peer == R_PRIMARY &&
|
||||
device->ldev->md.uuid[UI_BITMAP] == 0 && ns.disk >= D_UP_TO_DATE) {
|
||||
drbd_uuid_new_current(device);
|
||||
drbd_send_uuids(first_peer_device(device));
|
||||
drbd_send_uuids(peer_device);
|
||||
}
|
||||
/* D_DISKLESS Peer becomes secondary */
|
||||
if (os.peer == R_PRIMARY && ns.peer == R_SECONDARY)
|
||||
@@ -1373,16 +1381,16 @@ static void after_state_ch(struct drbd_device *device, union drbd_state os,
|
||||
/* Last part of the attaching process ... */
|
||||
if (ns.conn >= C_CONNECTED &&
|
||||
os.disk == D_ATTACHING && ns.disk == D_NEGOTIATING) {
|
||||
drbd_send_sizes(first_peer_device(device), 0, 0); /* to start sync... */
|
||||
drbd_send_uuids(first_peer_device(device));
|
||||
drbd_send_state(first_peer_device(device), ns);
|
||||
drbd_send_sizes(peer_device, 0, 0); /* to start sync... */
|
||||
drbd_send_uuids(peer_device);
|
||||
drbd_send_state(peer_device, ns);
|
||||
}
|
||||
|
||||
/* We want to pause/continue resync, tell peer. */
|
||||
if (ns.conn >= C_CONNECTED &&
|
||||
((os.aftr_isp != ns.aftr_isp) ||
|
||||
(os.user_isp != ns.user_isp)))
|
||||
drbd_send_state(first_peer_device(device), ns);
|
||||
drbd_send_state(peer_device, ns);
|
||||
|
||||
/* In case one of the isp bits got set, suspend other devices. */
|
||||
if ((!os.aftr_isp && !os.peer_isp && !os.user_isp) &&
|
||||
@@ -1392,10 +1400,10 @@ static void after_state_ch(struct drbd_device *device, union drbd_state os,
|
||||
/* Make sure the peer gets informed about eventual state
|
||||
changes (ISP bits) while we were in WFReportParams. */
|
||||
if (os.conn == C_WF_REPORT_PARAMS && ns.conn >= C_CONNECTED)
|
||||
drbd_send_state(first_peer_device(device), ns);
|
||||
drbd_send_state(peer_device, ns);
|
||||
|
||||
if (os.conn != C_AHEAD && ns.conn == C_AHEAD)
|
||||
drbd_send_state(first_peer_device(device), ns);
|
||||
drbd_send_state(peer_device, ns);
|
||||
|
||||
/* We are in the progress to start a full sync... */
|
||||
if ((os.conn != C_STARTING_SYNC_T && ns.conn == C_STARTING_SYNC_T) ||
|
||||
@@ -1449,7 +1457,7 @@ static void after_state_ch(struct drbd_device *device, union drbd_state os,
|
||||
drbd_disk_str(device->state.disk));
|
||||
|
||||
if (ns.conn >= C_CONNECTED)
|
||||
drbd_send_state(first_peer_device(device), ns);
|
||||
drbd_send_state(peer_device, ns);
|
||||
|
||||
drbd_rs_cancel_all(device);
|
||||
|
||||
@@ -1473,7 +1481,7 @@ static void after_state_ch(struct drbd_device *device, union drbd_state os,
|
||||
drbd_disk_str(device->state.disk));
|
||||
|
||||
if (ns.conn >= C_CONNECTED)
|
||||
drbd_send_state(first_peer_device(device), ns);
|
||||
drbd_send_state(peer_device, ns);
|
||||
/* corresponding get_ldev in __drbd_set_state
|
||||
* this may finally trigger drbd_ldev_destroy. */
|
||||
put_ldev(device);
|
||||
@@ -1481,7 +1489,7 @@ static void after_state_ch(struct drbd_device *device, union drbd_state os,
|
||||
|
||||
/* Notify peer that I had a local IO error, and did not detached.. */
|
||||
if (os.disk == D_UP_TO_DATE && ns.disk == D_INCONSISTENT && ns.conn >= C_CONNECTED)
|
||||
drbd_send_state(first_peer_device(device), ns);
|
||||
drbd_send_state(peer_device, ns);
|
||||
|
||||
/* Disks got bigger while they were detached */
|
||||
if (ns.disk > D_NEGOTIATING && ns.pdsk > D_NEGOTIATING &&
|
||||
@@ -1499,14 +1507,14 @@ static void after_state_ch(struct drbd_device *device, union drbd_state os,
|
||||
/* sync target done with resync. Explicitly notify peer, even though
|
||||
* it should (at least for non-empty resyncs) already know itself. */
|
||||
if (os.disk < D_UP_TO_DATE && os.conn >= C_SYNC_SOURCE && ns.conn == C_CONNECTED)
|
||||
drbd_send_state(first_peer_device(device), ns);
|
||||
drbd_send_state(peer_device, ns);
|
||||
|
||||
/* Verify finished, or reached stop sector. Peer did not know about
|
||||
* the stop sector, and we may even have changed the stop sector during
|
||||
* verify to interrupt/stop early. Send the new state. */
|
||||
if (os.conn == C_VERIFY_S && ns.conn == C_CONNECTED
|
||||
&& verify_can_do_stop_sector(device))
|
||||
drbd_send_state(first_peer_device(device), ns);
|
||||
drbd_send_state(peer_device, ns);
|
||||
|
||||
/* This triggers bitmap writeout of potentially still unwritten pages
|
||||
* if the resync finished cleanly, or aborted because of peer disk
|
||||
@@ -1563,7 +1571,7 @@ static int w_after_conn_state_ch(struct drbd_work *w, int unused)
|
||||
old_conf = connection->net_conf;
|
||||
connection->my_addr_len = 0;
|
||||
connection->peer_addr_len = 0;
|
||||
rcu_assign_pointer(connection->net_conf, NULL);
|
||||
RCU_INIT_POINTER(connection->net_conf, NULL);
|
||||
conn_free_crypto(connection);
|
||||
mutex_unlock(&connection->resource->conf_update);
|
||||
|
||||
@@ -1599,7 +1607,7 @@ static int w_after_conn_state_ch(struct drbd_work *w, int unused)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void conn_old_common_state(struct drbd_connection *connection, union drbd_state *pcs, enum chg_state_flags *pf)
|
||||
static void conn_old_common_state(struct drbd_connection *connection, union drbd_state *pcs, enum chg_state_flags *pf)
|
||||
{
|
||||
enum chg_state_flags flags = ~0;
|
||||
struct drbd_peer_device *peer_device;
|
||||
@@ -1688,7 +1696,7 @@ conn_is_valid_transition(struct drbd_connection *connection, union drbd_state ma
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
conn_set_state(struct drbd_connection *connection, union drbd_state mask, union drbd_state val,
|
||||
union drbd_state *pns_min, union drbd_state *pns_max, enum chg_state_flags flags)
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+84
-20
@@ -15,17 +15,22 @@
|
||||
#include <linux/numa.h>
|
||||
|
||||
#define PART_BITS 4
|
||||
#define VQ_NAME_LEN 16
|
||||
|
||||
static int major;
|
||||
static DEFINE_IDA(vd_index_ida);
|
||||
|
||||
static struct workqueue_struct *virtblk_wq;
|
||||
|
||||
struct virtio_blk_vq {
|
||||
struct virtqueue *vq;
|
||||
spinlock_t lock;
|
||||
char name[VQ_NAME_LEN];
|
||||
} ____cacheline_aligned_in_smp;
|
||||
|
||||
struct virtio_blk
|
||||
{
|
||||
struct virtio_device *vdev;
|
||||
struct virtqueue *vq;
|
||||
spinlock_t vq_lock;
|
||||
|
||||
/* The disk structure for the kernel. */
|
||||
struct gendisk *disk;
|
||||
@@ -47,6 +52,10 @@ struct virtio_blk
|
||||
|
||||
/* Ida index - used to track minor number allocations. */
|
||||
int index;
|
||||
|
||||
/* num of vqs */
|
||||
int num_vqs;
|
||||
struct virtio_blk_vq *vqs;
|
||||
};
|
||||
|
||||
struct virtblk_req
|
||||
@@ -133,14 +142,15 @@ static void virtblk_done(struct virtqueue *vq)
|
||||
{
|
||||
struct virtio_blk *vblk = vq->vdev->priv;
|
||||
bool req_done = false;
|
||||
int qid = vq->index;
|
||||
struct virtblk_req *vbr;
|
||||
unsigned long flags;
|
||||
unsigned int len;
|
||||
|
||||
spin_lock_irqsave(&vblk->vq_lock, flags);
|
||||
spin_lock_irqsave(&vblk->vqs[qid].lock, flags);
|
||||
do {
|
||||
virtqueue_disable_cb(vq);
|
||||
while ((vbr = virtqueue_get_buf(vblk->vq, &len)) != NULL) {
|
||||
while ((vbr = virtqueue_get_buf(vblk->vqs[qid].vq, &len)) != NULL) {
|
||||
blk_mq_complete_request(vbr->req);
|
||||
req_done = true;
|
||||
}
|
||||
@@ -151,7 +161,7 @@ static void virtblk_done(struct virtqueue *vq)
|
||||
/* In case queue is stopped waiting for more buffers. */
|
||||
if (req_done)
|
||||
blk_mq_start_stopped_hw_queues(vblk->disk->queue, true);
|
||||
spin_unlock_irqrestore(&vblk->vq_lock, flags);
|
||||
spin_unlock_irqrestore(&vblk->vqs[qid].lock, flags);
|
||||
}
|
||||
|
||||
static int virtio_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *req)
|
||||
@@ -160,6 +170,7 @@ static int virtio_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *req)
|
||||
struct virtblk_req *vbr = blk_mq_rq_to_pdu(req);
|
||||
unsigned long flags;
|
||||
unsigned int num;
|
||||
int qid = hctx->queue_num;
|
||||
const bool last = (req->cmd_flags & REQ_END) != 0;
|
||||
int err;
|
||||
bool notify = false;
|
||||
@@ -202,12 +213,12 @@ static int virtio_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *req)
|
||||
vbr->out_hdr.type |= VIRTIO_BLK_T_IN;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&vblk->vq_lock, flags);
|
||||
err = __virtblk_add_req(vblk->vq, vbr, vbr->sg, num);
|
||||
spin_lock_irqsave(&vblk->vqs[qid].lock, flags);
|
||||
err = __virtblk_add_req(vblk->vqs[qid].vq, vbr, vbr->sg, num);
|
||||
if (err) {
|
||||
virtqueue_kick(vblk->vq);
|
||||
virtqueue_kick(vblk->vqs[qid].vq);
|
||||
blk_mq_stop_hw_queue(hctx);
|
||||
spin_unlock_irqrestore(&vblk->vq_lock, flags);
|
||||
spin_unlock_irqrestore(&vblk->vqs[qid].lock, flags);
|
||||
/* Out of mem doesn't actually happen, since we fall back
|
||||
* to direct descriptors */
|
||||
if (err == -ENOMEM || err == -ENOSPC)
|
||||
@@ -215,12 +226,12 @@ static int virtio_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *req)
|
||||
return BLK_MQ_RQ_QUEUE_ERROR;
|
||||
}
|
||||
|
||||
if (last && virtqueue_kick_prepare(vblk->vq))
|
||||
if (last && virtqueue_kick_prepare(vblk->vqs[qid].vq))
|
||||
notify = true;
|
||||
spin_unlock_irqrestore(&vblk->vq_lock, flags);
|
||||
spin_unlock_irqrestore(&vblk->vqs[qid].lock, flags);
|
||||
|
||||
if (notify)
|
||||
virtqueue_notify(vblk->vq);
|
||||
virtqueue_notify(vblk->vqs[qid].vq);
|
||||
return BLK_MQ_RQ_QUEUE_OK;
|
||||
}
|
||||
|
||||
@@ -377,12 +388,64 @@ static void virtblk_config_changed(struct virtio_device *vdev)
|
||||
static int init_vq(struct virtio_blk *vblk)
|
||||
{
|
||||
int err = 0;
|
||||
int i;
|
||||
vq_callback_t **callbacks;
|
||||
const char **names;
|
||||
struct virtqueue **vqs;
|
||||
unsigned short num_vqs;
|
||||
struct virtio_device *vdev = vblk->vdev;
|
||||
|
||||
/* We expect one virtqueue, for output. */
|
||||
vblk->vq = virtio_find_single_vq(vblk->vdev, virtblk_done, "requests");
|
||||
if (IS_ERR(vblk->vq))
|
||||
err = PTR_ERR(vblk->vq);
|
||||
err = virtio_cread_feature(vdev, VIRTIO_BLK_F_MQ,
|
||||
struct virtio_blk_config, num_queues,
|
||||
&num_vqs);
|
||||
if (err)
|
||||
num_vqs = 1;
|
||||
|
||||
vblk->vqs = kmalloc(sizeof(*vblk->vqs) * num_vqs, GFP_KERNEL);
|
||||
if (!vblk->vqs) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
names = kmalloc(sizeof(*names) * num_vqs, GFP_KERNEL);
|
||||
if (!names)
|
||||
goto err_names;
|
||||
|
||||
callbacks = kmalloc(sizeof(*callbacks) * num_vqs, GFP_KERNEL);
|
||||
if (!callbacks)
|
||||
goto err_callbacks;
|
||||
|
||||
vqs = kmalloc(sizeof(*vqs) * num_vqs, GFP_KERNEL);
|
||||
if (!vqs)
|
||||
goto err_vqs;
|
||||
|
||||
for (i = 0; i < num_vqs; i++) {
|
||||
callbacks[i] = virtblk_done;
|
||||
snprintf(vblk->vqs[i].name, VQ_NAME_LEN, "req.%d", i);
|
||||
names[i] = vblk->vqs[i].name;
|
||||
}
|
||||
|
||||
/* Discover virtqueues and write information to configuration. */
|
||||
err = vdev->config->find_vqs(vdev, num_vqs, vqs, callbacks, names);
|
||||
if (err)
|
||||
goto err_find_vqs;
|
||||
|
||||
for (i = 0; i < num_vqs; i++) {
|
||||
spin_lock_init(&vblk->vqs[i].lock);
|
||||
vblk->vqs[i].vq = vqs[i];
|
||||
}
|
||||
vblk->num_vqs = num_vqs;
|
||||
|
||||
err_find_vqs:
|
||||
kfree(vqs);
|
||||
err_vqs:
|
||||
kfree(callbacks);
|
||||
err_callbacks:
|
||||
kfree(names);
|
||||
err_names:
|
||||
if (err)
|
||||
kfree(vblk->vqs);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -551,7 +614,6 @@ static int virtblk_probe(struct virtio_device *vdev)
|
||||
err = init_vq(vblk);
|
||||
if (err)
|
||||
goto out_free_vblk;
|
||||
spin_lock_init(&vblk->vq_lock);
|
||||
|
||||
/* FIXME: How many partitions? How long is a piece of string? */
|
||||
vblk->disk = alloc_disk(1 << PART_BITS);
|
||||
@@ -562,7 +624,7 @@ static int virtblk_probe(struct virtio_device *vdev)
|
||||
|
||||
/* Default queue sizing is to fill the ring. */
|
||||
if (!virtblk_queue_depth) {
|
||||
virtblk_queue_depth = vblk->vq->num_free;
|
||||
virtblk_queue_depth = vblk->vqs[0].vq->num_free;
|
||||
/* ... but without indirect descs, we use 2 descs per req */
|
||||
if (!virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC))
|
||||
virtblk_queue_depth /= 2;
|
||||
@@ -570,7 +632,6 @@ static int virtblk_probe(struct virtio_device *vdev)
|
||||
|
||||
memset(&vblk->tag_set, 0, sizeof(vblk->tag_set));
|
||||
vblk->tag_set.ops = &virtio_mq_ops;
|
||||
vblk->tag_set.nr_hw_queues = 1;
|
||||
vblk->tag_set.queue_depth = virtblk_queue_depth;
|
||||
vblk->tag_set.numa_node = NUMA_NO_NODE;
|
||||
vblk->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
|
||||
@@ -578,6 +639,7 @@ static int virtblk_probe(struct virtio_device *vdev)
|
||||
sizeof(struct virtblk_req) +
|
||||
sizeof(struct scatterlist) * sg_elems;
|
||||
vblk->tag_set.driver_data = vblk;
|
||||
vblk->tag_set.nr_hw_queues = vblk->num_vqs;
|
||||
|
||||
err = blk_mq_alloc_tag_set(&vblk->tag_set);
|
||||
if (err)
|
||||
@@ -727,6 +789,7 @@ static void virtblk_remove(struct virtio_device *vdev)
|
||||
refc = atomic_read(&disk_to_dev(vblk->disk)->kobj.kref.refcount);
|
||||
put_disk(vblk->disk);
|
||||
vdev->config->del_vqs(vdev);
|
||||
kfree(vblk->vqs);
|
||||
kfree(vblk);
|
||||
|
||||
/* Only free device id if we don't have any users */
|
||||
@@ -777,7 +840,8 @@ static const struct virtio_device_id id_table[] = {
|
||||
static unsigned int features[] = {
|
||||
VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_GEOMETRY,
|
||||
VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, VIRTIO_BLK_F_SCSI,
|
||||
VIRTIO_BLK_F_WCE, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE
|
||||
VIRTIO_BLK_F_WCE, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE,
|
||||
VIRTIO_BLK_F_MQ,
|
||||
};
|
||||
|
||||
static struct virtio_driver virtio_blk = {
|
||||
|
||||
Reference in New Issue
Block a user