drbd: cleanup, drop unused struct
[cascardo/linux.git] / drivers / block / drbd / drbd_int.h
index 0fb3fc3..e5c9853 100644 (file)
@@ -164,16 +164,9 @@ drbd_insert_fault(struct drbd_conf *mdev, unsigned int type) {
 /* usual integer division */
 #define div_floor(A, B) ((A)/(B))
 
-/* drbd_meta-data.c (still in drbd_main.c) */
-/* 4th incarnation of the disk layout. */
-#define DRBD_MD_MAGIC (DRBD_MAGIC+4)
-
 extern struct ratelimit_state drbd_ratelimit_state;
-extern struct idr minors;
-extern struct list_head drbd_tconns;
-extern struct rw_semaphore drbd_cfg_rwsem;
-/* drbd_cfg_rwsem protects: drbd_tconns list, minors idr, tconn->volumes idr 
-   note: non sleeping iterations over the idrs are protoected by RCU */
+extern struct idr minors; /* RCU, updates: genl_lock() */
+extern struct list_head drbd_tconns; /* RCU, updates: genl_lock() */
 
 /* on the wire */
 enum drbd_packet {
@@ -228,6 +221,7 @@ enum drbd_packet {
        P_CONN_ST_CHG_REQ     = 0x2a, /* data sock: Connection wide state request */
        P_CONN_ST_CHG_REPLY   = 0x2b, /* meta sock: Connection side state req reply */
        P_RETRY_WRITE         = 0x2c, /* Protocol C: retry conflicting write request */
+       P_PROTOCOL_UPDATE     = 0x2d, /* data sock: is used in established connections */
 
        P_MAY_IGNORE          = 0x100, /* Flag to test if (cmd > P_MAY_IGNORE) ... */
        P_MAX_OPT_CMD         = 0x101,
@@ -374,11 +368,11 @@ struct p_connection_features {
        u32 protocol_max;
 
        /* should be more than enough for future enhancements
-        * for now, feature_flags and the reserverd array shall be zero.
+        * for now, feature_flags and the reserved array shall be zero.
         */
 
        u32 _pad;
-       u64 reserverd[7];
+       u64 reserved[7];
 } __packed;
 
 struct p_barrier {
@@ -392,21 +386,21 @@ struct p_barrier_ack {
 } __packed;
 
 struct p_rs_param {
-       u32 rate;
+       u32 resync_rate;
 
              /* Since protocol version 88 and higher. */
        char verify_alg[0];
 } __packed;
 
 struct p_rs_param_89 {
-       u32 rate;
+       u32 resync_rate;
         /* protocol version 89: */
        char verify_alg[SHARED_SECRET_MAX];
        char csums_alg[SHARED_SECRET_MAX];
 } __packed;
 
 struct p_rs_param_95 {
-       u32 rate;
+       u32 resync_rate;
        char verify_alg[SHARED_SECRET_MAX];
        char csums_alg[SHARED_SECRET_MAX];
        u32 c_plan_ahead;
@@ -416,7 +410,7 @@ struct p_rs_param_95 {
 } __packed;
 
 enum drbd_conn_flags {
-       CF_WANT_LOSE = 1,
+       CF_DISCARD_MY_DATA = 1,
        CF_DRY_RUN = 2,
 };
 
@@ -473,12 +467,6 @@ struct p_drbd06_param {
        u32       bit_map_gen[5];
 } __packed;
 
-struct p_discard {
-       u64         block_id;
-       u32         seq_num;
-       u32         pad;
-} __packed;
-
 struct p_block_desc {
        u64 sector;
        u32 blksize;
@@ -568,29 +556,31 @@ struct drbd_request {
        struct bio *private_bio;
 
        struct drbd_interval i;
-       unsigned int epoch; /* barrier_nr */
 
-       /* barrier_nr: used to check on "completion" whether this req was in
+       /* epoch: used to check on "completion" whether this req was in
         * the current epoch, and we therefore have to close it,
-        * starting a new epoch...
+        * causing a p_barrier packet to be send, starting a new epoch.
+        *
+        * This corresponds to "barrier" in struct p_barrier[_ack],
+        * and to "barrier_nr" in struct drbd_epoch (and various
+        * comments/function parameters/local variable names).
         */
+       unsigned int epoch;
 
        struct list_head tl_requests; /* ring list in the transfer log */
        struct bio *master_bio;       /* master bio pointer */
-       unsigned long rq_state; /* see comments above _req_mod() */
-       int seq_num;
        unsigned long start_time;
-};
 
-struct drbd_tl_epoch {
-       struct drbd_work w;
-       struct list_head requests; /* requests before */
-       struct drbd_tl_epoch *next; /* pointer to the next barrier */
-       unsigned int br_number;  /* the barriers identifier. */
-       int n_writes;   /* number of requests attached before this barrier */
+       /* once it hits 0, we may complete the master_bio */
+       atomic_t completion_ref;
+       /* once it hits 0, we may destroy this drbd_request object */
+       struct kref kref;
+
+       unsigned rq_state; /* see comments above _req_mod() */
 };
 
 struct drbd_epoch {
+       struct drbd_tconn *tconn;
        struct list_head list;
        unsigned int barrier_nr;
        atomic_t epoch_size; /* increased on every request added. */
@@ -676,8 +666,6 @@ enum {
 
 /* flag bits per mdev */
 enum {
-       CREATE_BARRIER,         /* next P_DATA is preceded by a P_BARRIER */
-       UNPLUG_QUEUED,          /* only relevant with kernel 2.4 */
        UNPLUG_REMOTE,          /* sending a "UnplugRemote" could help */
        MD_DIRTY,               /* current uuids and flags not yet on disk */
        USE_DEGR_WFC_T,         /* degr-wfc-timeout instead of wfc-timeout. */
@@ -686,7 +674,6 @@ enum {
        CRASHED_PRIMARY,        /* This node was a crashed primary.
                                 * Gets cleared when the state.conn
                                 * goes into C_CONNECTED state. */
-       NO_BARRIER_SUPP,        /* underlying block device doesn't implement barriers */
        CONSIDER_RESYNC,
 
        MD_NO_FUA,              /* Users wants us to not use FUA/FLUSH on meta data dev */
@@ -696,6 +683,7 @@ enum {
        BITMAP_IO_QUEUED,       /* Started bitmap IO */
        GO_DISKLESS,            /* Disk is being detached, on io-error or admin request. */
        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. */
        RESIZE_PENDING,         /* Size change detected locally, waiting for the response from
                                 * the peer, if it changed there as well. */
@@ -703,6 +691,8 @@ enum {
        AL_SUSPENDED,           /* Activity logging is currently suspended. */
        AHEAD_TO_SYNC_SOURCE,   /* Ahead -> SyncSource queued */
        B_RS_H_DONE,            /* Before resync handler done (already executed) */
+       DISCARD_MY_DATA,        /* discard_my_data flag per volume */
+       READ_BALANCE_RR,
 };
 
 struct drbd_bitmap; /* opaque for drbd_conf */
@@ -714,39 +704,37 @@ enum bm_flag {
        BM_P_VMALLOCED = 0x10000, /* internal use only, will be masked out */
 
        /* currently locked for bulk operation */
-       BM_LOCKED_MASK = 0x7,
+       BM_LOCKED_MASK = 0xf,
 
        /* in detail, that is: */
        BM_DONT_CLEAR = 0x1,
        BM_DONT_SET   = 0x2,
        BM_DONT_TEST  = 0x4,
 
+       /* so we can mark it locked for bulk operation,
+        * and still allow all non-bulk operations */
+       BM_IS_LOCKED  = 0x8,
+
        /* (test bit, count bit) allowed (common case) */
-       BM_LOCKED_TEST_ALLOWED = 0x3,
+       BM_LOCKED_TEST_ALLOWED = BM_DONT_CLEAR | BM_DONT_SET | BM_IS_LOCKED,
 
        /* testing bits, as well as setting new bits allowed, but clearing bits
         * would be unexpected.  Used during bitmap receive.  Setting new bits
         * requires sending of "out-of-sync" information, though. */
-       BM_LOCKED_SET_ALLOWED = 0x1,
+       BM_LOCKED_SET_ALLOWED = BM_DONT_CLEAR | BM_IS_LOCKED,
 
-       /* clear is not expected while bitmap is locked for bulk operation */
+       /* for drbd_bm_write_copy_pages, everything is allowed,
+        * only concurrent bulk operations are locked out. */
+       BM_LOCKED_CHANGE_ALLOWED = BM_IS_LOCKED,
 };
 
-
-/* TODO sort members for performance
- * MAYBE group them further */
-
-/* THINK maybe we actually want to use the default "event/%s" worker threads
- * or similar in linux 2.6, which uses per cpu data and threads.
- */
 struct drbd_work_queue {
        struct list_head q;
-       struct semaphore s; /* producers up it, worker down()s it */
        spinlock_t q_lock;  /* to protect the list. */
+       wait_queue_head_t q_wait;
 };
 
 struct drbd_socket {
-       struct drbd_work_queue work;
        struct mutex mutex;
        struct socket    *socket;
        /* this way we get our
@@ -777,13 +765,12 @@ struct drbd_backing_dev {
        struct block_device *backing_bdev;
        struct block_device *md_bdev;
        struct drbd_md md;
-       struct disk_conf dc; /* The user provided config... */
+       struct disk_conf *disk_conf; /* RCU, for updates: mdev->tconn->conf_update */
        sector_t known_size; /* last known size of that backing device */
 };
 
 struct drbd_md_io {
-       struct drbd_conf *mdev;
-       struct completion event;
+       unsigned int done;
        int error;
 };
 
@@ -802,10 +789,12 @@ enum write_ordering_e {
 };
 
 struct fifo_buffer {
-       int *values;
        unsigned int head_index;
        unsigned int size;
+       int total; /* sum of all values */
+       int values[0];
 };
+extern struct fifo_buffer *fifo_alloc(int fifo_size);
 
 /* flag bits per tconn */
 enum {
@@ -814,20 +803,24 @@ enum {
        SEND_PING,              /* whether asender should send a ping asap */
        SIGNAL_ASENDER,         /* whether asender wants to be interrupted */
        GOT_PING_ACK,           /* set when we receive a ping_ack packet, ping_wait gets woken */
+       CONN_WD_ST_CHG_REQ,     /* A cluster wide state change on the connection is active */
        CONN_WD_ST_CHG_OKAY,
        CONN_WD_ST_CHG_FAIL,
-       CONFIG_PENDING,         /* serialization of (re)configuration requests.
-                                * if set, also prevents the device from dying */
-       OBJECT_DYING,           /* device became unconfigured,
-                                * but worker thread is still handling the cleanup.
-                                * reconfiguring (nl_disk_conf, nl_net_conf) is dissalowed,
-                                * while this is set. */
        CONN_DRY_RUN,           /* Expect disconnect after resync handshake. */
+       CREATE_BARRIER,         /* next P_DATA is preceded by a P_BARRIER */
+       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_tconn {                    /* is a resource from the config file */
        char *name;                     /* Resource name */
        struct list_head all_tconn;     /* linked on global drbd_tconns */
+       struct kref kref;
        struct idr volumes;             /* <tconn, vnr> to mdev mapping */
        enum drbd_conns cstate;         /* Only C_STANDALONE to C_WF_REPORT_PARAMS */
        unsigned susp:1;                /* IO suspended by user */
@@ -837,10 +830,15 @@ struct drbd_tconn {                       /* is a resource from the config file */
 
        unsigned long flags;
        struct net_conf *net_conf;      /* content protected by rcu */
-       struct mutex net_conf_update;   /* mutex for ready-copy-update of net_conf */
+       struct mutex conf_update;       /* mutex for ready-copy-update of net_conf and disk_conf */
        wait_queue_head_t ping_wait;    /* Woken upon reception of a ping, and a state change */
        struct res_opts res_opts;
 
+       struct sockaddr_storage my_addr;
+       int my_addr_len;
+       struct sockaddr_storage peer_addr;
+       int peer_addr_len;
+
        struct drbd_socket data;        /* data/barrier/cstate/parameter packets */
        struct drbd_socket meta;        /* ping/ack (metadata) packets */
        int agreed_pro_version;         /* actually used protocol version */
@@ -848,28 +846,53 @@ struct drbd_tconn {                       /* is a resource from the config file */
        unsigned int ko_count;
 
        spinlock_t req_lock;
-       struct drbd_tl_epoch *unused_spare_tle; /* for pre-allocation */
-       struct drbd_tl_epoch *newest_tle;
-       struct drbd_tl_epoch *oldest_tle;
-       struct list_head out_of_sequence_requests;
+
+       struct list_head transfer_log;  /* all requests not yet fully processed */
 
        struct crypto_hash *cram_hmac_tfm;
-       struct crypto_hash *integrity_w_tfm; /* to be used by the worker thread */
-       struct crypto_hash *integrity_r_tfm; /* to be used by the receiver thread */
+       struct crypto_hash *integrity_tfm;  /* checksums we compute, updates protected by tconn->data->mutex */
+       struct crypto_hash *peer_integrity_tfm;  /* checksums we verify, only accessed from receiver thread  */
        struct crypto_hash *csums_tfm;
        struct crypto_hash *verify_tfm;
        void *int_dig_in;
        void *int_dig_vv;
 
+       /* receiver side */
+       struct drbd_epoch *current_epoch;
+       spinlock_t epoch_lock;
+       unsigned int epochs;
+       enum write_ordering_e write_ordering;
+       atomic_t current_tle_nr;        /* transfer log epoch number */
+       unsigned current_tle_writes;    /* writes seen within this tl epoch */
+
+       unsigned long last_reconnect_jif;
        struct drbd_thread receiver;
        struct drbd_thread worker;
        struct drbd_thread asender;
        cpumask_var_t cpu_mask;
+
+       /* sender side */
+       struct drbd_work_queue sender_work;
+
+       struct {
+               /* whether this sender thread
+                * has processed a single write yet. */
+               bool seen_any_write_yet;
+
+               /* Which barrier number to send with the next P_BARRIER */
+               int current_epoch_nr;
+
+               /* how many write requests have been sent
+                * with req->epoch == current_epoch_nr.
+                * If none, no P_BARRIER will be sent. */
+               unsigned current_epoch_writes;
+       } send;
 };
 
 struct drbd_conf {
        struct drbd_tconn *tconn;
        int vnr;                        /* volume number within the connection */
+       struct kref kref;
 
        /* things that are stored as / read from meta data on disk */
        unsigned long flags;
@@ -882,6 +905,7 @@ struct drbd_conf {
        struct block_device *this_bdev;
        struct gendisk      *vdisk;
 
+       unsigned long last_reattach_jif;
        struct drbd_work  resync_work,
                          unplug_work,
                          go_diskless,
@@ -913,7 +937,7 @@ struct drbd_conf {
        atomic_t ap_bio_cnt;     /* Requests we need to complete */
        atomic_t ap_pending_cnt; /* AP data packets on the wire, ack expected */
        atomic_t rs_pending_cnt; /* RS request/data packets on the wire */
-       atomic_t unacked_cnt;    /* Need to send replys for */
+       atomic_t unacked_cnt;    /* Need to send replies for */
        atomic_t local_cnt;      /* Waiting for local completion */
 
        /* Interval tree of pending local requests */
@@ -941,6 +965,7 @@ struct drbd_conf {
 
        /* where does the admin want us to start? (sector) */
        sector_t ov_start_sector;
+       sector_t ov_stop_sector;
        /* where are we now? (sector) */
        sector_t ov_position;
        /* Start sector of out of sync range (to merge printk reporting). */
@@ -961,10 +986,7 @@ struct drbd_conf {
 
        int open_cnt;
        u64 *p_uuid;
-       struct drbd_epoch *current_epoch;
-       spinlock_t epoch_lock;
-       unsigned int epochs;
-       enum write_ordering_e write_ordering;
+
        struct list_head active_ee; /* IO in progress (P_DATA gets written to disk) */
        struct list_head sync_ee;   /* IO in progress (P_RS_DATA_REPLY gets written to disk) */
        struct list_head done_ee;   /* need to send P_WRITE_ACK */
@@ -977,7 +999,8 @@ struct drbd_conf {
        atomic_t pp_in_use_by_net;      /* sendpage()d, still referenced by tcp */
        wait_queue_head_t ee_wait;
        struct page *md_io_page;        /* one page buffer for md_io */
-       struct mutex md_io_mutex;       /* protects the md_io_buffer */
+       struct drbd_md_io md_io;
+       atomic_t md_io_in_use;          /* protects the md_io, md_io_page and md_io_tmpp */
        spinlock_t al_lock;
        wait_queue_head_t al_wait;
        struct lru_cache *act_log;      /* activity log */
@@ -1001,9 +1024,8 @@ struct drbd_conf {
        int rs_last_events;  /* counter of read or write "events" (unit sectors)
                              * on the lower level device when we last looked. */
        int c_sync_rate; /* current resync rate after syncer throttle magic */
-       struct fifo_buffer rs_plan_s; /* correction values of resync planer */
+       struct fifo_buffer *rs_plan_s; /* correction values of resync planer (RCU, tconn->conn_update) */
        int rs_in_flight; /* resync sectors in flight (to proxy, in proxy and from proxy) */
-       int rs_planed;    /* resync sectors already planned */
        atomic_t ap_in_flight; /* App sectors in flight (waiting for ack) */
        int peer_max_bio_size;
        int local_max_bio_size;
@@ -1049,24 +1071,22 @@ extern void drbd_calc_cpu_mask(struct drbd_tconn *tconn);
 extern void tl_release(struct drbd_tconn *, unsigned int barrier_nr,
                       unsigned int set_size);
 extern void tl_clear(struct drbd_tconn *);
-extern void _tl_add_barrier(struct drbd_tconn *, struct drbd_tl_epoch *);
 extern void drbd_free_sock(struct drbd_tconn *tconn);
 extern int drbd_send(struct drbd_tconn *tconn, struct socket *sock,
                     void *buf, size_t size, unsigned msg_flags);
 extern int drbd_send_all(struct drbd_tconn *, struct socket *, void *, size_t,
                         unsigned);
 
+extern int __drbd_send_protocol(struct drbd_tconn *tconn, enum drbd_packet cmd);
 extern int drbd_send_protocol(struct drbd_tconn *tconn);
 extern int drbd_send_uuids(struct drbd_conf *mdev);
 extern int drbd_send_uuids_skip_initial_sync(struct drbd_conf *mdev);
 extern void drbd_gen_and_send_sync_uuid(struct drbd_conf *mdev);
 extern int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags flags);
-extern int _conn_send_state_req(struct drbd_tconn *, int vnr, enum drbd_packet cmd,
-                               union drbd_state, union drbd_state);
-extern int _drbd_send_state(struct drbd_conf *mdev);
-extern int drbd_send_state(struct drbd_conf *mdev);
+extern int drbd_send_state(struct drbd_conf *mdev, union drbd_state s);
+extern int drbd_send_current_state(struct drbd_conf *mdev);
 extern int drbd_send_sync_param(struct drbd_conf *mdev);
-extern void drbd_send_b_ack(struct drbd_conf *mdev, u32 barrier_nr,
+extern void drbd_send_b_ack(struct drbd_tconn *tconn, u32 barrier_nr,
                            u32 set_size);
 extern int drbd_send_ack(struct drbd_conf *, enum drbd_packet,
                         struct drbd_peer_request *);
@@ -1283,7 +1303,8 @@ struct bm_extent {
 #endif
 #define DRBD_MAX_BIO_SIZE_SAFE (1 << 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 (1 << 15) /* Header 80 only allows packets up to 32KiB data */
+#define DRBD_MAX_BIO_SIZE_P95    (1 << 17) /* Protocol 95 to 99 allows bios up to 128KiB */
 
 extern int  drbd_bm_init(struct drbd_conf *mdev);
 extern int  drbd_bm_resize(struct drbd_conf *mdev, sector_t sectors, int set_new_bits);
@@ -1308,8 +1329,7 @@ extern int  drbd_bm_read(struct drbd_conf *mdev) __must_hold(local);
 extern void drbd_bm_mark_for_writeout(struct drbd_conf *mdev, int page_nr);
 extern int  drbd_bm_write(struct drbd_conf *mdev) __must_hold(local);
 extern int  drbd_bm_write_hinted(struct drbd_conf *mdev) __must_hold(local);
-extern unsigned long drbd_bm_ALe_set_all(struct drbd_conf *mdev,
-               unsigned long al_enr);
+extern int  drbd_bm_write_copy_pages(struct drbd_conf *mdev) __must_hold(local);
 extern size_t       drbd_bm_words(struct drbd_conf *mdev);
 extern unsigned long drbd_bm_bits(struct drbd_conf *mdev);
 extern sector_t      drbd_bm_capacity(struct drbd_conf *mdev);
@@ -1376,17 +1396,20 @@ extern rwlock_t global_state_lock;
 
 extern int conn_lowest_minor(struct drbd_tconn *tconn);
 enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor, int vnr);
-extern void drbd_delete_device(struct drbd_conf *mdev);
-
-struct drbd_tconn *drbd_new_tconn(const char *name);
-extern void drbd_free_tconn(struct drbd_tconn *tconn);
-struct drbd_tconn *conn_by_name(const char *name);
+extern void drbd_minor_destroy(struct kref *kref);
+
+extern int set_resource_options(struct drbd_tconn *tconn, struct res_opts *res_opts);
+extern struct drbd_tconn *conn_create(const char *name, struct res_opts *res_opts);
+extern void conn_destroy(struct kref *kref);
+struct drbd_tconn *conn_get_by_name(const char *name);
+extern struct drbd_tconn *conn_get_by_addrs(void *my_addr, int my_addr_len,
+                                           void *peer_addr, int peer_addr_len);
 extern void conn_free_crypto(struct drbd_tconn *tconn);
 
 extern int proc_details;
 
 /* drbd_req */
-extern int __drbd_make_request(struct drbd_conf *, struct bio *, unsigned long);
+extern void __drbd_make_request(struct drbd_conf *, struct bio *, unsigned long);
 extern int drbd_make_request(struct request_queue *q, struct bio *bio);
 extern int drbd_read_remote(struct drbd_conf *mdev, struct drbd_request *req);
 extern int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct bio_vec *bvec);
@@ -1398,7 +1421,7 @@ extern int drbd_msg_put_info(const char *info);
 extern void drbd_suspend_io(struct drbd_conf *mdev);
 extern void drbd_resume_io(struct drbd_conf *mdev);
 extern char *ppsize(char *buf, unsigned long long size);
-extern sector_t drbd_new_dev_size(struct drbd_conf *, struct drbd_backing_dev *, int);
+extern sector_t drbd_new_dev_size(struct drbd_conf *, struct drbd_backing_dev *, sector_t, int);
 enum determine_dev_size { dev_size_error = -1, unchanged = 0, shrunk = 1, grew = 2 };
 extern enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *, enum dds_flags) __must_hold(local);
 extern void resync_after_online_grow(struct drbd_conf *);
@@ -1412,15 +1435,20 @@ extern int drbd_khelper(struct drbd_conf *mdev, char *cmd);
 
 /* drbd_worker.c */
 extern int drbd_worker(struct drbd_thread *thi);
-extern int drbd_alter_sa(struct drbd_conf *mdev, int na);
+enum drbd_ret_code drbd_resync_after_valid(struct drbd_conf *mdev, int o_minor);
+void drbd_resync_after_changed(struct drbd_conf *mdev);
 extern void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side);
 extern void resume_next_sg(struct drbd_conf *mdev);
 extern void suspend_other_sg(struct drbd_conf *mdev);
 extern int drbd_resync_finished(struct drbd_conf *mdev);
 /* maybe rather drbd_main.c ? */
+extern void *drbd_md_get_buffer(struct drbd_conf *mdev);
+extern void drbd_md_put_buffer(struct drbd_conf *mdev);
 extern int drbd_md_sync_page_io(struct drbd_conf *mdev,
                struct drbd_backing_dev *bdev, sector_t sector, int rw);
 extern void drbd_ov_out_of_sync_found(struct drbd_conf *, sector_t, int);
+extern void wait_until_done_or_disk_failure(struct drbd_conf *mdev, struct drbd_backing_dev *bdev,
+                                           unsigned int *done);
 extern void drbd_rs_controller_reset(struct drbd_conf *mdev);
 
 static inline void ov_out_of_sync_print(struct drbd_conf *mdev)
@@ -1438,7 +1466,6 @@ extern void drbd_csum_bio(struct drbd_conf *, struct crypto_hash *, struct bio *
 extern void drbd_csum_ee(struct drbd_conf *, struct crypto_hash *,
                         struct drbd_peer_request *, void *);
 /* worker callbacks */
-extern int w_read_retry_remote(struct drbd_work *, int);
 extern int w_e_end_data_req(struct drbd_work *, int);
 extern int w_e_end_rsdata_req(struct drbd_work *, int);
 extern int w_e_end_csum_rs_req(struct drbd_work *, int);
@@ -1449,7 +1476,6 @@ extern int w_resync_timer(struct drbd_work *, int);
 extern int w_send_write_hint(struct drbd_work *, int);
 extern int w_make_resync_request(struct drbd_work *, int);
 extern int w_send_dblock(struct drbd_work *, int);
-extern int w_send_barrier(struct drbd_work *, int);
 extern int w_send_read_req(struct drbd_work *, int);
 extern int w_prev_work_done(struct drbd_work *, int);
 extern int w_e_reissue(struct drbd_work *, int);
@@ -1477,7 +1503,7 @@ extern struct page *drbd_alloc_pages(struct drbd_conf *, unsigned int, bool);
 extern void drbd_set_recv_tcq(struct drbd_conf *mdev, int tcq_enabled);
 extern void _drbd_clear_done_ee(struct drbd_conf *mdev, struct list_head *to_be_freed);
 extern void conn_flush_workqueue(struct drbd_tconn *tconn);
-extern int drbd_connected(int vnr, void *p, void *data);
+extern int drbd_connected(struct drbd_conf *mdev);
 static inline void drbd_flush_workqueue(struct drbd_conf *mdev)
 {
        conn_flush_workqueue(mdev->tconn);
@@ -1532,7 +1558,7 @@ static inline void drbd_tcp_quickack(struct socket *sock)
                        (char*)&val, sizeof(val));
 }
 
-void drbd_bump_write_ordering(struct drbd_conf *mdev, enum write_ordering_e wo);
+void drbd_bump_write_ordering(struct drbd_tconn *tconn, enum write_ordering_e wo);
 
 /* drbd_proc.c */
 extern struct proc_dir_entry *drbd_proc;
@@ -1550,7 +1576,6 @@ extern void drbd_rs_cancel_all(struct drbd_conf *mdev);
 extern int drbd_rs_del_all(struct drbd_conf *mdev);
 extern void drbd_rs_failed_io(struct drbd_conf *mdev,
                sector_t sector, int size);
-extern int drbd_al_read_log(struct drbd_conf *mdev, struct drbd_backing_dev *);
 extern void drbd_advance_rs_marks(struct drbd_conf *mdev, unsigned long still_to_go);
 extern void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector,
                int size, const char *file, const unsigned int line);
@@ -1560,7 +1585,6 @@ extern int __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector,
                int size, const char *file, const unsigned int line);
 #define drbd_set_out_of_sync(mdev, sector, size) \
        __drbd_set_out_of_sync(mdev, sector, size, __FILE__, __LINE__)
-extern void drbd_al_apply_to_bm(struct drbd_conf *mdev);
 extern void drbd_al_shrink(struct drbd_conf *mdev);
 
 /* drbd_nl.c */
@@ -1595,18 +1619,6 @@ static inline struct page *page_chain_next(struct page *page)
 #define page_chain_for_each_safe(page, n) \
        for (; page && ({ n = page_chain_next(page); 1; }); page = n)
 
-static inline int drbd_bio_has_active_page(struct bio *bio)
-{
-       struct bio_vec *bvec;
-       int i;
-
-       __bio_for_each_segment(bvec, bio, i, 0) {
-               if (page_count(bvec->bv_page) > 1)
-                       return 1;
-       }
-
-       return 0;
-}
 
 static inline int drbd_peer_req_has_active_page(struct drbd_peer_request *peer_req)
 {
@@ -1643,12 +1655,25 @@ static inline union drbd_state drbd_read_state(struct drbd_conf *mdev)
        return rv;
 }
 
+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__)
-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) {
-       case EP_PASS_ON:
-               if (!forcedetach) {
+       enum drbd_io_error_p ep;
+
+       rcu_read_lock();
+       ep = rcu_dereference(mdev->ldev->disk_conf)->on_io_error;
+       rcu_read_unlock();
+       switch (ep) {
+       case EP_PASS_ON: /* FIXME would this be better named "Ignore"? */
+               if (forcedetach == DRBD_IO_ERROR) {
                        if (__ratelimit(&drbd_ratelimit_state))
                                dev_err(DEV, "Local IO failed in %s.\n", where);
                        if (mdev->state.disk > D_INCONSISTENT)
@@ -1659,6 +1684,8 @@ static inline void __drbd_chk_io_error_(struct drbd_conf *mdev, int forcedetach,
        case EP_DETACH:
        case EP_CALL_HELPER:
                set_bit(WAS_IO_ERROR, &mdev->flags);
+               if (forcedetach == DRBD_FORCE_DETACH)
+                       set_bit(FORCE_DETACH, &mdev->flags);
                if (mdev->state.disk > D_FAILED) {
                        _drbd_set_state(_NS(mdev, disk, D_FAILED), CS_HARD, NULL);
                        dev_err(DEV,
@@ -1678,7 +1705,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__)
 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) {
                unsigned long flags;
@@ -1696,9 +1723,9 @@ static inline void drbd_chk_io_error_(struct drbd_conf *mdev,
  * BTW, for internal meta data, this happens to be the maximum capacity
  * we could agree upon with our peer node.
  */
-static inline sector_t drbd_md_first_sector(struct drbd_backing_dev *bdev)
+static inline sector_t _drbd_md_first_sector(int meta_dev_idx, struct drbd_backing_dev *bdev)
 {
-       switch (bdev->dc.meta_dev_idx) {
+       switch (meta_dev_idx) {
        case DRBD_MD_INDEX_INTERNAL:
        case DRBD_MD_INDEX_FLEX_INT:
                return bdev->md.md_offset + bdev->md.bm_offset;
@@ -1708,13 +1735,30 @@ static inline sector_t drbd_md_first_sector(struct drbd_backing_dev *bdev)
        }
 }
 
+static inline sector_t drbd_md_first_sector(struct drbd_backing_dev *bdev)
+{
+       int meta_dev_idx;
+
+       rcu_read_lock();
+       meta_dev_idx = rcu_dereference(bdev->disk_conf)->meta_dev_idx;
+       rcu_read_unlock();
+
+       return _drbd_md_first_sector(meta_dev_idx, bdev);
+}
+
 /**
  * drbd_md_last_sector() - Return the last sector number of the meta data area
  * @bdev:      Meta data block device.
  */
 static inline sector_t drbd_md_last_sector(struct drbd_backing_dev *bdev)
 {
-       switch (bdev->dc.meta_dev_idx) {
+       int meta_dev_idx;
+
+       rcu_read_lock();
+       meta_dev_idx = rcu_dereference(bdev->disk_conf)->meta_dev_idx;
+       rcu_read_unlock();
+
+       switch (meta_dev_idx) {
        case DRBD_MD_INDEX_INTERNAL:
        case DRBD_MD_INDEX_FLEX_INT:
                return bdev->md.md_offset + MD_AL_OFFSET - 1;
@@ -1742,12 +1786,18 @@ static inline sector_t drbd_get_capacity(struct block_device *bdev)
 static inline sector_t drbd_get_max_capacity(struct drbd_backing_dev *bdev)
 {
        sector_t s;
-       switch (bdev->dc.meta_dev_idx) {
+       int meta_dev_idx;
+
+       rcu_read_lock();
+       meta_dev_idx = rcu_dereference(bdev->disk_conf)->meta_dev_idx;
+       rcu_read_unlock();
+
+       switch (meta_dev_idx) {
        case DRBD_MD_INDEX_INTERNAL:
        case DRBD_MD_INDEX_FLEX_INT:
                s = drbd_get_capacity(bdev->backing_bdev)
                        ? min_t(sector_t, DRBD_MAX_SECTORS_FLEX,
-                                       drbd_md_first_sector(bdev))
+                               _drbd_md_first_sector(meta_dev_idx, bdev))
                        : 0;
                break;
        case DRBD_MD_INDEX_FLEX_EXT:
@@ -1773,9 +1823,15 @@ static inline sector_t drbd_get_max_capacity(struct drbd_backing_dev *bdev)
 static inline sector_t drbd_md_ss__(struct drbd_conf *mdev,
                                    struct drbd_backing_dev *bdev)
 {
-       switch (bdev->dc.meta_dev_idx) {
+       int meta_dev_idx;
+
+       rcu_read_lock();
+       meta_dev_idx = rcu_dereference(bdev->disk_conf)->meta_dev_idx;
+       rcu_read_unlock();
+
+       switch (meta_dev_idx) {
        default: /* external, some index */
-               return MD_RESERVED_SECT * bdev->dc.meta_dev_idx;
+               return MD_RESERVED_SECT * meta_dev_idx;
        case DRBD_MD_INDEX_INTERNAL:
                /* with drbd08, internal meta data is always "flexible" */
        case DRBD_MD_INDEX_FLEX_INT:
@@ -1801,9 +1857,8 @@ drbd_queue_work_front(struct drbd_work_queue *q, struct drbd_work *w)
        unsigned long flags;
        spin_lock_irqsave(&q->q_lock, flags);
        list_add(&w->list, &q->q);
-       up(&q->s); /* within the spinlock,
-                     see comment near end of drbd_worker() */
        spin_unlock_irqrestore(&q->q_lock, flags);
+       wake_up(&q->q_wait);
 }
 
 static inline void
@@ -1812,9 +1867,8 @@ drbd_queue_work(struct drbd_work_queue *q, struct drbd_work *w)
        unsigned long flags;
        spin_lock_irqsave(&q->q_lock, flags);
        list_add_tail(&w->list, &q->q);
-       up(&q->s); /* within the spinlock,
-                     see comment near end of drbd_worker() */
        spin_unlock_irqrestore(&q->q_lock, flags);
+       wake_up(&q->q_wait);
 }
 
 static inline void wake_asender(struct drbd_tconn *tconn)
@@ -2032,7 +2086,7 @@ static inline void drbd_get_syncer_progress(struct drbd_conf *mdev,
                 * 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 = mdev->rs_total >= (1ULL << 32) ? 16 : 10;
+               unsigned int shift = mdev->rs_total > UINT_MAX ? 16 : 10;
                unsigned long left = *bits_left >> shift;
                unsigned long total = 1UL + (mdev->rs_total >> shift);
                unsigned long tmp = 1000UL - left * 1000UL/total;
@@ -2111,12 +2165,12 @@ static inline int drbd_state_is_stable(struct drbd_conf *mdev)
        case D_OUTDATED:
        case D_CONSISTENT:
        case D_UP_TO_DATE:
+       case D_FAILED:
                /* disk state is stable as well. */
                break;
 
-       /* no new io accepted during tansitional states */
+       /* no new io accepted during transitional states */
        case D_ATTACHING:
-       case D_FAILED:
        case D_NEGOTIATING:
        case D_UNKNOWN:
        case D_MASK:
@@ -2178,7 +2232,7 @@ static inline void inc_ap_bio(struct drbd_conf *mdev)
        /* we wait here
         *    as long as the device is suspended
         *    until the bitmap is no longer on the fly during connection
-        *    handshake as long as we would exeed the max_buffer limit.
+        *    handshake as long as we would exceed the max_buffer limit.
         *
         * to avoid races with the reconnect code,
         * we need to atomic_inc within the spinlock. */
@@ -2192,15 +2246,23 @@ static inline void dec_ap_bio(struct drbd_conf *mdev)
        int ap_bio = atomic_dec_return(&mdev->ap_bio_cnt);
 
        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->tconn->sender_work, &mdev->bm_io_work.w);
+       }
+
        /* this currently does wake_up for every dec_ap_bio!
         * maybe rather introduce some type of hysteresis?
         * e.g. (ap_bio == mxb/2 || ap_bio == 0) ? */
        if (ap_bio < mxb)
                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->tconn->data.work, &mdev->bm_io_work.w);
-       }
+}
+
+static inline bool verify_can_do_stop_sector(struct drbd_conf *mdev)
+{
+       return mdev->tconn->agreed_pro_version >= 97 &&
+               mdev->tconn->agreed_pro_version != 100;
 }
 
 static inline int drbd_set_ed_uuid(struct drbd_conf *mdev, u64 val)