Skip to content

Commit

Permalink
Merge tag 'dm-3.8-fixes' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/agk/linux-dm

Pull dm update from Alasdair G Kergon:
 "Miscellaneous device-mapper fixes, cleanups and performance
  improvements.

  Of particular note:
   - Disable broken WRITE SAME support in all targets except linear and
     striped.  Use it when kcopyd is zeroing blocks.
   - Remove several mempools from targets by moving the data into the
     bio's new front_pad area(which dm calls 'per_bio_data').
   - Fix a race in thin provisioning if discards are misused.
   - Prevent userspace from interfering with the ioctl parameters and
     use kmalloc for the data buffer if it's small instead of vmalloc.
   - Throttle some annoying error messages when I/O fails."

* tag 'dm-3.8-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/agk/linux-dm: (36 commits)
  dm stripe: add WRITE SAME support
  dm: remove map_info
  dm snapshot: do not use map_context
  dm thin: dont use map_context
  dm raid1: dont use map_context
  dm flakey: dont use map_context
  dm raid1: rename read_record to bio_record
  dm: move target request nr to dm_target_io
  dm snapshot: use per_bio_data
  dm verity: use per_bio_data
  dm raid1: use per_bio_data
  dm: introduce per_bio_data
  dm kcopyd: add WRITE SAME support to dm_kcopyd_zero
  dm linear: add WRITE SAME support
  dm: add WRITE SAME support
  dm: prepare to support WRITE SAME
  dm ioctl: use kmalloc if possible
  dm ioctl: remove PF_MEMALLOC
  dm persistent data: improve improve space map block alloc failure message
  dm thin: use DMERR_LIMIT for errors
  ...
  • Loading branch information
torvalds committed Dec 22, 2012
2 parents 10532b5 + 45e621d commit b49249d
Show file tree
Hide file tree
Showing 30 changed files with 522 additions and 443 deletions.
25 changes: 0 additions & 25 deletions drivers/md/dm-bio-prison.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,31 +207,6 @@ void dm_cell_release(struct dm_bio_prison_cell *cell, struct bio_list *bios)
}
EXPORT_SYMBOL_GPL(dm_cell_release);

/*
* There are a couple of places where we put a bio into a cell briefly
* before taking it out again. In these situations we know that no other
* bio may be in the cell. This function releases the cell, and also does
* a sanity check.
*/
static void __cell_release_singleton(struct dm_bio_prison_cell *cell, struct bio *bio)
{
BUG_ON(cell->holder != bio);
BUG_ON(!bio_list_empty(&cell->bios));

__cell_release(cell, NULL);
}

void dm_cell_release_singleton(struct dm_bio_prison_cell *cell, struct bio *bio)
{
unsigned long flags;
struct dm_bio_prison *prison = cell->prison;

spin_lock_irqsave(&prison->lock, flags);
__cell_release_singleton(cell, bio);
spin_unlock_irqrestore(&prison->lock, flags);
}
EXPORT_SYMBOL_GPL(dm_cell_release_singleton);

/*
* Sometimes we don't want the holder, just the additional bios.
*/
Expand Down
1 change: 0 additions & 1 deletion drivers/md/dm-bio-prison.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ int dm_bio_detain(struct dm_bio_prison *prison, struct dm_cell_key *key,
struct bio *inmate, struct dm_bio_prison_cell **ref);

void dm_cell_release(struct dm_bio_prison_cell *cell, struct bio_list *bios);
void dm_cell_release_singleton(struct dm_bio_prison_cell *cell, struct bio *bio); // FIXME: bio arg not needed
void dm_cell_release_no_holder(struct dm_bio_prison_cell *cell, struct bio_list *inmates);
void dm_cell_error(struct dm_bio_prison_cell *cell);

Expand Down
5 changes: 2 additions & 3 deletions drivers/md/dm-crypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -1689,8 +1689,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
return ret;
}

static int crypt_map(struct dm_target *ti, struct bio *bio,
union map_info *map_context)
static int crypt_map(struct dm_target *ti, struct bio *bio)
{
struct dm_crypt_io *io;
struct crypt_config *cc = ti->private;
Expand Down Expand Up @@ -1846,7 +1845,7 @@ static int crypt_iterate_devices(struct dm_target *ti,

static struct target_type crypt_target = {
.name = "crypt",
.version = {1, 11, 0},
.version = {1, 12, 0},
.module = THIS_MODULE,
.ctr = crypt_ctr,
.dtr = crypt_dtr,
Expand Down
5 changes: 2 additions & 3 deletions drivers/md/dm-delay.c
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,7 @@ static void delay_resume(struct dm_target *ti)
atomic_set(&dc->may_delay, 1);
}

static int delay_map(struct dm_target *ti, struct bio *bio,
union map_info *map_context)
static int delay_map(struct dm_target *ti, struct bio *bio)
{
struct delay_c *dc = ti->private;

Expand Down Expand Up @@ -338,7 +337,7 @@ static int delay_iterate_devices(struct dm_target *ti,

static struct target_type delay_target = {
.name = "delay",
.version = {1, 1, 0},
.version = {1, 2, 0},
.module = THIS_MODULE,
.ctr = delay_ctr,
.dtr = delay_dtr,
Expand Down
21 changes: 13 additions & 8 deletions drivers/md/dm-flakey.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ enum feature_flag_bits {
DROP_WRITES
};

struct per_bio_data {
bool bio_submitted;
};

static int parse_features(struct dm_arg_set *as, struct flakey_c *fc,
struct dm_target *ti)
{
Expand Down Expand Up @@ -214,6 +218,7 @@ static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv)

ti->num_flush_requests = 1;
ti->num_discard_requests = 1;
ti->per_bio_data_size = sizeof(struct per_bio_data);
ti->private = fc;
return 0;

Expand Down Expand Up @@ -265,19 +270,20 @@ static void corrupt_bio_data(struct bio *bio, struct flakey_c *fc)
}
}

static int flakey_map(struct dm_target *ti, struct bio *bio,
union map_info *map_context)
static int flakey_map(struct dm_target *ti, struct bio *bio)
{
struct flakey_c *fc = ti->private;
unsigned elapsed;
struct per_bio_data *pb = dm_per_bio_data(bio, sizeof(struct per_bio_data));
pb->bio_submitted = false;

/* Are we alive ? */
elapsed = (jiffies - fc->start_time) / HZ;
if (elapsed % (fc->up_interval + fc->down_interval) >= fc->up_interval) {
/*
* Flag this bio as submitted while down.
*/
map_context->ll = 1;
pb->bio_submitted = true;

/*
* Map reads as normal.
Expand Down Expand Up @@ -314,17 +320,16 @@ static int flakey_map(struct dm_target *ti, struct bio *bio,
return DM_MAPIO_REMAPPED;
}

static int flakey_end_io(struct dm_target *ti, struct bio *bio,
int error, union map_info *map_context)
static int flakey_end_io(struct dm_target *ti, struct bio *bio, int error)
{
struct flakey_c *fc = ti->private;
unsigned bio_submitted_while_down = map_context->ll;
struct per_bio_data *pb = dm_per_bio_data(bio, sizeof(struct per_bio_data));

/*
* Corrupt successful READs while in down state.
* If flags were specified, only corrupt those that match.
*/
if (fc->corrupt_bio_byte && !error && bio_submitted_while_down &&
if (fc->corrupt_bio_byte && !error && pb->bio_submitted &&
(bio_data_dir(bio) == READ) && (fc->corrupt_bio_rw == READ) &&
all_corrupt_bio_flags_match(bio, fc))
corrupt_bio_data(bio, fc);
Expand Down Expand Up @@ -406,7 +411,7 @@ static int flakey_iterate_devices(struct dm_target *ti, iterate_devices_callout_

static struct target_type flakey_target = {
.name = "flakey",
.version = {1, 2, 0},
.version = {1, 3, 0},
.module = THIS_MODULE,
.ctr = flakey_ctr,
.dtr = flakey_dtr,
Expand Down
23 changes: 18 additions & 5 deletions drivers/md/dm-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,8 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
unsigned num_bvecs;
sector_t remaining = where->count;
struct request_queue *q = bdev_get_queue(where->bdev);
sector_t discard_sectors;
unsigned short logical_block_size = queue_logical_block_size(q);
sector_t num_sectors;

/*
* where->count may be zero if rw holds a flush and we need to
Expand All @@ -297,7 +298,7 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
/*
* Allocate a suitably sized-bio.
*/
if (rw & REQ_DISCARD)
if ((rw & REQ_DISCARD) || (rw & REQ_WRITE_SAME))
num_bvecs = 1;
else
num_bvecs = min_t(int, bio_get_nr_vecs(where->bdev),
Expand All @@ -310,9 +311,21 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
store_io_and_region_in_bio(bio, io, region);

if (rw & REQ_DISCARD) {
discard_sectors = min_t(sector_t, q->limits.max_discard_sectors, remaining);
bio->bi_size = discard_sectors << SECTOR_SHIFT;
remaining -= discard_sectors;
num_sectors = min_t(sector_t, q->limits.max_discard_sectors, remaining);
bio->bi_size = num_sectors << SECTOR_SHIFT;
remaining -= num_sectors;
} else if (rw & REQ_WRITE_SAME) {
/*
* WRITE SAME only uses a single page.
*/
dp->get_page(dp, &page, &len, &offset);
bio_add_page(bio, page, logical_block_size, offset);
num_sectors = min_t(sector_t, q->limits.max_write_same_sectors, remaining);
bio->bi_size = num_sectors << SECTOR_SHIFT;

offset = 0;
remaining -= num_sectors;
dp->next_page(dp);
} else while (remaining) {
/*
* Try and add as many pages as possible.
Expand Down
64 changes: 43 additions & 21 deletions drivers/md/dm-ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1543,7 +1543,21 @@ static int check_version(unsigned int cmd, struct dm_ioctl __user *user)
return r;
}

static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param)
#define DM_PARAMS_VMALLOC 0x0001 /* Params alloced with vmalloc not kmalloc */
#define DM_WIPE_BUFFER 0x0010 /* Wipe input buffer before returning from ioctl */

static void free_params(struct dm_ioctl *param, size_t param_size, int param_flags)
{
if (param_flags & DM_WIPE_BUFFER)
memset(param, 0, param_size);

if (param_flags & DM_PARAMS_VMALLOC)
vfree(param);
else
kfree(param);
}

static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param, int *param_flags)
{
struct dm_ioctl tmp, *dmi;
int secure_data;
Expand All @@ -1556,7 +1570,21 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param)

secure_data = tmp.flags & DM_SECURE_DATA_FLAG;

dmi = vmalloc(tmp.data_size);
*param_flags = secure_data ? DM_WIPE_BUFFER : 0;

/*
* Try to avoid low memory issues when a device is suspended.
* Use kmalloc() rather than vmalloc() when we can.
*/
dmi = NULL;
if (tmp.data_size <= KMALLOC_MAX_SIZE)
dmi = kmalloc(tmp.data_size, GFP_NOIO | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN);

if (!dmi) {
dmi = __vmalloc(tmp.data_size, GFP_NOIO | __GFP_REPEAT | __GFP_HIGH, PAGE_KERNEL);
*param_flags |= DM_PARAMS_VMALLOC;
}

if (!dmi) {
if (secure_data && clear_user(user, tmp.data_size))
return -EFAULT;
Expand All @@ -1566,6 +1594,14 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param)
if (copy_from_user(dmi, user, tmp.data_size))
goto bad;

/*
* Abort if something changed the ioctl data while it was being copied.
*/
if (dmi->data_size != tmp.data_size) {
DMERR("rejecting ioctl: data size modified while processing parameters");
goto bad;
}

/* Wipe the user buffer so we do not return it to userspace */
if (secure_data && clear_user(user, tmp.data_size))
goto bad;
Expand All @@ -1574,9 +1610,8 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param)
return 0;

bad:
if (secure_data)
memset(dmi, 0, tmp.data_size);
vfree(dmi);
free_params(dmi, tmp.data_size, *param_flags);

return -EFAULT;
}

Expand Down Expand Up @@ -1613,7 +1648,7 @@ static int validate_params(uint cmd, struct dm_ioctl *param)
static int ctl_ioctl(uint command, struct dm_ioctl __user *user)
{
int r = 0;
int wipe_buffer;
int param_flags;
unsigned int cmd;
struct dm_ioctl *uninitialized_var(param);
ioctl_fn fn = NULL;
Expand Down Expand Up @@ -1648,25 +1683,15 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user)
return -ENOTTY;
}

/*
* Trying to avoid low memory issues when a device is
* suspended.
*/
current->flags |= PF_MEMALLOC;

/*
* Copy the parameters into kernel space.
*/
r = copy_params(user, &param);

current->flags &= ~PF_MEMALLOC;
r = copy_params(user, &param, &param_flags);

if (r)
return r;

input_param_size = param->data_size;
wipe_buffer = param->flags & DM_SECURE_DATA_FLAG;

r = validate_params(cmd, param);
if (r)
goto out;
Expand All @@ -1681,10 +1706,7 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user)
r = -EFAULT;

out:
if (wipe_buffer)
memset(param, 0, input_param_size);

vfree(param);
free_params(param, input_param_size, param_flags);
return r;
}

Expand Down
18 changes: 14 additions & 4 deletions drivers/md/dm-kcopyd.c
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ static void complete_io(unsigned long error, void *context)
struct dm_kcopyd_client *kc = job->kc;

if (error) {
if (job->rw == WRITE)
if (job->rw & WRITE)
job->write_err |= error;
else
job->read_err = 1;
Expand All @@ -361,7 +361,7 @@ static void complete_io(unsigned long error, void *context)
}
}

if (job->rw == WRITE)
if (job->rw & WRITE)
push(&kc->complete_jobs, job);

else {
Expand Down Expand Up @@ -432,7 +432,7 @@ static int process_jobs(struct list_head *jobs, struct dm_kcopyd_client *kc,

if (r < 0) {
/* error this rogue job */
if (job->rw == WRITE)
if (job->rw & WRITE)
job->write_err = (unsigned long) -1L;
else
job->read_err = 1;
Expand Down Expand Up @@ -585,6 +585,7 @@ int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from,
unsigned int flags, dm_kcopyd_notify_fn fn, void *context)
{
struct kcopyd_job *job;
int i;

/*
* Allocate an array of jobs consisting of one master job
Expand All @@ -611,7 +612,16 @@ int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from,
memset(&job->source, 0, sizeof job->source);
job->source.count = job->dests[0].count;
job->pages = &zero_page_list;
job->rw = WRITE;

/*
* Use WRITE SAME to optimize zeroing if all dests support it.
*/
job->rw = WRITE | REQ_WRITE_SAME;
for (i = 0; i < job->num_dests; i++)
if (!bdev_write_same(job->dests[i].bdev)) {
job->rw = WRITE;
break;
}
}

job->fn = fn;
Expand Down
6 changes: 3 additions & 3 deletions drivers/md/dm-linear.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv)

ti->num_flush_requests = 1;
ti->num_discard_requests = 1;
ti->num_write_same_requests = 1;
ti->private = lc;
return 0;

Expand Down Expand Up @@ -87,8 +88,7 @@ static void linear_map_bio(struct dm_target *ti, struct bio *bio)
bio->bi_sector = linear_map_sector(ti, bio->bi_sector);
}

static int linear_map(struct dm_target *ti, struct bio *bio,
union map_info *map_context)
static int linear_map(struct dm_target *ti, struct bio *bio)
{
linear_map_bio(ti, bio);

Expand Down Expand Up @@ -155,7 +155,7 @@ static int linear_iterate_devices(struct dm_target *ti,

static struct target_type linear_target = {
.name = "linear",
.version = {1, 1, 0},
.version = {1, 2, 0},
.module = THIS_MODULE,
.ctr = linear_ctr,
.dtr = linear_dtr,
Expand Down
Loading

0 comments on commit b49249d

Please sign in to comment.