mirror of
https://github.com/torvalds/linux.git
synced 2024-11-28 07:01:32 +00:00
drbd: separate out __al_write_transaction helper function
To be able to "force out" an activity log transaction, even if there are no pending updates. This will be used to relocate the on-disk activity log, if the on-disk offsets have to be changed, without the need to empty the activity log first. While at it, move the definition, so we can drop the forward declaration of a static helper. Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com> Signed-off-by: Jens Axboe <axboe@fb.com>
This commit is contained in:
parent
7dbb4386b9
commit
603ee2c8c7
@ -288,7 +288,162 @@ bool drbd_al_begin_io_prepare(struct drbd_device *device, struct drbd_interval *
|
|||||||
return need_transaction;
|
return need_transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int al_write_transaction(struct drbd_device *device);
|
#if (PAGE_SHIFT + 3) < (AL_EXTENT_SHIFT - BM_BLOCK_SHIFT)
|
||||||
|
/* Currently BM_BLOCK_SHIFT, BM_EXT_SHIFT and AL_EXTENT_SHIFT
|
||||||
|
* are still coupled, or assume too much about their relation.
|
||||||
|
* Code below will not work if this is violated.
|
||||||
|
* Will be cleaned up with some followup patch.
|
||||||
|
*/
|
||||||
|
# error FIXME
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static unsigned int al_extent_to_bm_page(unsigned int al_enr)
|
||||||
|
{
|
||||||
|
return al_enr >>
|
||||||
|
/* bit to page */
|
||||||
|
((PAGE_SHIFT + 3) -
|
||||||
|
/* al extent number to bit */
|
||||||
|
(AL_EXTENT_SHIFT - BM_BLOCK_SHIFT));
|
||||||
|
}
|
||||||
|
|
||||||
|
static sector_t al_tr_number_to_on_disk_sector(struct drbd_device *device)
|
||||||
|
{
|
||||||
|
const unsigned int stripes = device->ldev->md.al_stripes;
|
||||||
|
const unsigned int stripe_size_4kB = device->ldev->md.al_stripe_size_4k;
|
||||||
|
|
||||||
|
/* transaction number, modulo on-disk ring buffer wrap around */
|
||||||
|
unsigned int t = device->al_tr_number % (device->ldev->md.al_size_4k);
|
||||||
|
|
||||||
|
/* ... to aligned 4k on disk block */
|
||||||
|
t = ((t % stripes) * stripe_size_4kB) + t/stripes;
|
||||||
|
|
||||||
|
/* ... to 512 byte sector in activity log */
|
||||||
|
t *= 8;
|
||||||
|
|
||||||
|
/* ... plus offset to the on disk position */
|
||||||
|
return device->ldev->md.md_offset + device->ldev->md.al_offset + t;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __al_write_transaction(struct drbd_device *device, struct al_transaction_on_disk *buffer)
|
||||||
|
{
|
||||||
|
struct lc_element *e;
|
||||||
|
sector_t sector;
|
||||||
|
int i, mx;
|
||||||
|
unsigned extent_nr;
|
||||||
|
unsigned crc = 0;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
memset(buffer, 0, sizeof(*buffer));
|
||||||
|
buffer->magic = cpu_to_be32(DRBD_AL_MAGIC);
|
||||||
|
buffer->tr_number = cpu_to_be32(device->al_tr_number);
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
/* Even though no one can start to change this list
|
||||||
|
* once we set the LC_LOCKED -- from drbd_al_begin_io(),
|
||||||
|
* lc_try_lock_for_transaction() --, someone may still
|
||||||
|
* be in the process of changing it. */
|
||||||
|
spin_lock_irq(&device->al_lock);
|
||||||
|
list_for_each_entry(e, &device->act_log->to_be_changed, list) {
|
||||||
|
if (i == AL_UPDATES_PER_TRANSACTION) {
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buffer->update_slot_nr[i] = cpu_to_be16(e->lc_index);
|
||||||
|
buffer->update_extent_nr[i] = cpu_to_be32(e->lc_new_number);
|
||||||
|
if (e->lc_number != LC_FREE)
|
||||||
|
drbd_bm_mark_for_writeout(device,
|
||||||
|
al_extent_to_bm_page(e->lc_number));
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
spin_unlock_irq(&device->al_lock);
|
||||||
|
BUG_ON(i > AL_UPDATES_PER_TRANSACTION);
|
||||||
|
|
||||||
|
buffer->n_updates = cpu_to_be16(i);
|
||||||
|
for ( ; i < AL_UPDATES_PER_TRANSACTION; i++) {
|
||||||
|
buffer->update_slot_nr[i] = cpu_to_be16(-1);
|
||||||
|
buffer->update_extent_nr[i] = cpu_to_be32(LC_FREE);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer->context_size = cpu_to_be16(device->act_log->nr_elements);
|
||||||
|
buffer->context_start_slot_nr = cpu_to_be16(device->al_tr_cycle);
|
||||||
|
|
||||||
|
mx = min_t(int, AL_CONTEXT_PER_TRANSACTION,
|
||||||
|
device->act_log->nr_elements - device->al_tr_cycle);
|
||||||
|
for (i = 0; i < mx; i++) {
|
||||||
|
unsigned idx = device->al_tr_cycle + i;
|
||||||
|
extent_nr = lc_element_by_index(device->act_log, idx)->lc_number;
|
||||||
|
buffer->context[i] = cpu_to_be32(extent_nr);
|
||||||
|
}
|
||||||
|
for (; i < AL_CONTEXT_PER_TRANSACTION; i++)
|
||||||
|
buffer->context[i] = cpu_to_be32(LC_FREE);
|
||||||
|
|
||||||
|
device->al_tr_cycle += AL_CONTEXT_PER_TRANSACTION;
|
||||||
|
if (device->al_tr_cycle >= device->act_log->nr_elements)
|
||||||
|
device->al_tr_cycle = 0;
|
||||||
|
|
||||||
|
sector = al_tr_number_to_on_disk_sector(device);
|
||||||
|
|
||||||
|
crc = crc32c(0, buffer, 4096);
|
||||||
|
buffer->crc32c = cpu_to_be32(crc);
|
||||||
|
|
||||||
|
if (drbd_bm_write_hinted(device))
|
||||||
|
err = -EIO;
|
||||||
|
else {
|
||||||
|
bool write_al_updates;
|
||||||
|
rcu_read_lock();
|
||||||
|
write_al_updates = rcu_dereference(device->ldev->disk_conf)->al_updates;
|
||||||
|
rcu_read_unlock();
|
||||||
|
if (write_al_updates) {
|
||||||
|
if (drbd_md_sync_page_io(device, device->ldev, sector, WRITE)) {
|
||||||
|
err = -EIO;
|
||||||
|
drbd_chk_io_error(device, 1, DRBD_META_IO_ERROR);
|
||||||
|
} else {
|
||||||
|
device->al_tr_number++;
|
||||||
|
device->al_writ_cnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int al_write_transaction(struct drbd_device *device)
|
||||||
|
{
|
||||||
|
struct al_transaction_on_disk *buffer;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!get_ldev(device)) {
|
||||||
|
drbd_err(device, "disk is %s, cannot start al transaction\n",
|
||||||
|
drbd_disk_str(device->state.disk));
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The bitmap write may have failed, causing a state change. */
|
||||||
|
if (device->state.disk < D_INCONSISTENT) {
|
||||||
|
drbd_err(device,
|
||||||
|
"disk is %s, cannot write al transaction\n",
|
||||||
|
drbd_disk_str(device->state.disk));
|
||||||
|
put_ldev(device);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* protects md_io_buffer, al_tr_cycle, ... */
|
||||||
|
buffer = drbd_md_get_buffer(device, __func__);
|
||||||
|
if (!buffer) {
|
||||||
|
drbd_err(device, "disk failed while waiting for md_io buffer\n");
|
||||||
|
put_ldev(device);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = __al_write_transaction(device, buffer);
|
||||||
|
|
||||||
|
drbd_md_put_buffer(device);
|
||||||
|
put_ldev(device);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void drbd_al_begin_io_commit(struct drbd_device *device)
|
void drbd_al_begin_io_commit(struct drbd_device *device)
|
||||||
{
|
{
|
||||||
@ -420,153 +575,6 @@ void drbd_al_complete_io(struct drbd_device *device, struct drbd_interval *i)
|
|||||||
wake_up(&device->al_wait);
|
wake_up(&device->al_wait);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (PAGE_SHIFT + 3) < (AL_EXTENT_SHIFT - BM_BLOCK_SHIFT)
|
|
||||||
/* Currently BM_BLOCK_SHIFT, BM_EXT_SHIFT and AL_EXTENT_SHIFT
|
|
||||||
* are still coupled, or assume too much about their relation.
|
|
||||||
* Code below will not work if this is violated.
|
|
||||||
* Will be cleaned up with some followup patch.
|
|
||||||
*/
|
|
||||||
# error FIXME
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static unsigned int al_extent_to_bm_page(unsigned int al_enr)
|
|
||||||
{
|
|
||||||
return al_enr >>
|
|
||||||
/* bit to page */
|
|
||||||
((PAGE_SHIFT + 3) -
|
|
||||||
/* al extent number to bit */
|
|
||||||
(AL_EXTENT_SHIFT - BM_BLOCK_SHIFT));
|
|
||||||
}
|
|
||||||
|
|
||||||
static sector_t al_tr_number_to_on_disk_sector(struct drbd_device *device)
|
|
||||||
{
|
|
||||||
const unsigned int stripes = device->ldev->md.al_stripes;
|
|
||||||
const unsigned int stripe_size_4kB = device->ldev->md.al_stripe_size_4k;
|
|
||||||
|
|
||||||
/* transaction number, modulo on-disk ring buffer wrap around */
|
|
||||||
unsigned int t = device->al_tr_number % (device->ldev->md.al_size_4k);
|
|
||||||
|
|
||||||
/* ... to aligned 4k on disk block */
|
|
||||||
t = ((t % stripes) * stripe_size_4kB) + t/stripes;
|
|
||||||
|
|
||||||
/* ... to 512 byte sector in activity log */
|
|
||||||
t *= 8;
|
|
||||||
|
|
||||||
/* ... plus offset to the on disk position */
|
|
||||||
return device->ldev->md.md_offset + device->ldev->md.al_offset + t;
|
|
||||||
}
|
|
||||||
|
|
||||||
int al_write_transaction(struct drbd_device *device)
|
|
||||||
{
|
|
||||||
struct al_transaction_on_disk *buffer;
|
|
||||||
struct lc_element *e;
|
|
||||||
sector_t sector;
|
|
||||||
int i, mx;
|
|
||||||
unsigned extent_nr;
|
|
||||||
unsigned crc = 0;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
if (!get_ldev(device)) {
|
|
||||||
drbd_err(device, "disk is %s, cannot start al transaction\n",
|
|
||||||
drbd_disk_str(device->state.disk));
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The bitmap write may have failed, causing a state change. */
|
|
||||||
if (device->state.disk < D_INCONSISTENT) {
|
|
||||||
drbd_err(device,
|
|
||||||
"disk is %s, cannot write al transaction\n",
|
|
||||||
drbd_disk_str(device->state.disk));
|
|
||||||
put_ldev(device);
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* protects md_io_buffer, al_tr_cycle, ... */
|
|
||||||
buffer = drbd_md_get_buffer(device, __func__);
|
|
||||||
if (!buffer) {
|
|
||||||
drbd_err(device, "disk failed while waiting for md_io buffer\n");
|
|
||||||
put_ldev(device);
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(buffer, 0, sizeof(*buffer));
|
|
||||||
buffer->magic = cpu_to_be32(DRBD_AL_MAGIC);
|
|
||||||
buffer->tr_number = cpu_to_be32(device->al_tr_number);
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
|
|
||||||
/* Even though no one can start to change this list
|
|
||||||
* once we set the LC_LOCKED -- from drbd_al_begin_io(),
|
|
||||||
* lc_try_lock_for_transaction() --, someone may still
|
|
||||||
* be in the process of changing it. */
|
|
||||||
spin_lock_irq(&device->al_lock);
|
|
||||||
list_for_each_entry(e, &device->act_log->to_be_changed, list) {
|
|
||||||
if (i == AL_UPDATES_PER_TRANSACTION) {
|
|
||||||
i++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
buffer->update_slot_nr[i] = cpu_to_be16(e->lc_index);
|
|
||||||
buffer->update_extent_nr[i] = cpu_to_be32(e->lc_new_number);
|
|
||||||
if (e->lc_number != LC_FREE)
|
|
||||||
drbd_bm_mark_for_writeout(device,
|
|
||||||
al_extent_to_bm_page(e->lc_number));
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
spin_unlock_irq(&device->al_lock);
|
|
||||||
BUG_ON(i > AL_UPDATES_PER_TRANSACTION);
|
|
||||||
|
|
||||||
buffer->n_updates = cpu_to_be16(i);
|
|
||||||
for ( ; i < AL_UPDATES_PER_TRANSACTION; i++) {
|
|
||||||
buffer->update_slot_nr[i] = cpu_to_be16(-1);
|
|
||||||
buffer->update_extent_nr[i] = cpu_to_be32(LC_FREE);
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer->context_size = cpu_to_be16(device->act_log->nr_elements);
|
|
||||||
buffer->context_start_slot_nr = cpu_to_be16(device->al_tr_cycle);
|
|
||||||
|
|
||||||
mx = min_t(int, AL_CONTEXT_PER_TRANSACTION,
|
|
||||||
device->act_log->nr_elements - device->al_tr_cycle);
|
|
||||||
for (i = 0; i < mx; i++) {
|
|
||||||
unsigned idx = device->al_tr_cycle + i;
|
|
||||||
extent_nr = lc_element_by_index(device->act_log, idx)->lc_number;
|
|
||||||
buffer->context[i] = cpu_to_be32(extent_nr);
|
|
||||||
}
|
|
||||||
for (; i < AL_CONTEXT_PER_TRANSACTION; i++)
|
|
||||||
buffer->context[i] = cpu_to_be32(LC_FREE);
|
|
||||||
|
|
||||||
device->al_tr_cycle += AL_CONTEXT_PER_TRANSACTION;
|
|
||||||
if (device->al_tr_cycle >= device->act_log->nr_elements)
|
|
||||||
device->al_tr_cycle = 0;
|
|
||||||
|
|
||||||
sector = al_tr_number_to_on_disk_sector(device);
|
|
||||||
|
|
||||||
crc = crc32c(0, buffer, 4096);
|
|
||||||
buffer->crc32c = cpu_to_be32(crc);
|
|
||||||
|
|
||||||
if (drbd_bm_write_hinted(device))
|
|
||||||
err = -EIO;
|
|
||||||
else {
|
|
||||||
bool write_al_updates;
|
|
||||||
rcu_read_lock();
|
|
||||||
write_al_updates = rcu_dereference(device->ldev->disk_conf)->al_updates;
|
|
||||||
rcu_read_unlock();
|
|
||||||
if (write_al_updates) {
|
|
||||||
if (drbd_md_sync_page_io(device, device->ldev, sector, WRITE)) {
|
|
||||||
err = -EIO;
|
|
||||||
drbd_chk_io_error(device, 1, DRBD_META_IO_ERROR);
|
|
||||||
} else {
|
|
||||||
device->al_tr_number++;
|
|
||||||
device->al_writ_cnt++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
drbd_md_put_buffer(device);
|
|
||||||
put_ldev(device);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _try_lc_del(struct drbd_device *device, struct lc_element *al_ext)
|
static int _try_lc_del(struct drbd_device *device, struct lc_element *al_ext)
|
||||||
{
|
{
|
||||||
int rv;
|
int rv;
|
||||||
|
Loading…
Reference in New Issue
Block a user