Skip to content

Commit

Permalink
Merge tag 'md/4.5' of git://neil.brown.name/md
Browse files Browse the repository at this point in the history
Pull md updates from Neil Brown:
 "Mostly clustered-raid1 and raid5 journal updates.  one Y2038 fix and
  other minor stuff.

  One patch removes me from the MAINTAINERS file and adds a record of my
  md maintainership to Credits"

Many thanks to Neil, who has been around for a _looong_ time.

* tag 'md/4.5' of git://neil.brown.name/md: (26 commits)
  md/raid: only permit hot-add of compatible integrity profiles
  Remove myself as MD Maintainer, and add to Credits.
  raid5-cache: handle journal hotadd in quiesce
  MD: add journal with array suspended
  md: set MD_HAS_JOURNAL in correct places
  md: Remove 'ready' field from mddev.
  md: remove unnecesary md_new_event_inintr
  raid5: allow r5l_io_unit allocations to fail
  raid5-cache: use a mempool for the metadata block
  raid5-cache: use a bio_set
  raid5-cache: add journal hot add/remove support
  drivers: md: use ktime_get_real_seconds()
  md: avoid warning for 32-bit sector_t
  raid5-cache: free meta_page earlier
  raid5-cache: simplify r5l_move_io_unit_list
  md: update comment for md_allow_write
  md-cluster: update comments for MD_CLUSTER_SEND_LOCKED_ALREADY
  md-cluster: Protect communication with mutexes
  md-cluster: Defer MD reloading to mddev->thread
  md-cluster: update the documentation
  ...
  • Loading branch information
torvalds committed Jan 15, 2016
2 parents 4b43ea2 + 1501efa commit 3c28c9c
Show file tree
Hide file tree
Showing 13 changed files with 649 additions and 231 deletions.
1 change: 1 addition & 0 deletions CREDITS
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,7 @@ N: NeilBrown
E: [email protected]
P: 4096R/566281B9 1BC6 29EB D390 D870 7B5F 497A 39EC 9EDD 5662 81B9
D: NFSD Maintainer 2000-2007
D: MD Maintainer 2001-2016

N: Zach Brown
E: [email protected]
Expand Down
314 changes: 228 additions & 86 deletions Documentation/md-cluster.txt

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -9999,7 +9999,6 @@ S: Supported
F: drivers/media/pci/solo6x10/

SOFTWARE RAID (Multiple Disks) SUPPORT
M: Neil Brown <[email protected]>
L: [email protected]
S: Supported
F: drivers/md/
Expand Down
164 changes: 150 additions & 14 deletions drivers/md/md-cluster.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,29 @@ struct resync_info {
#define MD_CLUSTER_SUSPEND_READ_BALANCING 2
#define MD_CLUSTER_BEGIN_JOIN_CLUSTER 3

/* Lock the send communication. This is done through
* bit manipulation as opposed to a mutex in order to
* accomodate lock and hold. See next comment.
*/
#define MD_CLUSTER_SEND_LOCK 4
/* If cluster operations (such as adding a disk) must lock the
* communication channel, so as to perform extra operations
* (update metadata) and no other operation is allowed on the
* MD. Token needs to be locked and held until the operation
* completes witha md_update_sb(), which would eventually release
* the lock.
*/
#define MD_CLUSTER_SEND_LOCKED_ALREADY 5


struct md_cluster_info {
/* dlm lock space and resources for clustered raid. */
dlm_lockspace_t *lockspace;
int slot_number;
struct completion completion;
struct mutex recv_mutex;
struct dlm_lock_resource *bitmap_lockres;
struct dlm_lock_resource **other_bitmap_lockres;
struct dlm_lock_resource *resync_lockres;
struct list_head suspend_list;
spinlock_t suspend_lock;
Expand All @@ -67,6 +83,7 @@ struct md_cluster_info {
struct dlm_lock_resource *no_new_dev_lockres;
struct md_thread *recv_thread;
struct completion newdisk_completion;
wait_queue_head_t wait;
unsigned long state;
};

Expand Down Expand Up @@ -431,17 +448,22 @@ static void process_add_new_disk(struct mddev *mddev, struct cluster_msg *cmsg)
static void process_metadata_update(struct mddev *mddev, struct cluster_msg *msg)
{
struct md_cluster_info *cinfo = mddev->cluster_info;
md_reload_sb(mddev, le32_to_cpu(msg->raid_slot));
mddev->good_device_nr = le32_to_cpu(msg->raid_slot);
set_bit(MD_RELOAD_SB, &mddev->flags);
dlm_lock_sync(cinfo->no_new_dev_lockres, DLM_LOCK_CR);
md_wakeup_thread(mddev->thread);
}

static void process_remove_disk(struct mddev *mddev, struct cluster_msg *msg)
{
struct md_rdev *rdev = md_find_rdev_nr_rcu(mddev,
le32_to_cpu(msg->raid_slot));

if (rdev)
md_kick_rdev_from_array(rdev);
if (rdev) {
set_bit(ClusterRemove, &rdev->flags);
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
md_wakeup_thread(mddev->thread);
}
else
pr_warn("%s: %d Could not find disk(%d) to REMOVE\n",
__func__, __LINE__, le32_to_cpu(msg->raid_slot));
Expand Down Expand Up @@ -502,9 +524,11 @@ static void recv_daemon(struct md_thread *thread)
struct cluster_msg msg;
int ret;

mutex_lock(&cinfo->recv_mutex);
/*get CR on Message*/
if (dlm_lock_sync(message_lockres, DLM_LOCK_CR)) {
pr_err("md/raid1:failed to get CR on MESSAGE\n");
mutex_unlock(&cinfo->recv_mutex);
return;
}

Expand All @@ -528,33 +552,45 @@ static void recv_daemon(struct md_thread *thread)
ret = dlm_unlock_sync(message_lockres);
if (unlikely(ret != 0))
pr_info("unlock msg failed return %d\n", ret);
mutex_unlock(&cinfo->recv_mutex);
}

/* lock_comm()
/* lock_token()
* Takes the lock on the TOKEN lock resource so no other
* node can communicate while the operation is underway.
* If called again, and the TOKEN lock is alread in EX mode
* return success. However, care must be taken that unlock_comm()
* is called only once.
*/
static int lock_comm(struct md_cluster_info *cinfo)
static int lock_token(struct md_cluster_info *cinfo)
{
int error;

if (cinfo->token_lockres->mode == DLM_LOCK_EX)
return 0;

error = dlm_lock_sync(cinfo->token_lockres, DLM_LOCK_EX);
if (error)
pr_err("md-cluster(%s:%d): failed to get EX on TOKEN (%d)\n",
__func__, __LINE__, error);

/* Lock the receive sequence */
mutex_lock(&cinfo->recv_mutex);
return error;
}

/* lock_comm()
* Sets the MD_CLUSTER_SEND_LOCK bit to lock the send channel.
*/
static int lock_comm(struct md_cluster_info *cinfo)
{
wait_event(cinfo->wait,
!test_and_set_bit(MD_CLUSTER_SEND_LOCK, &cinfo->state));

return lock_token(cinfo);
}

static void unlock_comm(struct md_cluster_info *cinfo)
{
WARN_ON(cinfo->token_lockres->mode != DLM_LOCK_EX);
mutex_unlock(&cinfo->recv_mutex);
dlm_unlock_sync(cinfo->token_lockres);
clear_bit(MD_CLUSTER_SEND_LOCK, &cinfo->state);
wake_up(&cinfo->wait);
}

/* __sendmsg()
Expand Down Expand Up @@ -707,6 +743,8 @@ static int join(struct mddev *mddev, int nodes)
spin_lock_init(&cinfo->suspend_lock);
init_completion(&cinfo->completion);
set_bit(MD_CLUSTER_BEGIN_JOIN_CLUSTER, &cinfo->state);
init_waitqueue_head(&cinfo->wait);
mutex_init(&cinfo->recv_mutex);

mddev->cluster_info = cinfo;

Expand Down Expand Up @@ -800,6 +838,7 @@ static void resync_bitmap(struct mddev *mddev)
__func__, __LINE__, err);
}

static void unlock_all_bitmaps(struct mddev *mddev);
static int leave(struct mddev *mddev)
{
struct md_cluster_info *cinfo = mddev->cluster_info;
Expand All @@ -820,6 +859,7 @@ static int leave(struct mddev *mddev)
lockres_free(cinfo->ack_lockres);
lockres_free(cinfo->no_new_dev_lockres);
lockres_free(cinfo->bitmap_lockres);
unlock_all_bitmaps(mddev);
dlm_release_lockspace(cinfo->lockspace, 2);
return 0;
}
Expand All @@ -835,9 +875,25 @@ static int slot_number(struct mddev *mddev)
return cinfo->slot_number - 1;
}

/*
* Check if the communication is already locked, else lock the communication
* channel.
* If it is already locked, token is in EX mode, and hence lock_token()
* should not be called.
*/
static int metadata_update_start(struct mddev *mddev)
{
return lock_comm(mddev->cluster_info);
struct md_cluster_info *cinfo = mddev->cluster_info;

wait_event(cinfo->wait,
!test_and_set_bit(MD_CLUSTER_SEND_LOCK, &cinfo->state) ||
test_and_clear_bit(MD_CLUSTER_SEND_LOCKED_ALREADY, &cinfo->state));

/* If token is already locked, return 0 */
if (cinfo->token_lockres->mode == DLM_LOCK_EX)
return 0;

return lock_token(cinfo);
}

static int metadata_update_finish(struct mddev *mddev)
Expand All @@ -862,13 +918,15 @@ static int metadata_update_finish(struct mddev *mddev)
ret = __sendmsg(cinfo, &cmsg);
} else
pr_warn("md-cluster: No good device id found to send\n");
clear_bit(MD_CLUSTER_SEND_LOCKED_ALREADY, &cinfo->state);
unlock_comm(cinfo);
return ret;
}

static void metadata_update_cancel(struct mddev *mddev)
{
struct md_cluster_info *cinfo = mddev->cluster_info;
clear_bit(MD_CLUSTER_SEND_LOCKED_ALREADY, &cinfo->state);
unlock_comm(cinfo);
}

Expand All @@ -882,8 +940,16 @@ static int resync_start(struct mddev *mddev)
static int resync_info_update(struct mddev *mddev, sector_t lo, sector_t hi)
{
struct md_cluster_info *cinfo = mddev->cluster_info;
struct resync_info ri;
struct cluster_msg cmsg = {0};

/* do not send zero again, if we have sent before */
if (hi == 0) {
memcpy(&ri, cinfo->bitmap_lockres->lksb.sb_lvbptr, sizeof(struct resync_info));
if (le64_to_cpu(ri.hi) == 0)
return 0;
}

add_resync_info(cinfo->bitmap_lockres, lo, hi);
/* Re-acquire the lock to refresh LVB */
dlm_lock_sync(cinfo->bitmap_lockres, DLM_LOCK_PW);
Expand Down Expand Up @@ -954,14 +1020,30 @@ static int add_new_disk(struct mddev *mddev, struct md_rdev *rdev)
ret = -ENOENT;
if (ret)
unlock_comm(cinfo);
else
else {
dlm_lock_sync(cinfo->no_new_dev_lockres, DLM_LOCK_CR);
/* Since MD_CHANGE_DEVS will be set in add_bound_rdev which
* will run soon after add_new_disk, the below path will be
* invoked:
* md_wakeup_thread(mddev->thread)
* -> conf->thread (raid1d)
* -> md_check_recovery -> md_update_sb
* -> metadata_update_start/finish
* MD_CLUSTER_SEND_LOCKED_ALREADY will be cleared eventually.
*
* For other failure cases, metadata_update_cancel and
* add_new_disk_cancel also clear below bit as well.
* */
set_bit(MD_CLUSTER_SEND_LOCKED_ALREADY, &cinfo->state);
wake_up(&cinfo->wait);
}
return ret;
}

static void add_new_disk_cancel(struct mddev *mddev)
{
struct md_cluster_info *cinfo = mddev->cluster_info;
clear_bit(MD_CLUSTER_SEND_LOCKED_ALREADY, &cinfo->state);
unlock_comm(cinfo);
}

Expand All @@ -986,7 +1068,59 @@ static int remove_disk(struct mddev *mddev, struct md_rdev *rdev)
struct md_cluster_info *cinfo = mddev->cluster_info;
cmsg.type = cpu_to_le32(REMOVE);
cmsg.raid_slot = cpu_to_le32(rdev->desc_nr);
return __sendmsg(cinfo, &cmsg);
return sendmsg(cinfo, &cmsg);
}

static int lock_all_bitmaps(struct mddev *mddev)
{
int slot, my_slot, ret, held = 1, i = 0;
char str[64];
struct md_cluster_info *cinfo = mddev->cluster_info;

cinfo->other_bitmap_lockres = kzalloc((mddev->bitmap_info.nodes - 1) *
sizeof(struct dlm_lock_resource *),
GFP_KERNEL);
if (!cinfo->other_bitmap_lockres) {
pr_err("md: can't alloc mem for other bitmap locks\n");
return 0;
}

my_slot = slot_number(mddev);
for (slot = 0; slot < mddev->bitmap_info.nodes; slot++) {
if (slot == my_slot)
continue;

memset(str, '\0', 64);
snprintf(str, 64, "bitmap%04d", slot);
cinfo->other_bitmap_lockres[i] = lockres_init(mddev, str, NULL, 1);
if (!cinfo->other_bitmap_lockres[i])
return -ENOMEM;

cinfo->other_bitmap_lockres[i]->flags |= DLM_LKF_NOQUEUE;
ret = dlm_lock_sync(cinfo->other_bitmap_lockres[i], DLM_LOCK_PW);
if (ret)
held = -1;
i++;
}

return held;
}

static void unlock_all_bitmaps(struct mddev *mddev)
{
struct md_cluster_info *cinfo = mddev->cluster_info;
int i;

/* release other node's bitmap lock if they are existed */
if (cinfo->other_bitmap_lockres) {
for (i = 0; i < mddev->bitmap_info.nodes - 1; i++) {
if (cinfo->other_bitmap_lockres[i]) {
dlm_unlock_sync(cinfo->other_bitmap_lockres[i]);
lockres_free(cinfo->other_bitmap_lockres[i]);
}
}
kfree(cinfo->other_bitmap_lockres);
}
}

static int gather_bitmaps(struct md_rdev *rdev)
Expand Down Expand Up @@ -1034,6 +1168,8 @@ static struct md_cluster_operations cluster_ops = {
.new_disk_ack = new_disk_ack,
.remove_disk = remove_disk,
.gather_bitmaps = gather_bitmaps,
.lock_all_bitmaps = lock_all_bitmaps,
.unlock_all_bitmaps = unlock_all_bitmaps,
};

static int __init cluster_init(void)
Expand Down
2 changes: 2 additions & 0 deletions drivers/md/md-cluster.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ struct md_cluster_operations {
int (*new_disk_ack)(struct mddev *mddev, bool ack);
int (*remove_disk)(struct mddev *mddev, struct md_rdev *rdev);
int (*gather_bitmaps)(struct md_rdev *rdev);
int (*lock_all_bitmaps)(struct mddev *mddev);
void (*unlock_all_bitmaps)(struct mddev *mddev);
};

#endif /* _MD_CLUSTER_H */
Loading

0 comments on commit 3c28c9c

Please sign in to comment.