Merge branch 'for-3.6/drivers' of git://git.kernel.dk/linux-block
Pull block driver changes from Jens Axboe: - Making the plugging support for drivers a bit more sane from Neil. This supersedes the plugging change from Shaohua as well. - The usual round of drbd updates. - Using a tail add instead of a head add in the request completion for ndb, making us find the most completed request more quickly. - A few floppy changes, getting rid of a duplicated flag and also running the floppy init async (since it takes forever in boot terms) from Andi. * 'for-3.6/drivers' of git://git.kernel.dk/linux-block: floppy: remove duplicated flag FD_RAW_NEED_DISK blk: pass from_schedule to non-request unplug functions. block: stack unplug blk: centralize non-request unplug handling. md: remove plug_cnt feature of plugging. block/nbd: micro-optimization in nbd request completion drbd: announce FLUSH/FUA capability to upper layers drbd: fix max_bio_size to be unsigned drbd: flush drbd work queue before invalidate/invalidate remote drbd: fix potential access after free drbd: call local-io-error handler early drbd: do not reset rs_pending_cnt too early drbd: reset congestion information before reporting it in /proc/drbd drbd: report congestion if we are waiting for some userland callback drbd: differentiate between normal and forced detach drbd: cleanup, remove two unused global flags floppy: Run floppy initialization asynchronous
This commit is contained in:
Коммит
eff0d13f38
|
@ -2909,24 +2909,48 @@ static void queue_unplugged(struct request_queue *q, unsigned int depth,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void flush_plug_callbacks(struct blk_plug *plug)
|
static void flush_plug_callbacks(struct blk_plug *plug, bool from_schedule)
|
||||||
{
|
{
|
||||||
LIST_HEAD(callbacks);
|
LIST_HEAD(callbacks);
|
||||||
|
|
||||||
if (list_empty(&plug->cb_list))
|
while (!list_empty(&plug->cb_list)) {
|
||||||
return;
|
list_splice_init(&plug->cb_list, &callbacks);
|
||||||
|
|
||||||
list_splice_init(&plug->cb_list, &callbacks);
|
while (!list_empty(&callbacks)) {
|
||||||
|
struct blk_plug_cb *cb = list_first_entry(&callbacks,
|
||||||
while (!list_empty(&callbacks)) {
|
|
||||||
struct blk_plug_cb *cb = list_first_entry(&callbacks,
|
|
||||||
struct blk_plug_cb,
|
struct blk_plug_cb,
|
||||||
list);
|
list);
|
||||||
list_del(&cb->list);
|
list_del(&cb->list);
|
||||||
cb->callback(cb);
|
cb->callback(cb, from_schedule);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct blk_plug_cb *blk_check_plugged(blk_plug_cb_fn unplug, void *data,
|
||||||
|
int size)
|
||||||
|
{
|
||||||
|
struct blk_plug *plug = current->plug;
|
||||||
|
struct blk_plug_cb *cb;
|
||||||
|
|
||||||
|
if (!plug)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
list_for_each_entry(cb, &plug->cb_list, list)
|
||||||
|
if (cb->callback == unplug && cb->data == data)
|
||||||
|
return cb;
|
||||||
|
|
||||||
|
/* Not currently on the callback list */
|
||||||
|
BUG_ON(size < sizeof(*cb));
|
||||||
|
cb = kzalloc(size, GFP_ATOMIC);
|
||||||
|
if (cb) {
|
||||||
|
cb->data = data;
|
||||||
|
cb->callback = unplug;
|
||||||
|
list_add(&cb->list, &plug->cb_list);
|
||||||
|
}
|
||||||
|
return cb;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(blk_check_plugged);
|
||||||
|
|
||||||
void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule)
|
void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule)
|
||||||
{
|
{
|
||||||
struct request_queue *q;
|
struct request_queue *q;
|
||||||
|
@ -2937,7 +2961,7 @@ void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule)
|
||||||
|
|
||||||
BUG_ON(plug->magic != PLUG_MAGIC);
|
BUG_ON(plug->magic != PLUG_MAGIC);
|
||||||
|
|
||||||
flush_plug_callbacks(plug);
|
flush_plug_callbacks(plug, from_schedule);
|
||||||
if (list_empty(&plug->list))
|
if (list_empty(&plug->list))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -411,7 +411,7 @@ w_al_write_transaction(struct drbd_conf *mdev, struct drbd_work *w, int unused)
|
||||||
+ mdev->ldev->md.al_offset + mdev->al_tr_pos;
|
+ mdev->ldev->md.al_offset + mdev->al_tr_pos;
|
||||||
|
|
||||||
if (!drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE))
|
if (!drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE))
|
||||||
drbd_chk_io_error(mdev, 1, true);
|
drbd_chk_io_error(mdev, 1, DRBD_META_IO_ERROR);
|
||||||
|
|
||||||
if (++mdev->al_tr_pos >
|
if (++mdev->al_tr_pos >
|
||||||
div_ceil(mdev->act_log->nr_elements, AL_EXTENTS_PT))
|
div_ceil(mdev->act_log->nr_elements, AL_EXTENTS_PT))
|
||||||
|
@ -876,7 +876,11 @@ int __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector, int size,
|
||||||
unsigned int enr, count = 0;
|
unsigned int enr, count = 0;
|
||||||
struct lc_element *e;
|
struct lc_element *e;
|
||||||
|
|
||||||
if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_BIO_SIZE) {
|
/* this should be an empty REQ_FLUSH */
|
||||||
|
if (size == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (size < 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_BIO_SIZE) {
|
||||||
dev_err(DEV, "sector: %llus, size: %d\n",
|
dev_err(DEV, "sector: %llus, size: %d\n",
|
||||||
(unsigned long long)sector, size);
|
(unsigned long long)sector, size);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -1096,7 +1096,7 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w
|
||||||
|
|
||||||
if (ctx->error) {
|
if (ctx->error) {
|
||||||
dev_alert(DEV, "we had at least one MD IO ERROR during bitmap IO\n");
|
dev_alert(DEV, "we had at least one MD IO ERROR during bitmap IO\n");
|
||||||
drbd_chk_io_error(mdev, 1, true);
|
drbd_chk_io_error(mdev, 1, DRBD_META_IO_ERROR);
|
||||||
err = -EIO; /* ctx->error ? */
|
err = -EIO; /* ctx->error ? */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1212,7 +1212,7 @@ int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(loc
|
||||||
wait_until_done_or_disk_failure(mdev, mdev->ldev, &ctx->done);
|
wait_until_done_or_disk_failure(mdev, mdev->ldev, &ctx->done);
|
||||||
|
|
||||||
if (ctx->error)
|
if (ctx->error)
|
||||||
drbd_chk_io_error(mdev, 1, true);
|
drbd_chk_io_error(mdev, 1, DRBD_META_IO_ERROR);
|
||||||
/* that should force detach, so the in memory bitmap will be
|
/* that should force detach, so the in memory bitmap will be
|
||||||
* gone in a moment as well. */
|
* gone in a moment as well. */
|
||||||
|
|
||||||
|
|
|
@ -813,7 +813,6 @@ enum {
|
||||||
SIGNAL_ASENDER, /* whether asender wants to be interrupted */
|
SIGNAL_ASENDER, /* whether asender wants to be interrupted */
|
||||||
SEND_PING, /* whether asender should send a ping asap */
|
SEND_PING, /* whether asender should send a ping asap */
|
||||||
|
|
||||||
UNPLUG_QUEUED, /* only relevant with kernel 2.4 */
|
|
||||||
UNPLUG_REMOTE, /* sending a "UnplugRemote" could help */
|
UNPLUG_REMOTE, /* sending a "UnplugRemote" could help */
|
||||||
MD_DIRTY, /* current uuids and flags not yet on disk */
|
MD_DIRTY, /* current uuids and flags not yet on disk */
|
||||||
DISCARD_CONCURRENT, /* Set on one node, cleared on the peer! */
|
DISCARD_CONCURRENT, /* Set on one node, cleared on the peer! */
|
||||||
|
@ -824,7 +823,6 @@ enum {
|
||||||
CRASHED_PRIMARY, /* This node was a crashed primary.
|
CRASHED_PRIMARY, /* This node was a crashed primary.
|
||||||
* Gets cleared when the state.conn
|
* Gets cleared when the state.conn
|
||||||
* goes into C_CONNECTED state. */
|
* goes into C_CONNECTED state. */
|
||||||
NO_BARRIER_SUPP, /* underlying block device doesn't implement barriers */
|
|
||||||
CONSIDER_RESYNC,
|
CONSIDER_RESYNC,
|
||||||
|
|
||||||
MD_NO_FUA, /* Users wants us to not use FUA/FLUSH on meta data dev */
|
MD_NO_FUA, /* Users wants us to not use FUA/FLUSH on meta data dev */
|
||||||
|
@ -834,6 +832,7 @@ enum {
|
||||||
BITMAP_IO_QUEUED, /* Started bitmap IO */
|
BITMAP_IO_QUEUED, /* Started bitmap IO */
|
||||||
GO_DISKLESS, /* Disk is being detached, on io-error or admin request. */
|
GO_DISKLESS, /* Disk is being detached, on io-error or admin request. */
|
||||||
WAS_IO_ERROR, /* Local disk failed returned IO error */
|
WAS_IO_ERROR, /* Local disk failed returned IO error */
|
||||||
|
FORCE_DETACH, /* Force-detach from local disk, aborting any pending local IO */
|
||||||
RESYNC_AFTER_NEG, /* Resync after online grow after the attach&negotiate finished. */
|
RESYNC_AFTER_NEG, /* Resync after online grow after the attach&negotiate finished. */
|
||||||
NET_CONGESTED, /* The data socket is congested */
|
NET_CONGESTED, /* The data socket is congested */
|
||||||
|
|
||||||
|
@ -851,6 +850,13 @@ enum {
|
||||||
AL_SUSPENDED, /* Activity logging is currently suspended. */
|
AL_SUSPENDED, /* Activity logging is currently suspended. */
|
||||||
AHEAD_TO_SYNC_SOURCE, /* Ahead -> SyncSource queued */
|
AHEAD_TO_SYNC_SOURCE, /* Ahead -> SyncSource queued */
|
||||||
STATE_SENT, /* Do not change state/UUIDs while this is set */
|
STATE_SENT, /* Do not change state/UUIDs while this is set */
|
||||||
|
|
||||||
|
CALLBACK_PENDING, /* Whether we have a call_usermodehelper(, UMH_WAIT_PROC)
|
||||||
|
* pending, from drbd worker context.
|
||||||
|
* If set, bdi_write_congested() returns true,
|
||||||
|
* so shrink_page_list() would not recurse into,
|
||||||
|
* and potentially deadlock on, this drbd worker.
|
||||||
|
*/
|
||||||
};
|
};
|
||||||
|
|
||||||
struct drbd_bitmap; /* opaque for drbd_conf */
|
struct drbd_bitmap; /* opaque for drbd_conf */
|
||||||
|
@ -1130,8 +1136,8 @@ struct drbd_conf {
|
||||||
int rs_in_flight; /* resync sectors in flight (to proxy, in proxy and from proxy) */
|
int rs_in_flight; /* resync sectors in flight (to proxy, in proxy and from proxy) */
|
||||||
int rs_planed; /* resync sectors already planned */
|
int rs_planed; /* resync sectors already planned */
|
||||||
atomic_t ap_in_flight; /* App sectors in flight (waiting for ack) */
|
atomic_t ap_in_flight; /* App sectors in flight (waiting for ack) */
|
||||||
int peer_max_bio_size;
|
unsigned int peer_max_bio_size;
|
||||||
int local_max_bio_size;
|
unsigned int local_max_bio_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct drbd_conf *minor_to_mdev(unsigned int minor)
|
static inline struct drbd_conf *minor_to_mdev(unsigned int minor)
|
||||||
|
@ -1435,9 +1441,9 @@ struct bm_extent {
|
||||||
* hash table. */
|
* hash table. */
|
||||||
#define HT_SHIFT 8
|
#define HT_SHIFT 8
|
||||||
#define DRBD_MAX_BIO_SIZE (1U<<(9+HT_SHIFT))
|
#define DRBD_MAX_BIO_SIZE (1U<<(9+HT_SHIFT))
|
||||||
#define DRBD_MAX_BIO_SIZE_SAFE (1 << 12) /* Works always = 4k */
|
#define DRBD_MAX_BIO_SIZE_SAFE (1U << 12) /* Works always = 4k */
|
||||||
|
|
||||||
#define DRBD_MAX_SIZE_H80_PACKET (1 << 15) /* The old header only allows packets up to 32Kib data */
|
#define DRBD_MAX_SIZE_H80_PACKET (1U << 15) /* The old header only allows packets up to 32Kib data */
|
||||||
|
|
||||||
/* Number of elements in the app_reads_hash */
|
/* Number of elements in the app_reads_hash */
|
||||||
#define APP_R_HSIZE 15
|
#define APP_R_HSIZE 15
|
||||||
|
@ -1840,12 +1846,20 @@ static inline int drbd_request_state(struct drbd_conf *mdev,
|
||||||
return _drbd_request_state(mdev, mask, val, CS_VERBOSE + CS_ORDERED);
|
return _drbd_request_state(mdev, mask, val, CS_VERBOSE + CS_ORDERED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum drbd_force_detach_flags {
|
||||||
|
DRBD_IO_ERROR,
|
||||||
|
DRBD_META_IO_ERROR,
|
||||||
|
DRBD_FORCE_DETACH,
|
||||||
|
};
|
||||||
|
|
||||||
#define __drbd_chk_io_error(m,f) __drbd_chk_io_error_(m,f, __func__)
|
#define __drbd_chk_io_error(m,f) __drbd_chk_io_error_(m,f, __func__)
|
||||||
static inline void __drbd_chk_io_error_(struct drbd_conf *mdev, int forcedetach, const char *where)
|
static inline void __drbd_chk_io_error_(struct drbd_conf *mdev,
|
||||||
|
enum drbd_force_detach_flags forcedetach,
|
||||||
|
const char *where)
|
||||||
{
|
{
|
||||||
switch (mdev->ldev->dc.on_io_error) {
|
switch (mdev->ldev->dc.on_io_error) {
|
||||||
case EP_PASS_ON:
|
case EP_PASS_ON:
|
||||||
if (!forcedetach) {
|
if (forcedetach == DRBD_IO_ERROR) {
|
||||||
if (__ratelimit(&drbd_ratelimit_state))
|
if (__ratelimit(&drbd_ratelimit_state))
|
||||||
dev_err(DEV, "Local IO failed in %s.\n", where);
|
dev_err(DEV, "Local IO failed in %s.\n", where);
|
||||||
if (mdev->state.disk > D_INCONSISTENT)
|
if (mdev->state.disk > D_INCONSISTENT)
|
||||||
|
@ -1856,6 +1870,8 @@ static inline void __drbd_chk_io_error_(struct drbd_conf *mdev, int forcedetach,
|
||||||
case EP_DETACH:
|
case EP_DETACH:
|
||||||
case EP_CALL_HELPER:
|
case EP_CALL_HELPER:
|
||||||
set_bit(WAS_IO_ERROR, &mdev->flags);
|
set_bit(WAS_IO_ERROR, &mdev->flags);
|
||||||
|
if (forcedetach == DRBD_FORCE_DETACH)
|
||||||
|
set_bit(FORCE_DETACH, &mdev->flags);
|
||||||
if (mdev->state.disk > D_FAILED) {
|
if (mdev->state.disk > D_FAILED) {
|
||||||
_drbd_set_state(_NS(mdev, disk, D_FAILED), CS_HARD, NULL);
|
_drbd_set_state(_NS(mdev, disk, D_FAILED), CS_HARD, NULL);
|
||||||
dev_err(DEV,
|
dev_err(DEV,
|
||||||
|
@ -1875,7 +1891,7 @@ static inline void __drbd_chk_io_error_(struct drbd_conf *mdev, int forcedetach,
|
||||||
*/
|
*/
|
||||||
#define drbd_chk_io_error(m,e,f) drbd_chk_io_error_(m,e,f, __func__)
|
#define drbd_chk_io_error(m,e,f) drbd_chk_io_error_(m,e,f, __func__)
|
||||||
static inline void drbd_chk_io_error_(struct drbd_conf *mdev,
|
static inline void drbd_chk_io_error_(struct drbd_conf *mdev,
|
||||||
int error, int forcedetach, const char *where)
|
int error, enum drbd_force_detach_flags forcedetach, const char *where)
|
||||||
{
|
{
|
||||||
if (error) {
|
if (error) {
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
@ -2405,15 +2421,17 @@ static inline void dec_ap_bio(struct drbd_conf *mdev)
|
||||||
int ap_bio = atomic_dec_return(&mdev->ap_bio_cnt);
|
int ap_bio = atomic_dec_return(&mdev->ap_bio_cnt);
|
||||||
|
|
||||||
D_ASSERT(ap_bio >= 0);
|
D_ASSERT(ap_bio >= 0);
|
||||||
|
|
||||||
|
if (ap_bio == 0 && test_bit(BITMAP_IO, &mdev->flags)) {
|
||||||
|
if (!test_and_set_bit(BITMAP_IO_QUEUED, &mdev->flags))
|
||||||
|
drbd_queue_work(&mdev->data.work, &mdev->bm_io_work.w);
|
||||||
|
}
|
||||||
|
|
||||||
/* this currently does wake_up for every dec_ap_bio!
|
/* this currently does wake_up for every dec_ap_bio!
|
||||||
* maybe rather introduce some type of hysteresis?
|
* maybe rather introduce some type of hysteresis?
|
||||||
* e.g. (ap_bio == mxb/2 || ap_bio == 0) ? */
|
* e.g. (ap_bio == mxb/2 || ap_bio == 0) ? */
|
||||||
if (ap_bio < mxb)
|
if (ap_bio < mxb)
|
||||||
wake_up(&mdev->misc_wait);
|
wake_up(&mdev->misc_wait);
|
||||||
if (ap_bio == 0 && test_bit(BITMAP_IO, &mdev->flags)) {
|
|
||||||
if (!test_and_set_bit(BITMAP_IO_QUEUED, &mdev->flags))
|
|
||||||
drbd_queue_work(&mdev->data.work, &mdev->bm_io_work.w);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int drbd_set_ed_uuid(struct drbd_conf *mdev, u64 val)
|
static inline int drbd_set_ed_uuid(struct drbd_conf *mdev, u64 val)
|
||||||
|
|
|
@ -1514,6 +1514,13 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
|
||||||
|
|
||||||
/* Do not change the order of the if above and the two below... */
|
/* Do not change the order of the if above and the two below... */
|
||||||
if (os.pdsk == D_DISKLESS && ns.pdsk > D_DISKLESS) { /* attach on the peer */
|
if (os.pdsk == D_DISKLESS && ns.pdsk > D_DISKLESS) { /* attach on the peer */
|
||||||
|
/* we probably will start a resync soon.
|
||||||
|
* make sure those things are properly reset. */
|
||||||
|
mdev->rs_total = 0;
|
||||||
|
mdev->rs_failed = 0;
|
||||||
|
atomic_set(&mdev->rs_pending_cnt, 0);
|
||||||
|
drbd_rs_cancel_all(mdev);
|
||||||
|
|
||||||
drbd_send_uuids(mdev);
|
drbd_send_uuids(mdev);
|
||||||
drbd_send_state(mdev, ns);
|
drbd_send_state(mdev, ns);
|
||||||
}
|
}
|
||||||
|
@ -1630,9 +1637,24 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
|
||||||
eh = mdev->ldev->dc.on_io_error;
|
eh = mdev->ldev->dc.on_io_error;
|
||||||
was_io_error = test_and_clear_bit(WAS_IO_ERROR, &mdev->flags);
|
was_io_error = test_and_clear_bit(WAS_IO_ERROR, &mdev->flags);
|
||||||
|
|
||||||
/* Immediately allow completion of all application IO, that waits
|
if (was_io_error && eh == EP_CALL_HELPER)
|
||||||
for completion from the local disk. */
|
drbd_khelper(mdev, "local-io-error");
|
||||||
tl_abort_disk_io(mdev);
|
|
||||||
|
/* Immediately allow completion of all application IO,
|
||||||
|
* that waits for completion from the local disk,
|
||||||
|
* if this was a force-detach due to disk_timeout
|
||||||
|
* or administrator request (drbdsetup detach --force).
|
||||||
|
* Do NOT abort otherwise.
|
||||||
|
* Aborting local requests may cause serious problems,
|
||||||
|
* if requests are completed to upper layers already,
|
||||||
|
* and then later the already submitted local bio completes.
|
||||||
|
* This can cause DMA into former bio pages that meanwhile
|
||||||
|
* have been re-used for other things.
|
||||||
|
* So aborting local requests may cause crashes,
|
||||||
|
* or even worse, silent data corruption.
|
||||||
|
*/
|
||||||
|
if (test_and_clear_bit(FORCE_DETACH, &mdev->flags))
|
||||||
|
tl_abort_disk_io(mdev);
|
||||||
|
|
||||||
/* current state still has to be D_FAILED,
|
/* current state still has to be D_FAILED,
|
||||||
* there is only one way out: to D_DISKLESS,
|
* there is only one way out: to D_DISKLESS,
|
||||||
|
@ -1653,9 +1675,6 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
|
||||||
drbd_md_sync(mdev);
|
drbd_md_sync(mdev);
|
||||||
}
|
}
|
||||||
put_ldev(mdev);
|
put_ldev(mdev);
|
||||||
|
|
||||||
if (was_io_error && eh == EP_CALL_HELPER)
|
|
||||||
drbd_khelper(mdev, "local-io-error");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* second half of local IO error, failure to attach,
|
/* second half of local IO error, failure to attach,
|
||||||
|
@ -1669,10 +1688,6 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
|
||||||
"ASSERT FAILED: disk is %s while going diskless\n",
|
"ASSERT FAILED: disk is %s while going diskless\n",
|
||||||
drbd_disk_str(mdev->state.disk));
|
drbd_disk_str(mdev->state.disk));
|
||||||
|
|
||||||
mdev->rs_total = 0;
|
|
||||||
mdev->rs_failed = 0;
|
|
||||||
atomic_set(&mdev->rs_pending_cnt, 0);
|
|
||||||
|
|
||||||
if (ns.conn >= C_CONNECTED)
|
if (ns.conn >= C_CONNECTED)
|
||||||
drbd_send_state(mdev, ns);
|
drbd_send_state(mdev, ns);
|
||||||
|
|
||||||
|
@ -2194,7 +2209,8 @@ int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags fl
|
||||||
{
|
{
|
||||||
struct p_sizes p;
|
struct p_sizes p;
|
||||||
sector_t d_size, u_size;
|
sector_t d_size, u_size;
|
||||||
int q_order_type, max_bio_size;
|
int q_order_type;
|
||||||
|
unsigned int max_bio_size;
|
||||||
int ok;
|
int ok;
|
||||||
|
|
||||||
if (get_ldev_if_state(mdev, D_NEGOTIATING)) {
|
if (get_ldev_if_state(mdev, D_NEGOTIATING)) {
|
||||||
|
@ -2203,7 +2219,7 @@ int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags fl
|
||||||
u_size = mdev->ldev->dc.disk_size;
|
u_size = mdev->ldev->dc.disk_size;
|
||||||
q_order_type = drbd_queue_order_type(mdev);
|
q_order_type = drbd_queue_order_type(mdev);
|
||||||
max_bio_size = queue_max_hw_sectors(mdev->ldev->backing_bdev->bd_disk->queue) << 9;
|
max_bio_size = queue_max_hw_sectors(mdev->ldev->backing_bdev->bd_disk->queue) << 9;
|
||||||
max_bio_size = min_t(int, max_bio_size, DRBD_MAX_BIO_SIZE);
|
max_bio_size = min(max_bio_size, DRBD_MAX_BIO_SIZE);
|
||||||
put_ldev(mdev);
|
put_ldev(mdev);
|
||||||
} else {
|
} else {
|
||||||
d_size = 0;
|
d_size = 0;
|
||||||
|
@ -2214,7 +2230,7 @@ int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags fl
|
||||||
|
|
||||||
/* Never allow old drbd (up to 8.3.7) to see more than 32KiB */
|
/* Never allow old drbd (up to 8.3.7) to see more than 32KiB */
|
||||||
if (mdev->agreed_pro_version <= 94)
|
if (mdev->agreed_pro_version <= 94)
|
||||||
max_bio_size = min_t(int, max_bio_size, DRBD_MAX_SIZE_H80_PACKET);
|
max_bio_size = min(max_bio_size, DRBD_MAX_SIZE_H80_PACKET);
|
||||||
|
|
||||||
p.d_size = cpu_to_be64(d_size);
|
p.d_size = cpu_to_be64(d_size);
|
||||||
p.u_size = cpu_to_be64(u_size);
|
p.u_size = cpu_to_be64(u_size);
|
||||||
|
@ -3541,6 +3557,22 @@ static int drbd_congested(void *congested_data, int bdi_bits)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (test_bit(CALLBACK_PENDING, &mdev->flags)) {
|
||||||
|
r |= (1 << BDI_async_congested);
|
||||||
|
/* Without good local data, we would need to read from remote,
|
||||||
|
* and that would need the worker thread as well, which is
|
||||||
|
* currently blocked waiting for that usermode helper to
|
||||||
|
* finish.
|
||||||
|
*/
|
||||||
|
if (!get_ldev_if_state(mdev, D_UP_TO_DATE))
|
||||||
|
r |= (1 << BDI_sync_congested);
|
||||||
|
else
|
||||||
|
put_ldev(mdev);
|
||||||
|
r &= bdi_bits;
|
||||||
|
reason = 'c';
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (get_ldev(mdev)) {
|
if (get_ldev(mdev)) {
|
||||||
q = bdev_get_queue(mdev->ldev->backing_bdev);
|
q = bdev_get_queue(mdev->ldev->backing_bdev);
|
||||||
r = bdi_congested(&q->backing_dev_info, bdi_bits);
|
r = bdi_congested(&q->backing_dev_info, bdi_bits);
|
||||||
|
@ -3604,6 +3636,7 @@ struct drbd_conf *drbd_new_device(unsigned int minor)
|
||||||
q->backing_dev_info.congested_data = mdev;
|
q->backing_dev_info.congested_data = mdev;
|
||||||
|
|
||||||
blk_queue_make_request(q, drbd_make_request);
|
blk_queue_make_request(q, drbd_make_request);
|
||||||
|
blk_queue_flush(q, REQ_FLUSH | REQ_FUA);
|
||||||
/* Setting the max_hw_sectors to an odd value of 8kibyte here
|
/* Setting the max_hw_sectors to an odd value of 8kibyte here
|
||||||
This triggers a max_bio_size message upon first attach or connect */
|
This triggers a max_bio_size message upon first attach or connect */
|
||||||
blk_queue_max_hw_sectors(q, DRBD_MAX_BIO_SIZE_SAFE >> 8);
|
blk_queue_max_hw_sectors(q, DRBD_MAX_BIO_SIZE_SAFE >> 8);
|
||||||
|
@ -3870,7 +3903,7 @@ void drbd_md_sync(struct drbd_conf *mdev)
|
||||||
if (!drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE)) {
|
if (!drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE)) {
|
||||||
/* this was a try anyways ... */
|
/* this was a try anyways ... */
|
||||||
dev_err(DEV, "meta data update failed!\n");
|
dev_err(DEV, "meta data update failed!\n");
|
||||||
drbd_chk_io_error(mdev, 1, true);
|
drbd_chk_io_error(mdev, 1, DRBD_META_IO_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update mdev->ldev->md.la_size_sect,
|
/* Update mdev->ldev->md.la_size_sect,
|
||||||
|
@ -3950,9 +3983,9 @@ int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
|
||||||
|
|
||||||
spin_lock_irq(&mdev->req_lock);
|
spin_lock_irq(&mdev->req_lock);
|
||||||
if (mdev->state.conn < C_CONNECTED) {
|
if (mdev->state.conn < C_CONNECTED) {
|
||||||
int peer;
|
unsigned int peer;
|
||||||
peer = be32_to_cpu(buffer->la_peer_max_bio_size);
|
peer = be32_to_cpu(buffer->la_peer_max_bio_size);
|
||||||
peer = max_t(int, peer, DRBD_MAX_BIO_SIZE_SAFE);
|
peer = max(peer, DRBD_MAX_BIO_SIZE_SAFE);
|
||||||
mdev->peer_max_bio_size = peer;
|
mdev->peer_max_bio_size = peer;
|
||||||
}
|
}
|
||||||
spin_unlock_irq(&mdev->req_lock);
|
spin_unlock_irq(&mdev->req_lock);
|
||||||
|
|
|
@ -147,6 +147,9 @@ int drbd_khelper(struct drbd_conf *mdev, char *cmd)
|
||||||
char *argv[] = {usermode_helper, cmd, mb, NULL };
|
char *argv[] = {usermode_helper, cmd, mb, NULL };
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (current == mdev->worker.task)
|
||||||
|
set_bit(CALLBACK_PENDING, &mdev->flags);
|
||||||
|
|
||||||
snprintf(mb, 12, "minor-%d", mdev_to_minor(mdev));
|
snprintf(mb, 12, "minor-%d", mdev_to_minor(mdev));
|
||||||
|
|
||||||
if (get_net_conf(mdev)) {
|
if (get_net_conf(mdev)) {
|
||||||
|
@ -189,6 +192,9 @@ int drbd_khelper(struct drbd_conf *mdev, char *cmd)
|
||||||
usermode_helper, cmd, mb,
|
usermode_helper, cmd, mb,
|
||||||
(ret >> 8) & 0xff, ret);
|
(ret >> 8) & 0xff, ret);
|
||||||
|
|
||||||
|
if (current == mdev->worker.task)
|
||||||
|
clear_bit(CALLBACK_PENDING, &mdev->flags);
|
||||||
|
|
||||||
if (ret < 0) /* Ignore any ERRNOs we got. */
|
if (ret < 0) /* Ignore any ERRNOs we got. */
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
|
@ -795,8 +801,8 @@ static int drbd_check_al_size(struct drbd_conf *mdev)
|
||||||
static void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int max_bio_size)
|
static void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int max_bio_size)
|
||||||
{
|
{
|
||||||
struct request_queue * const q = mdev->rq_queue;
|
struct request_queue * const q = mdev->rq_queue;
|
||||||
int max_hw_sectors = max_bio_size >> 9;
|
unsigned int max_hw_sectors = max_bio_size >> 9;
|
||||||
int max_segments = 0;
|
unsigned int max_segments = 0;
|
||||||
|
|
||||||
if (get_ldev_if_state(mdev, D_ATTACHING)) {
|
if (get_ldev_if_state(mdev, D_ATTACHING)) {
|
||||||
struct request_queue * const b = mdev->ldev->backing_bdev->bd_disk->queue;
|
struct request_queue * const b = mdev->ldev->backing_bdev->bd_disk->queue;
|
||||||
|
@ -829,7 +835,7 @@ static void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int max_bio_
|
||||||
|
|
||||||
void drbd_reconsider_max_bio_size(struct drbd_conf *mdev)
|
void drbd_reconsider_max_bio_size(struct drbd_conf *mdev)
|
||||||
{
|
{
|
||||||
int now, new, local, peer;
|
unsigned int now, new, local, peer;
|
||||||
|
|
||||||
now = queue_max_hw_sectors(mdev->rq_queue) << 9;
|
now = queue_max_hw_sectors(mdev->rq_queue) << 9;
|
||||||
local = mdev->local_max_bio_size; /* Eventually last known value, from volatile memory */
|
local = mdev->local_max_bio_size; /* Eventually last known value, from volatile memory */
|
||||||
|
@ -840,13 +846,14 @@ void drbd_reconsider_max_bio_size(struct drbd_conf *mdev)
|
||||||
mdev->local_max_bio_size = local;
|
mdev->local_max_bio_size = local;
|
||||||
put_ldev(mdev);
|
put_ldev(mdev);
|
||||||
}
|
}
|
||||||
|
local = min(local, DRBD_MAX_BIO_SIZE);
|
||||||
|
|
||||||
/* We may ignore peer limits if the peer is modern enough.
|
/* We may ignore peer limits if the peer is modern enough.
|
||||||
Because new from 8.3.8 onwards the peer can use multiple
|
Because new from 8.3.8 onwards the peer can use multiple
|
||||||
BIOs for a single peer_request */
|
BIOs for a single peer_request */
|
||||||
if (mdev->state.conn >= C_CONNECTED) {
|
if (mdev->state.conn >= C_CONNECTED) {
|
||||||
if (mdev->agreed_pro_version < 94) {
|
if (mdev->agreed_pro_version < 94) {
|
||||||
peer = min_t(int, mdev->peer_max_bio_size, DRBD_MAX_SIZE_H80_PACKET);
|
peer = min(mdev->peer_max_bio_size, DRBD_MAX_SIZE_H80_PACKET);
|
||||||
/* Correct old drbd (up to 8.3.7) if it believes it can do more than 32KiB */
|
/* Correct old drbd (up to 8.3.7) if it believes it can do more than 32KiB */
|
||||||
} else if (mdev->agreed_pro_version == 94)
|
} else if (mdev->agreed_pro_version == 94)
|
||||||
peer = DRBD_MAX_SIZE_H80_PACKET;
|
peer = DRBD_MAX_SIZE_H80_PACKET;
|
||||||
|
@ -854,10 +861,10 @@ void drbd_reconsider_max_bio_size(struct drbd_conf *mdev)
|
||||||
peer = DRBD_MAX_BIO_SIZE;
|
peer = DRBD_MAX_BIO_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
new = min_t(int, local, peer);
|
new = min(local, peer);
|
||||||
|
|
||||||
if (mdev->state.role == R_PRIMARY && new < now)
|
if (mdev->state.role == R_PRIMARY && new < now)
|
||||||
dev_err(DEV, "ASSERT FAILED new < now; (%d < %d)\n", new, now);
|
dev_err(DEV, "ASSERT FAILED new < now; (%u < %u)\n", new, now);
|
||||||
|
|
||||||
if (new != now)
|
if (new != now)
|
||||||
dev_info(DEV, "max BIO size = %u\n", new);
|
dev_info(DEV, "max BIO size = %u\n", new);
|
||||||
|
@ -950,6 +957,14 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
|
||||||
* to realize a "hot spare" feature (not that I'd recommend that) */
|
* to realize a "hot spare" feature (not that I'd recommend that) */
|
||||||
wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt));
|
wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt));
|
||||||
|
|
||||||
|
/* make sure there is no leftover from previous force-detach attempts */
|
||||||
|
clear_bit(FORCE_DETACH, &mdev->flags);
|
||||||
|
|
||||||
|
/* and no leftover from previously aborted resync or verify, either */
|
||||||
|
mdev->rs_total = 0;
|
||||||
|
mdev->rs_failed = 0;
|
||||||
|
atomic_set(&mdev->rs_pending_cnt, 0);
|
||||||
|
|
||||||
/* allocation not in the IO path, cqueue thread context */
|
/* allocation not in the IO path, cqueue thread context */
|
||||||
nbc = kzalloc(sizeof(struct drbd_backing_dev), GFP_KERNEL);
|
nbc = kzalloc(sizeof(struct drbd_backing_dev), GFP_KERNEL);
|
||||||
if (!nbc) {
|
if (!nbc) {
|
||||||
|
@ -1345,6 +1360,7 @@ static int drbd_nl_detach(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dt.detach_force) {
|
if (dt.detach_force) {
|
||||||
|
set_bit(FORCE_DETACH, &mdev->flags);
|
||||||
drbd_force_state(mdev, NS(disk, D_FAILED));
|
drbd_force_state(mdev, NS(disk, D_FAILED));
|
||||||
reply->ret_code = SS_SUCCESS;
|
reply->ret_code = SS_SUCCESS;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -1962,9 +1978,11 @@ static int drbd_nl_invalidate(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl
|
||||||
int retcode;
|
int retcode;
|
||||||
|
|
||||||
/* If there is still bitmap IO pending, probably because of a previous
|
/* If there is still bitmap IO pending, probably because of a previous
|
||||||
* resync just being finished, wait for it before requesting a new resync. */
|
* resync just being finished, wait for it before requesting a new resync.
|
||||||
|
* Also wait for it's after_state_ch(). */
|
||||||
drbd_suspend_io(mdev);
|
drbd_suspend_io(mdev);
|
||||||
wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags));
|
wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags));
|
||||||
|
drbd_flush_workqueue(mdev);
|
||||||
|
|
||||||
retcode = _drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_T), CS_ORDERED);
|
retcode = _drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_T), CS_ORDERED);
|
||||||
|
|
||||||
|
@ -2003,9 +2021,11 @@ static int drbd_nl_invalidate_peer(struct drbd_conf *mdev, struct drbd_nl_cfg_re
|
||||||
int retcode;
|
int retcode;
|
||||||
|
|
||||||
/* If there is still bitmap IO pending, probably because of a previous
|
/* If there is still bitmap IO pending, probably because of a previous
|
||||||
* resync just being finished, wait for it before requesting a new resync. */
|
* resync just being finished, wait for it before requesting a new resync.
|
||||||
|
* Also wait for it's after_state_ch(). */
|
||||||
drbd_suspend_io(mdev);
|
drbd_suspend_io(mdev);
|
||||||
wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags));
|
wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags));
|
||||||
|
drbd_flush_workqueue(mdev);
|
||||||
|
|
||||||
retcode = _drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_S), CS_ORDERED);
|
retcode = _drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_S), CS_ORDERED);
|
||||||
|
|
||||||
|
|
|
@ -245,6 +245,9 @@ static int drbd_seq_show(struct seq_file *seq, void *v)
|
||||||
mdev->state.role == R_SECONDARY) {
|
mdev->state.role == R_SECONDARY) {
|
||||||
seq_printf(seq, "%2d: cs:Unconfigured\n", i);
|
seq_printf(seq, "%2d: cs:Unconfigured\n", i);
|
||||||
} else {
|
} else {
|
||||||
|
/* reset mdev->congestion_reason */
|
||||||
|
bdi_rw_congested(&mdev->rq_queue->backing_dev_info);
|
||||||
|
|
||||||
seq_printf(seq,
|
seq_printf(seq,
|
||||||
"%2d: cs:%s ro:%s/%s ds:%s/%s %c %c%c%c%c%c%c\n"
|
"%2d: cs:%s ro:%s/%s ds:%s/%s %c %c%c%c%c%c%c\n"
|
||||||
" ns:%u nr:%u dw:%u dr:%u al:%u bm:%u "
|
" ns:%u nr:%u dw:%u dr:%u al:%u bm:%u "
|
||||||
|
|
|
@ -277,6 +277,9 @@ static void drbd_pp_free(struct drbd_conf *mdev, struct page *page, int is_net)
|
||||||
atomic_t *a = is_net ? &mdev->pp_in_use_by_net : &mdev->pp_in_use;
|
atomic_t *a = is_net ? &mdev->pp_in_use_by_net : &mdev->pp_in_use;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (page == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
if (drbd_pp_vacant > (DRBD_MAX_BIO_SIZE/PAGE_SIZE)*minor_count)
|
if (drbd_pp_vacant > (DRBD_MAX_BIO_SIZE/PAGE_SIZE)*minor_count)
|
||||||
i = page_chain_free(page);
|
i = page_chain_free(page);
|
||||||
else {
|
else {
|
||||||
|
@ -316,7 +319,7 @@ struct drbd_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev,
|
||||||
gfp_t gfp_mask) __must_hold(local)
|
gfp_t gfp_mask) __must_hold(local)
|
||||||
{
|
{
|
||||||
struct drbd_epoch_entry *e;
|
struct drbd_epoch_entry *e;
|
||||||
struct page *page;
|
struct page *page = NULL;
|
||||||
unsigned nr_pages = (data_size + PAGE_SIZE -1) >> PAGE_SHIFT;
|
unsigned nr_pages = (data_size + PAGE_SIZE -1) >> PAGE_SHIFT;
|
||||||
|
|
||||||
if (drbd_insert_fault(mdev, DRBD_FAULT_AL_EE))
|
if (drbd_insert_fault(mdev, DRBD_FAULT_AL_EE))
|
||||||
|
@ -329,9 +332,11 @@ struct drbd_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
page = drbd_pp_alloc(mdev, nr_pages, (gfp_mask & __GFP_WAIT));
|
if (data_size) {
|
||||||
if (!page)
|
page = drbd_pp_alloc(mdev, nr_pages, (gfp_mask & __GFP_WAIT));
|
||||||
goto fail;
|
if (!page)
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
INIT_HLIST_NODE(&e->collision);
|
INIT_HLIST_NODE(&e->collision);
|
||||||
e->epoch = NULL;
|
e->epoch = NULL;
|
||||||
|
@ -1270,7 +1275,6 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, int data_size) __
|
||||||
|
|
||||||
data_size -= dgs;
|
data_size -= dgs;
|
||||||
|
|
||||||
ERR_IF(data_size == 0) return NULL;
|
|
||||||
ERR_IF(data_size & 0x1ff) return NULL;
|
ERR_IF(data_size & 0x1ff) return NULL;
|
||||||
ERR_IF(data_size > DRBD_MAX_BIO_SIZE) return NULL;
|
ERR_IF(data_size > DRBD_MAX_BIO_SIZE) return NULL;
|
||||||
|
|
||||||
|
@ -1291,6 +1295,9 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, int data_size) __
|
||||||
if (!e)
|
if (!e)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
if (!data_size)
|
||||||
|
return e;
|
||||||
|
|
||||||
ds = data_size;
|
ds = data_size;
|
||||||
page = e->pages;
|
page = e->pages;
|
||||||
page_chain_for_each(page) {
|
page_chain_for_each(page) {
|
||||||
|
@ -1715,6 +1722,10 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
|
||||||
|
|
||||||
dp_flags = be32_to_cpu(p->dp_flags);
|
dp_flags = be32_to_cpu(p->dp_flags);
|
||||||
rw |= wire_flags_to_bio(mdev, dp_flags);
|
rw |= wire_flags_to_bio(mdev, dp_flags);
|
||||||
|
if (e->pages == NULL) {
|
||||||
|
D_ASSERT(e->size == 0);
|
||||||
|
D_ASSERT(dp_flags & DP_FLUSH);
|
||||||
|
}
|
||||||
|
|
||||||
if (dp_flags & DP_MAY_SET_IN_SYNC)
|
if (dp_flags & DP_MAY_SET_IN_SYNC)
|
||||||
e->flags |= EE_MAY_SET_IN_SYNC;
|
e->flags |= EE_MAY_SET_IN_SYNC;
|
||||||
|
@ -3801,11 +3812,18 @@ void drbd_free_tl_hash(struct drbd_conf *mdev)
|
||||||
mdev->ee_hash = NULL;
|
mdev->ee_hash = NULL;
|
||||||
mdev->ee_hash_s = 0;
|
mdev->ee_hash_s = 0;
|
||||||
|
|
||||||
/* paranoia code */
|
/* We may not have had the chance to wait for all locally pending
|
||||||
for (h = mdev->tl_hash; h < mdev->tl_hash + mdev->tl_hash_s; h++)
|
* application requests. The hlist_add_fake() prevents access after
|
||||||
if (h->first)
|
* free on master bio completion. */
|
||||||
dev_err(DEV, "ASSERT FAILED tl_hash[%u] == %p, expected NULL\n",
|
for (h = mdev->tl_hash; h < mdev->tl_hash + mdev->tl_hash_s; h++) {
|
||||||
(int)(h - mdev->tl_hash), h->first);
|
struct drbd_request *req;
|
||||||
|
struct hlist_node *pos, *n;
|
||||||
|
hlist_for_each_entry_safe(req, pos, n, h, collision) {
|
||||||
|
hlist_del_init(&req->collision);
|
||||||
|
hlist_add_fake(&req->collision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
kfree(mdev->tl_hash);
|
kfree(mdev->tl_hash);
|
||||||
mdev->tl_hash = NULL;
|
mdev->tl_hash = NULL;
|
||||||
mdev->tl_hash_s = 0;
|
mdev->tl_hash_s = 0;
|
||||||
|
|
|
@ -455,7 +455,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
|
||||||
req->rq_state |= RQ_LOCAL_COMPLETED;
|
req->rq_state |= RQ_LOCAL_COMPLETED;
|
||||||
req->rq_state &= ~RQ_LOCAL_PENDING;
|
req->rq_state &= ~RQ_LOCAL_PENDING;
|
||||||
|
|
||||||
__drbd_chk_io_error(mdev, false);
|
__drbd_chk_io_error(mdev, DRBD_IO_ERROR);
|
||||||
_req_may_be_done_not_susp(req, m);
|
_req_may_be_done_not_susp(req, m);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -477,7 +477,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
__drbd_chk_io_error(mdev, false);
|
__drbd_chk_io_error(mdev, DRBD_IO_ERROR);
|
||||||
|
|
||||||
goto_queue_for_net_read:
|
goto_queue_for_net_read:
|
||||||
|
|
||||||
|
@ -1111,13 +1111,12 @@ void drbd_make_request(struct request_queue *q, struct bio *bio)
|
||||||
/*
|
/*
|
||||||
* what we "blindly" assume:
|
* what we "blindly" assume:
|
||||||
*/
|
*/
|
||||||
D_ASSERT(bio->bi_size > 0);
|
|
||||||
D_ASSERT((bio->bi_size & 0x1ff) == 0);
|
D_ASSERT((bio->bi_size & 0x1ff) == 0);
|
||||||
|
|
||||||
/* to make some things easier, force alignment of requests within the
|
/* to make some things easier, force alignment of requests within the
|
||||||
* granularity of our hash tables */
|
* granularity of our hash tables */
|
||||||
s_enr = bio->bi_sector >> HT_SHIFT;
|
s_enr = bio->bi_sector >> HT_SHIFT;
|
||||||
e_enr = (bio->bi_sector+(bio->bi_size>>9)-1) >> HT_SHIFT;
|
e_enr = bio->bi_size ? (bio->bi_sector+(bio->bi_size>>9)-1) >> HT_SHIFT : s_enr;
|
||||||
|
|
||||||
if (likely(s_enr == e_enr)) {
|
if (likely(s_enr == e_enr)) {
|
||||||
do {
|
do {
|
||||||
|
@ -1275,7 +1274,7 @@ void request_timer_fn(unsigned long data)
|
||||||
time_after(now, req->start_time + dt) &&
|
time_after(now, req->start_time + dt) &&
|
||||||
!time_in_range(now, mdev->last_reattach_jif, mdev->last_reattach_jif + dt)) {
|
!time_in_range(now, mdev->last_reattach_jif, mdev->last_reattach_jif + dt)) {
|
||||||
dev_warn(DEV, "Local backing device failed to meet the disk-timeout\n");
|
dev_warn(DEV, "Local backing device failed to meet the disk-timeout\n");
|
||||||
__drbd_chk_io_error(mdev, 1);
|
__drbd_chk_io_error(mdev, DRBD_FORCE_DETACH);
|
||||||
}
|
}
|
||||||
nt = (time_after(now, req->start_time + et) ? now : req->start_time) + et;
|
nt = (time_after(now, req->start_time + et) ? now : req->start_time) + et;
|
||||||
spin_unlock_irq(&mdev->req_lock);
|
spin_unlock_irq(&mdev->req_lock);
|
||||||
|
|
|
@ -111,7 +111,7 @@ void drbd_endio_read_sec_final(struct drbd_epoch_entry *e) __releases(local)
|
||||||
if (list_empty(&mdev->read_ee))
|
if (list_empty(&mdev->read_ee))
|
||||||
wake_up(&mdev->ee_wait);
|
wake_up(&mdev->ee_wait);
|
||||||
if (test_bit(__EE_WAS_ERROR, &e->flags))
|
if (test_bit(__EE_WAS_ERROR, &e->flags))
|
||||||
__drbd_chk_io_error(mdev, false);
|
__drbd_chk_io_error(mdev, DRBD_IO_ERROR);
|
||||||
spin_unlock_irqrestore(&mdev->req_lock, flags);
|
spin_unlock_irqrestore(&mdev->req_lock, flags);
|
||||||
|
|
||||||
drbd_queue_work(&mdev->data.work, &e->w);
|
drbd_queue_work(&mdev->data.work, &e->w);
|
||||||
|
@ -154,7 +154,7 @@ static void drbd_endio_write_sec_final(struct drbd_epoch_entry *e) __releases(lo
|
||||||
: list_empty(&mdev->active_ee);
|
: list_empty(&mdev->active_ee);
|
||||||
|
|
||||||
if (test_bit(__EE_WAS_ERROR, &e->flags))
|
if (test_bit(__EE_WAS_ERROR, &e->flags))
|
||||||
__drbd_chk_io_error(mdev, false);
|
__drbd_chk_io_error(mdev, DRBD_IO_ERROR);
|
||||||
spin_unlock_irqrestore(&mdev->req_lock, flags);
|
spin_unlock_irqrestore(&mdev->req_lock, flags);
|
||||||
|
|
||||||
if (is_syncer_req)
|
if (is_syncer_req)
|
||||||
|
@ -1501,14 +1501,6 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mdev->state.conn < C_AHEAD) {
|
|
||||||
/* In case a previous resync run was aborted by an IO error/detach on the peer. */
|
|
||||||
drbd_rs_cancel_all(mdev);
|
|
||||||
/* This should be done when we abort the resync. We definitely do not
|
|
||||||
want to have this for connections going back and forth between
|
|
||||||
Ahead/Behind and SyncSource/SyncTarget */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (side == C_SYNC_TARGET) {
|
if (side == C_SYNC_TARGET) {
|
||||||
/* Since application IO was locked out during C_WF_BITMAP_T and
|
/* Since application IO was locked out during C_WF_BITMAP_T and
|
||||||
C_WF_SYNC_UUID we are still unmodified. Before going to C_SYNC_TARGET
|
C_WF_SYNC_UUID we are still unmodified. Before going to C_SYNC_TARGET
|
||||||
|
|
|
@ -191,6 +191,7 @@ static int print_unex = 1;
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
|
#include <linux/async.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PS/2 floppies have much slower step rates than regular floppies.
|
* PS/2 floppies have much slower step rates than regular floppies.
|
||||||
|
@ -2516,8 +2517,7 @@ static int make_raw_rw_request(void)
|
||||||
set_fdc((long)current_req->rq_disk->private_data);
|
set_fdc((long)current_req->rq_disk->private_data);
|
||||||
|
|
||||||
raw_cmd = &default_raw_cmd;
|
raw_cmd = &default_raw_cmd;
|
||||||
raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK |
|
raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK;
|
||||||
FD_RAW_NEED_SEEK;
|
|
||||||
raw_cmd->cmd_count = NR_RW;
|
raw_cmd->cmd_count = NR_RW;
|
||||||
if (rq_data_dir(current_req) == READ) {
|
if (rq_data_dir(current_req) == READ) {
|
||||||
raw_cmd->flags |= FD_RAW_READ;
|
raw_cmd->flags |= FD_RAW_READ;
|
||||||
|
@ -4123,7 +4123,7 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data)
|
||||||
return get_disk(disks[drive]);
|
return get_disk(disks[drive]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init floppy_init(void)
|
static int __init do_floppy_init(void)
|
||||||
{
|
{
|
||||||
int i, unit, drive;
|
int i, unit, drive;
|
||||||
int err, dr;
|
int err, dr;
|
||||||
|
@ -4338,6 +4338,24 @@ out_put_disk:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef MODULE
|
||||||
|
static __init void floppy_async_init(void *data, async_cookie_t cookie)
|
||||||
|
{
|
||||||
|
do_floppy_init();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int __init floppy_init(void)
|
||||||
|
{
|
||||||
|
#ifdef MODULE
|
||||||
|
return do_floppy_init();
|
||||||
|
#else
|
||||||
|
/* Don't hold up the bootup by the floppy initialization */
|
||||||
|
async_schedule(floppy_async_init, NULL);
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static const struct io_region {
|
static const struct io_region {
|
||||||
int offset;
|
int offset;
|
||||||
int size;
|
int size;
|
||||||
|
|
|
@ -485,7 +485,7 @@ static void nbd_handle_req(struct nbd_device *nbd, struct request *req)
|
||||||
nbd_end_request(req);
|
nbd_end_request(req);
|
||||||
} else {
|
} else {
|
||||||
spin_lock(&nbd->queue_lock);
|
spin_lock(&nbd->queue_lock);
|
||||||
list_add(&req->queuelist, &nbd->queue_head);
|
list_add_tail(&req->queuelist, &nbd->queue_head);
|
||||||
spin_unlock(&nbd->queue_lock);
|
spin_unlock(&nbd->queue_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -513,42 +513,19 @@ static void process_page(unsigned long data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct mm_plug_cb {
|
static void mm_unplug(struct blk_plug_cb *cb, bool from_schedule)
|
||||||
struct blk_plug_cb cb;
|
|
||||||
struct cardinfo *card;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void mm_unplug(struct blk_plug_cb *cb)
|
|
||||||
{
|
{
|
||||||
struct mm_plug_cb *mmcb = container_of(cb, struct mm_plug_cb, cb);
|
struct cardinfo *card = cb->data;
|
||||||
|
|
||||||
spin_lock_irq(&mmcb->card->lock);
|
spin_lock_irq(&card->lock);
|
||||||
activate(mmcb->card);
|
activate(card);
|
||||||
spin_unlock_irq(&mmcb->card->lock);
|
spin_unlock_irq(&card->lock);
|
||||||
kfree(mmcb);
|
kfree(cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mm_check_plugged(struct cardinfo *card)
|
static int mm_check_plugged(struct cardinfo *card)
|
||||||
{
|
{
|
||||||
struct blk_plug *plug = current->plug;
|
return !!blk_check_plugged(mm_unplug, card, sizeof(struct blk_plug_cb));
|
||||||
struct mm_plug_cb *mmcb;
|
|
||||||
|
|
||||||
if (!plug)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
list_for_each_entry(mmcb, &plug->cb_list, cb.list) {
|
|
||||||
if (mmcb->cb.callback == mm_unplug && mmcb->card == card)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
/* Not currently on the callback list */
|
|
||||||
mmcb = kmalloc(sizeof(*mmcb), GFP_ATOMIC);
|
|
||||||
if (!mmcb)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
mmcb->card = card;
|
|
||||||
mmcb->cb.callback = mm_unplug;
|
|
||||||
list_add(&mmcb->cb.list, &plug->cb_list);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mm_make_request(struct request_queue *q, struct bio *bio)
|
static void mm_make_request(struct request_queue *q, struct bio *bio)
|
||||||
|
|
|
@ -498,61 +498,13 @@ void md_flush_request(struct mddev *mddev, struct bio *bio)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(md_flush_request);
|
EXPORT_SYMBOL(md_flush_request);
|
||||||
|
|
||||||
/* Support for plugging.
|
void md_unplug(struct blk_plug_cb *cb, bool from_schedule)
|
||||||
* This mirrors the plugging support in request_queue, but does not
|
|
||||||
* require having a whole queue or request structures.
|
|
||||||
* We allocate an md_plug_cb for each md device and each thread it gets
|
|
||||||
* plugged on. This links tot the private plug_handle structure in the
|
|
||||||
* personality data where we keep a count of the number of outstanding
|
|
||||||
* plugs so other code can see if a plug is active.
|
|
||||||
*/
|
|
||||||
struct md_plug_cb {
|
|
||||||
struct blk_plug_cb cb;
|
|
||||||
struct mddev *mddev;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void plugger_unplug(struct blk_plug_cb *cb)
|
|
||||||
{
|
{
|
||||||
struct md_plug_cb *mdcb = container_of(cb, struct md_plug_cb, cb);
|
struct mddev *mddev = cb->data;
|
||||||
if (atomic_dec_and_test(&mdcb->mddev->plug_cnt))
|
md_wakeup_thread(mddev->thread);
|
||||||
md_wakeup_thread(mdcb->mddev->thread);
|
kfree(cb);
|
||||||
kfree(mdcb);
|
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(md_unplug);
|
||||||
/* Check that an unplug wakeup will come shortly.
|
|
||||||
* If not, wakeup the md thread immediately
|
|
||||||
*/
|
|
||||||
int mddev_check_plugged(struct mddev *mddev)
|
|
||||||
{
|
|
||||||
struct blk_plug *plug = current->plug;
|
|
||||||
struct md_plug_cb *mdcb;
|
|
||||||
|
|
||||||
if (!plug)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
list_for_each_entry(mdcb, &plug->cb_list, cb.list) {
|
|
||||||
if (mdcb->cb.callback == plugger_unplug &&
|
|
||||||
mdcb->mddev == mddev) {
|
|
||||||
/* Already on the list, move to top */
|
|
||||||
if (mdcb != list_first_entry(&plug->cb_list,
|
|
||||||
struct md_plug_cb,
|
|
||||||
cb.list))
|
|
||||||
list_move(&mdcb->cb.list, &plug->cb_list);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Not currently on the callback list */
|
|
||||||
mdcb = kmalloc(sizeof(*mdcb), GFP_ATOMIC);
|
|
||||||
if (!mdcb)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
mdcb->mddev = mddev;
|
|
||||||
mdcb->cb.callback = plugger_unplug;
|
|
||||||
atomic_inc(&mddev->plug_cnt);
|
|
||||||
list_add(&mdcb->cb.list, &plug->cb_list);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(mddev_check_plugged);
|
|
||||||
|
|
||||||
static inline struct mddev *mddev_get(struct mddev *mddev)
|
static inline struct mddev *mddev_get(struct mddev *mddev)
|
||||||
{
|
{
|
||||||
|
@ -602,7 +554,6 @@ void mddev_init(struct mddev *mddev)
|
||||||
atomic_set(&mddev->active, 1);
|
atomic_set(&mddev->active, 1);
|
||||||
atomic_set(&mddev->openers, 0);
|
atomic_set(&mddev->openers, 0);
|
||||||
atomic_set(&mddev->active_io, 0);
|
atomic_set(&mddev->active_io, 0);
|
||||||
atomic_set(&mddev->plug_cnt, 0);
|
|
||||||
spin_lock_init(&mddev->write_lock);
|
spin_lock_init(&mddev->write_lock);
|
||||||
atomic_set(&mddev->flush_pending, 0);
|
atomic_set(&mddev->flush_pending, 0);
|
||||||
init_waitqueue_head(&mddev->sb_wait);
|
init_waitqueue_head(&mddev->sb_wait);
|
||||||
|
|
|
@ -266,9 +266,6 @@ struct mddev {
|
||||||
int new_chunk_sectors;
|
int new_chunk_sectors;
|
||||||
int reshape_backwards;
|
int reshape_backwards;
|
||||||
|
|
||||||
atomic_t plug_cnt; /* If device is expecting
|
|
||||||
* more bios soon.
|
|
||||||
*/
|
|
||||||
struct md_thread *thread; /* management thread */
|
struct md_thread *thread; /* management thread */
|
||||||
struct md_thread *sync_thread; /* doing resync or reconstruct */
|
struct md_thread *sync_thread; /* doing resync or reconstruct */
|
||||||
sector_t curr_resync; /* last block scheduled */
|
sector_t curr_resync; /* last block scheduled */
|
||||||
|
@ -630,6 +627,12 @@ extern struct bio *bio_clone_mddev(struct bio *bio, gfp_t gfp_mask,
|
||||||
struct mddev *mddev);
|
struct mddev *mddev);
|
||||||
extern struct bio *bio_alloc_mddev(gfp_t gfp_mask, int nr_iovecs,
|
extern struct bio *bio_alloc_mddev(gfp_t gfp_mask, int nr_iovecs,
|
||||||
struct mddev *mddev);
|
struct mddev *mddev);
|
||||||
extern int mddev_check_plugged(struct mddev *mddev);
|
|
||||||
extern void md_trim_bio(struct bio *bio, int offset, int size);
|
extern void md_trim_bio(struct bio *bio, int offset, int size);
|
||||||
|
|
||||||
|
extern void md_unplug(struct blk_plug_cb *cb, bool from_schedule);
|
||||||
|
static inline int mddev_check_plugged(struct mddev *mddev)
|
||||||
|
{
|
||||||
|
return !!blk_check_plugged(md_unplug, mddev,
|
||||||
|
sizeof(struct blk_plug_cb));
|
||||||
|
}
|
||||||
#endif /* _MD_MD_H */
|
#endif /* _MD_MD_H */
|
||||||
|
|
|
@ -2247,8 +2247,7 @@ static void raid1d(struct mddev *mddev)
|
||||||
blk_start_plug(&plug);
|
blk_start_plug(&plug);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
||||||
if (atomic_read(&mddev->plug_cnt) == 0)
|
flush_pending_writes(conf);
|
||||||
flush_pending_writes(conf);
|
|
||||||
|
|
||||||
spin_lock_irqsave(&conf->device_lock, flags);
|
spin_lock_irqsave(&conf->device_lock, flags);
|
||||||
if (list_empty(head)) {
|
if (list_empty(head)) {
|
||||||
|
|
|
@ -2680,8 +2680,7 @@ static void raid10d(struct mddev *mddev)
|
||||||
blk_start_plug(&plug);
|
blk_start_plug(&plug);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
||||||
if (atomic_read(&mddev->plug_cnt) == 0)
|
flush_pending_writes(conf);
|
||||||
flush_pending_writes(conf);
|
|
||||||
|
|
||||||
spin_lock_irqsave(&conf->device_lock, flags);
|
spin_lock_irqsave(&conf->device_lock, flags);
|
||||||
if (list_empty(head)) {
|
if (list_empty(head)) {
|
||||||
|
|
|
@ -4562,7 +4562,7 @@ static void raid5d(struct mddev *mddev)
|
||||||
while (1) {
|
while (1) {
|
||||||
struct bio *bio;
|
struct bio *bio;
|
||||||
|
|
||||||
if (atomic_read(&mddev->plug_cnt) == 0 &&
|
if (
|
||||||
!list_empty(&conf->bitmap_list)) {
|
!list_empty(&conf->bitmap_list)) {
|
||||||
/* Now is a good time to flush some bitmap updates */
|
/* Now is a good time to flush some bitmap updates */
|
||||||
conf->seq_flush++;
|
conf->seq_flush++;
|
||||||
|
@ -4572,8 +4572,7 @@ static void raid5d(struct mddev *mddev)
|
||||||
conf->seq_write = conf->seq_flush;
|
conf->seq_write = conf->seq_flush;
|
||||||
activate_bit_delay(conf);
|
activate_bit_delay(conf);
|
||||||
}
|
}
|
||||||
if (atomic_read(&mddev->plug_cnt) == 0)
|
raid5_activate_delayed(conf);
|
||||||
raid5_activate_delayed(conf);
|
|
||||||
|
|
||||||
while ((bio = remove_bio_from_retry(conf))) {
|
while ((bio = remove_bio_from_retry(conf))) {
|
||||||
int ok;
|
int ok;
|
||||||
|
|
|
@ -922,11 +922,15 @@ struct blk_plug {
|
||||||
};
|
};
|
||||||
#define BLK_MAX_REQUEST_COUNT 16
|
#define BLK_MAX_REQUEST_COUNT 16
|
||||||
|
|
||||||
|
struct blk_plug_cb;
|
||||||
|
typedef void (*blk_plug_cb_fn)(struct blk_plug_cb *, bool);
|
||||||
struct blk_plug_cb {
|
struct blk_plug_cb {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
void (*callback)(struct blk_plug_cb *);
|
blk_plug_cb_fn callback;
|
||||||
|
void *data;
|
||||||
};
|
};
|
||||||
|
extern struct blk_plug_cb *blk_check_plugged(blk_plug_cb_fn unplug,
|
||||||
|
void *data, int size);
|
||||||
extern void blk_start_plug(struct blk_plug *);
|
extern void blk_start_plug(struct blk_plug *);
|
||||||
extern void blk_finish_plug(struct blk_plug *);
|
extern void blk_finish_plug(struct blk_plug *);
|
||||||
extern void blk_flush_plug_list(struct blk_plug *, bool);
|
extern void blk_flush_plug_list(struct blk_plug *, bool);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче