Merge branch 'for-2.6.38/core' of git://git.kernel.dk/linux-2.6-block

* 'for-2.6.38/core' of git://git.kernel.dk/linux-2.6-block: (43 commits)
  block: ensure that completion error gets properly traced
  blktrace: add missing probe argument to block_bio_complete
  block cfq: don't use atomic_t for cfq_group
  block cfq: don't use atomic_t for cfq_queue
  block: trace event block fix unassigned field
  block: add internal hd part table references
  block: fix accounting bug on cross partition merges
  kref: add kref_test_and_get
  bio-integrity: mark kintegrityd_wq highpri and CPU intensive
  block: make kblockd_workqueue smarter
  Revert "sd: implement sd_check_events()"
  block: Clean up exit_io_context() source code.
  Fix compile warnings due to missing removal of a 'ret' variable
  fs/block: type signature of major_to_index(int) to major_to_index(unsigned)
  block: convert !IS_ERR(p) && p to !IS_ERR_NOR_NULL(p)
  cfq-iosched: don't check cfqg in choose_service_tree()
  fs/splice: Pull buf->ops->confirm() from splice_from_pipe actors
  cdrom: export cdrom_check_events()
  sd: implement sd_check_events()
  sr: implement sr_check_events()
  ...
This commit is contained in:
Linus Torvalds 2011-01-13 10:45:01 -08:00
commit 275220f0fc
53 changed files with 1329 additions and 1091 deletions

View File

@ -89,6 +89,33 @@ Throttling/Upper Limit policy
Limits for writes can be put using blkio.write_bps_device file.
Hierarchical Cgroups
====================
- Currently none of the IO control policy supports hierarhical groups. But
cgroup interface does allow creation of hierarhical cgroups and internally
IO policies treat them as flat hierarchy.
So this patch will allow creation of cgroup hierarhcy but at the backend
everything will be treated as flat. So if somebody created a hierarchy like
as follows.
root
/ \
test1 test2
|
test3
CFQ and throttling will practically treat all groups at same level.
pivot
/ | \ \
root test1 test2 test3
Down the line we can implement hierarchical accounting/control support
and also introduce a new cgroup file "use_hierarchy" which will control
whether cgroup hierarchy is viewed as flat or hierarchical by the policy..
This is how memory controller also has implemented the things.
Various user visible config options
===================================
CONFIG_BLK_CGROUP

View File

@ -1452,10 +1452,6 @@ blkiocg_create(struct cgroup_subsys *subsys, struct cgroup *cgroup)
goto done;
}
/* Currently we do not support hierarchy deeper than two level (0,1) */
if (parent != cgroup->top_cgroup)
return ERR_PTR(-EPERM);
blkcg = kzalloc(sizeof(*blkcg), GFP_KERNEL);
if (!blkcg)
return ERR_PTR(-ENOMEM);

View File

@ -33,7 +33,7 @@
#include "blk.h"
EXPORT_TRACEPOINT_SYMBOL_GPL(block_remap);
EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_remap);
EXPORT_TRACEPOINT_SYMBOL_GPL(block_rq_remap);
EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_complete);
@ -64,13 +64,27 @@ static void drive_stat_acct(struct request *rq, int new_io)
return;
cpu = part_stat_lock();
part = disk_map_sector_rcu(rq->rq_disk, blk_rq_pos(rq));
if (!new_io)
if (!new_io) {
part = rq->part;
part_stat_inc(cpu, part, merges[rw]);
else {
} else {
part = disk_map_sector_rcu(rq->rq_disk, blk_rq_pos(rq));
if (!hd_struct_try_get(part)) {
/*
* The partition is already being removed,
* the request will be accounted on the disk only
*
* We take a reference on disk->part0 although that
* partition will never be deleted, so we can treat
* it as any other partition.
*/
part = &rq->rq_disk->part0;
hd_struct_get(part);
}
part_round_stats(cpu, part);
part_inc_in_flight(part, rw);
rq->part = part;
}
part_stat_unlock();
@ -128,6 +142,7 @@ void blk_rq_init(struct request_queue *q, struct request *rq)
rq->ref_count = 1;
rq->start_time = jiffies;
set_start_time_ns(rq);
rq->part = NULL;
}
EXPORT_SYMBOL(blk_rq_init);
@ -1329,9 +1344,9 @@ static inline void blk_partition_remap(struct bio *bio)
bio->bi_sector += p->start_sect;
bio->bi_bdev = bdev->bd_contains;
trace_block_remap(bdev_get_queue(bio->bi_bdev), bio,
bdev->bd_dev,
bio->bi_sector - p->start_sect);
trace_block_bio_remap(bdev_get_queue(bio->bi_bdev), bio,
bdev->bd_dev,
bio->bi_sector - p->start_sect);
}
}
@ -1500,7 +1515,7 @@ static inline void __generic_make_request(struct bio *bio)
goto end_io;
if (old_sector != -1)
trace_block_remap(q, bio, old_dev, old_sector);
trace_block_bio_remap(q, bio, old_dev, old_sector);
old_sector = bio->bi_sector;
old_dev = bio->bi_bdev->bd_dev;
@ -1776,7 +1791,7 @@ static void blk_account_io_completion(struct request *req, unsigned int bytes)
int cpu;
cpu = part_stat_lock();
part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req));
part = req->part;
part_stat_add(cpu, part, sectors[rw], bytes >> 9);
part_stat_unlock();
}
@ -1796,13 +1811,14 @@ static void blk_account_io_done(struct request *req)
int cpu;
cpu = part_stat_lock();
part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req));
part = req->part;
part_stat_inc(cpu, part, ios[rw]);
part_stat_add(cpu, part, ticks[rw], duration);
part_round_stats(cpu, part);
part_dec_in_flight(part, rw);
hd_struct_put(part);
part_stat_unlock();
}
}
@ -2606,7 +2622,9 @@ int __init blk_dev_init(void)
BUILD_BUG_ON(__REQ_NR_BITS > 8 *
sizeof(((struct request *)0)->cmd_flags));
kblockd_workqueue = create_workqueue("kblockd");
/* used for unplugging and affects IO latency/throughput - HIGHPRI */
kblockd_workqueue = alloc_workqueue("kblockd",
WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
if (!kblockd_workqueue)
panic("Failed to create kblockd\n");

View File

@ -64,7 +64,7 @@ static void cfq_exit(struct io_context *ioc)
rcu_read_unlock();
}
/* Called by the exitting task */
/* Called by the exiting task */
void exit_io_context(struct task_struct *task)
{
struct io_context *ioc;
@ -74,10 +74,9 @@ void exit_io_context(struct task_struct *task)
task->io_context = NULL;
task_unlock(task);
if (atomic_dec_and_test(&ioc->nr_tasks)) {
if (atomic_dec_and_test(&ioc->nr_tasks))
cfq_exit(ioc);
}
put_io_context(ioc);
}

View File

@ -351,11 +351,12 @@ static void blk_account_io_merge(struct request *req)
int cpu;
cpu = part_stat_lock();
part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req));
part = req->part;
part_round_stats(cpu, part);
part_dec_in_flight(part, rq_data_dir(req));
hd_struct_put(part);
part_stat_unlock();
}
}

View File

@ -87,7 +87,6 @@ struct cfq_rb_root {
unsigned count;
unsigned total_weight;
u64 min_vdisktime;
struct rb_node *active;
};
#define CFQ_RB_ROOT (struct cfq_rb_root) { .rb = RB_ROOT, .left = NULL, \
.count = 0, .min_vdisktime = 0, }
@ -97,7 +96,7 @@ struct cfq_rb_root {
*/
struct cfq_queue {
/* reference count */
atomic_t ref;
int ref;
/* various state flags, see below */
unsigned int flags;
/* parent cfq_data */
@ -180,7 +179,6 @@ struct cfq_group {
/* group service_tree key */
u64 vdisktime;
unsigned int weight;
bool on_st;
/* number of cfqq currently on this group */
int nr_cfqq;
@ -209,7 +207,7 @@ struct cfq_group {
struct blkio_group blkg;
#ifdef CONFIG_CFQ_GROUP_IOSCHED
struct hlist_node cfqd_node;
atomic_t ref;
int ref;
#endif
/* number of requests that are on the dispatch list or inside driver */
int dispatched;
@ -563,11 +561,6 @@ static void update_min_vdisktime(struct cfq_rb_root *st)
u64 vdisktime = st->min_vdisktime;
struct cfq_group *cfqg;
if (st->active) {
cfqg = rb_entry_cfqg(st->active);
vdisktime = cfqg->vdisktime;
}
if (st->left) {
cfqg = rb_entry_cfqg(st->left);
vdisktime = min_vdisktime(vdisktime, cfqg->vdisktime);
@ -646,11 +639,11 @@ cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
static inline bool cfq_slice_used(struct cfq_queue *cfqq)
{
if (cfq_cfqq_slice_new(cfqq))
return 0;
return false;
if (time_before(jiffies, cfqq->slice_end))
return 0;
return false;
return 1;
return true;
}
/*
@ -869,7 +862,7 @@ cfq_group_service_tree_add(struct cfq_data *cfqd, struct cfq_group *cfqg)
struct rb_node *n;
cfqg->nr_cfqq++;
if (cfqg->on_st)
if (!RB_EMPTY_NODE(&cfqg->rb_node))
return;
/*
@ -885,7 +878,6 @@ cfq_group_service_tree_add(struct cfq_data *cfqd, struct cfq_group *cfqg)
cfqg->vdisktime = st->min_vdisktime;
__cfq_group_service_tree_add(st, cfqg);
cfqg->on_st = true;
st->total_weight += cfqg->weight;
}
@ -894,9 +886,6 @@ cfq_group_service_tree_del(struct cfq_data *cfqd, struct cfq_group *cfqg)
{
struct cfq_rb_root *st = &cfqd->grp_service_tree;
if (st->active == &cfqg->rb_node)
st->active = NULL;
BUG_ON(cfqg->nr_cfqq < 1);
cfqg->nr_cfqq--;
@ -905,7 +894,6 @@ cfq_group_service_tree_del(struct cfq_data *cfqd, struct cfq_group *cfqg)
return;
cfq_log_cfqg(cfqd, cfqg, "del_from_rr group");
cfqg->on_st = false;
st->total_weight -= cfqg->weight;
if (!RB_EMPTY_NODE(&cfqg->rb_node))
cfq_rb_erase(&cfqg->rb_node, st);
@ -1026,7 +1014,7 @@ cfq_find_alloc_cfqg(struct cfq_data *cfqd, struct cgroup *cgroup, int create)
* elevator which will be dropped by either elevator exit
* or cgroup deletion path depending on who is exiting first.
*/
atomic_set(&cfqg->ref, 1);
cfqg->ref = 1;
/*
* Add group onto cgroup list. It might happen that bdi->dev is
@ -1071,7 +1059,7 @@ static struct cfq_group *cfq_get_cfqg(struct cfq_data *cfqd, int create)
static inline struct cfq_group *cfq_ref_get_cfqg(struct cfq_group *cfqg)
{
atomic_inc(&cfqg->ref);
cfqg->ref++;
return cfqg;
}
@ -1083,7 +1071,7 @@ static void cfq_link_cfqq_cfqg(struct cfq_queue *cfqq, struct cfq_group *cfqg)
cfqq->cfqg = cfqg;
/* cfqq reference on cfqg */
atomic_inc(&cfqq->cfqg->ref);
cfqq->cfqg->ref++;
}
static void cfq_put_cfqg(struct cfq_group *cfqg)
@ -1091,11 +1079,12 @@ static void cfq_put_cfqg(struct cfq_group *cfqg)
struct cfq_rb_root *st;
int i, j;
BUG_ON(atomic_read(&cfqg->ref) <= 0);
if (!atomic_dec_and_test(&cfqg->ref))
BUG_ON(cfqg->ref <= 0);
cfqg->ref--;
if (cfqg->ref)
return;
for_each_cfqg_st(cfqg, i, j, st)
BUG_ON(!RB_EMPTY_ROOT(&st->rb) || st->active != NULL);
BUG_ON(!RB_EMPTY_ROOT(&st->rb));
kfree(cfqg);
}
@ -1200,7 +1189,7 @@ static void cfq_service_tree_add(struct cfq_data *cfqd, struct cfq_queue *cfqq,
cfq_group_service_tree_del(cfqd, cfqq->cfqg);
cfqq->orig_cfqg = cfqq->cfqg;
cfqq->cfqg = &cfqd->root_group;
atomic_inc(&cfqd->root_group.ref);
cfqd->root_group.ref++;
group_changed = 1;
} else if (!cfqd->cfq_group_isolation
&& cfqq_type(cfqq) == SYNC_WORKLOAD && cfqq->orig_cfqg) {
@ -1687,9 +1676,6 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
if (cfqq == cfqd->active_queue)
cfqd->active_queue = NULL;
if (&cfqq->cfqg->rb_node == cfqd->grp_service_tree.active)
cfqd->grp_service_tree.active = NULL;
if (cfqd->active_cic) {
put_io_context(cfqd->active_cic->ioc);
cfqd->active_cic = NULL;
@ -1901,10 +1887,10 @@ static bool cfq_should_idle(struct cfq_data *cfqd, struct cfq_queue *cfqq)
* in their service tree.
*/
if (service_tree->count == 1 && cfq_cfqq_sync(cfqq))
return 1;
return true;
cfq_log_cfqq(cfqd, cfqq, "Not idling. st->count:%d",
service_tree->count);
return 0;
return false;
}
static void cfq_arm_slice_timer(struct cfq_data *cfqd)
@ -2040,7 +2026,7 @@ static int cfqq_process_refs(struct cfq_queue *cfqq)
int process_refs, io_refs;
io_refs = cfqq->allocated[READ] + cfqq->allocated[WRITE];
process_refs = atomic_read(&cfqq->ref) - io_refs;
process_refs = cfqq->ref - io_refs;
BUG_ON(process_refs < 0);
return process_refs;
}
@ -2080,10 +2066,10 @@ static void cfq_setup_merge(struct cfq_queue *cfqq, struct cfq_queue *new_cfqq)
*/
if (new_process_refs >= process_refs) {
cfqq->new_cfqq = new_cfqq;
atomic_add(process_refs, &new_cfqq->ref);
new_cfqq->ref += process_refs;
} else {
new_cfqq->new_cfqq = cfqq;
atomic_add(new_process_refs, &cfqq->ref);
cfqq->ref += new_process_refs;
}
}
@ -2116,12 +2102,7 @@ static void choose_service_tree(struct cfq_data *cfqd, struct cfq_group *cfqg)
unsigned count;
struct cfq_rb_root *st;
unsigned group_slice;
if (!cfqg) {
cfqd->serving_prio = IDLE_WORKLOAD;
cfqd->workload_expires = jiffies + 1;
return;
}
enum wl_prio_t original_prio = cfqd->serving_prio;
/* Choose next priority. RT > BE > IDLE */
if (cfq_group_busy_queues_wl(RT_WORKLOAD, cfqd, cfqg))
@ -2134,6 +2115,9 @@ static void choose_service_tree(struct cfq_data *cfqd, struct cfq_group *cfqg)
return;
}
if (original_prio != cfqd->serving_prio)
goto new_workload;
/*
* For RT and BE, we have to choose also the type
* (SYNC, SYNC_NOIDLE, ASYNC), and to compute a workload
@ -2148,6 +2132,7 @@ static void choose_service_tree(struct cfq_data *cfqd, struct cfq_group *cfqg)
if (count && !time_after(jiffies, cfqd->workload_expires))
return;
new_workload:
/* otherwise select new workload type */
cfqd->serving_type =
cfq_choose_wl(cfqd, cfqg, cfqd->serving_prio);
@ -2199,7 +2184,6 @@ static struct cfq_group *cfq_get_next_cfqg(struct cfq_data *cfqd)
if (RB_EMPTY_ROOT(&st->rb))
return NULL;
cfqg = cfq_rb_first_group(st);
st->active = &cfqg->rb_node;
update_min_vdisktime(st);
return cfqg;
}
@ -2293,6 +2277,17 @@ static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd)
goto keep_queue;
}
/*
* This is a deep seek queue, but the device is much faster than
* the queue can deliver, don't idle
**/
if (CFQQ_SEEKY(cfqq) && cfq_cfqq_idle_window(cfqq) &&
(cfq_cfqq_slice_new(cfqq) ||
(cfqq->slice_end - jiffies > jiffies - cfqq->slice_start))) {
cfq_clear_cfqq_deep(cfqq);
cfq_clear_cfqq_idle_window(cfqq);
}
if (cfqq->dispatched && cfq_should_idle(cfqd, cfqq)) {
cfqq = NULL;
goto keep_queue;
@ -2367,12 +2362,12 @@ static inline bool cfq_slice_used_soon(struct cfq_data *cfqd,
{
/* the queue hasn't finished any request, can't estimate */
if (cfq_cfqq_slice_new(cfqq))
return 1;
return true;
if (time_after(jiffies + cfqd->cfq_slice_idle * cfqq->dispatched,
cfqq->slice_end))
return 1;
return true;
return 0;
return false;
}
static bool cfq_may_dispatch(struct cfq_data *cfqd, struct cfq_queue *cfqq)
@ -2538,9 +2533,10 @@ static void cfq_put_queue(struct cfq_queue *cfqq)
struct cfq_data *cfqd = cfqq->cfqd;
struct cfq_group *cfqg, *orig_cfqg;
BUG_ON(atomic_read(&cfqq->ref) <= 0);
BUG_ON(cfqq->ref <= 0);
if (!atomic_dec_and_test(&cfqq->ref))
cfqq->ref--;
if (cfqq->ref)
return;
cfq_log_cfqq(cfqd, cfqq, "put_queue");
@ -2843,7 +2839,7 @@ static void cfq_init_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq,
RB_CLEAR_NODE(&cfqq->p_node);
INIT_LIST_HEAD(&cfqq->fifo);
atomic_set(&cfqq->ref, 0);
cfqq->ref = 0;
cfqq->cfqd = cfqd;
cfq_mark_cfqq_prio_changed(cfqq);
@ -2979,11 +2975,11 @@ cfq_get_queue(struct cfq_data *cfqd, bool is_sync, struct io_context *ioc,
* pin the queue now that it's allocated, scheduler exit will prune it
*/
if (!is_sync && !(*async_cfqq)) {
atomic_inc(&cfqq->ref);
cfqq->ref++;
*async_cfqq = cfqq;
}
atomic_inc(&cfqq->ref);
cfqq->ref++;
return cfqq;
}
@ -3265,6 +3261,10 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
if (cfq_class_rt(new_cfqq) && !cfq_class_rt(cfqq))
return true;
/* An idle queue should not be idle now for some reason */
if (RB_EMPTY_ROOT(&cfqq->sort_list) && !cfq_should_idle(cfqd, cfqq))
return true;
if (!cfqd->active_cic || !cfq_cfqq_wait_request(cfqq))
return false;
@ -3681,13 +3681,13 @@ new_queue:
}
cfqq->allocated[rw]++;
atomic_inc(&cfqq->ref);
spin_unlock_irqrestore(q->queue_lock, flags);
cfqq->ref++;
rq->elevator_private = cic;
rq->elevator_private2 = cfqq;
rq->elevator_private3 = cfq_ref_get_cfqg(cfqq->cfqg);
spin_unlock_irqrestore(q->queue_lock, flags);
return 0;
queue_fail:
@ -3862,6 +3862,10 @@ static void *cfq_init_queue(struct request_queue *q)
if (!cfqd)
return NULL;
/*
* Don't need take queue_lock in the routine, since we are
* initializing the ioscheduler, and nobody is using cfqd
*/
cfqd->cic_index = i;
/* Init root service tree */
@ -3881,7 +3885,7 @@ static void *cfq_init_queue(struct request_queue *q)
* Take a reference to root group which we never drop. This is just
* to make sure that cfq_put_cfqg() does not try to kfree root group
*/
atomic_set(&cfqg->ref, 1);
cfqg->ref = 1;
rcu_read_lock();
cfq_blkiocg_add_blkio_group(&blkio_root_cgroup, &cfqg->blkg,
(void *)cfqd, 0);
@ -3901,7 +3905,7 @@ static void *cfq_init_queue(struct request_queue *q)
* will not attempt to free it.
*/
cfq_init_cfqq(cfqd, &cfqd->oom_cfqq, 1, 0);
atomic_inc(&cfqd->oom_cfqq.ref);
cfqd->oom_cfqq.ref++;
cfq_link_cfqq_cfqg(&cfqd->oom_cfqq, &cfqd->root_group);
INIT_LIST_HEAD(&cfqd->cic_list);

View File

@ -18,6 +18,7 @@
#include <linux/buffer_head.h>
#include <linux/mutex.h>
#include <linux/idr.h>
#include <linux/log2.h>
#include "blk.h"
@ -35,6 +36,10 @@ static DEFINE_IDR(ext_devt_idr);
static struct device_type disk_type;
static void disk_add_events(struct gendisk *disk);
static void disk_del_events(struct gendisk *disk);
static void disk_release_events(struct gendisk *disk);
/**
* disk_get_part - get partition
* @disk: disk to look partition from
@ -239,7 +244,7 @@ static struct blk_major_name {
} *major_names[BLKDEV_MAJOR_HASH_SIZE];
/* index in the above - for now: assume no multimajor ranges */
static inline int major_to_index(int major)
static inline int major_to_index(unsigned major)
{
return major % BLKDEV_MAJOR_HASH_SIZE;
}
@ -502,6 +507,64 @@ static int exact_lock(dev_t devt, void *data)
return 0;
}
void register_disk(struct gendisk *disk)
{
struct device *ddev = disk_to_dev(disk);
struct block_device *bdev;
struct disk_part_iter piter;
struct hd_struct *part;
int err;
ddev->parent = disk->driverfs_dev;
dev_set_name(ddev, disk->disk_name);
/* delay uevents, until we scanned partition table */
dev_set_uevent_suppress(ddev, 1);
if (device_add(ddev))
return;
if (!sysfs_deprecated) {
err = sysfs_create_link(block_depr, &ddev->kobj,
kobject_name(&ddev->kobj));
if (err) {
device_del(ddev);
return;
}
}
disk->part0.holder_dir = kobject_create_and_add("holders", &ddev->kobj);
disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj);
/* No minors to use for partitions */
if (!disk_partitionable(disk))
goto exit;
/* No such device (e.g., media were just removed) */
if (!get_capacity(disk))
goto exit;
bdev = bdget_disk(disk, 0);
if (!bdev)
goto exit;
bdev->bd_invalidated = 1;
err = blkdev_get(bdev, FMODE_READ, NULL);
if (err < 0)
goto exit;
blkdev_put(bdev, FMODE_READ);
exit:
/* announce disk after possible partitions are created */
dev_set_uevent_suppress(ddev, 0);
kobject_uevent(&ddev->kobj, KOBJ_ADD);
/* announce possible partitions */
disk_part_iter_init(&piter, disk, 0);
while ((part = disk_part_iter_next(&piter)))
kobject_uevent(&part_to_dev(part)->kobj, KOBJ_ADD);
disk_part_iter_exit(&piter);
}
/**
* add_disk - add partitioning information to kernel list
* @disk: per-device partitioning information
@ -551,18 +614,48 @@ void add_disk(struct gendisk *disk)
retval = sysfs_create_link(&disk_to_dev(disk)->kobj, &bdi->dev->kobj,
"bdi");
WARN_ON(retval);
disk_add_events(disk);
}
EXPORT_SYMBOL(add_disk);
EXPORT_SYMBOL(del_gendisk); /* in partitions/check.c */
void unlink_gendisk(struct gendisk *disk)
void del_gendisk(struct gendisk *disk)
{
struct disk_part_iter piter;
struct hd_struct *part;
disk_del_events(disk);
/* invalidate stuff */
disk_part_iter_init(&piter, disk,
DISK_PITER_INCL_EMPTY | DISK_PITER_REVERSE);
while ((part = disk_part_iter_next(&piter))) {
invalidate_partition(disk, part->partno);
delete_partition(disk, part->partno);
}
disk_part_iter_exit(&piter);
invalidate_partition(disk, 0);
blk_free_devt(disk_to_dev(disk)->devt);
set_capacity(disk, 0);
disk->flags &= ~GENHD_FL_UP;
sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi");
bdi_unregister(&disk->queue->backing_dev_info);
blk_unregister_queue(disk);
blk_unregister_region(disk_devt(disk), disk->minors);
part_stat_set_all(&disk->part0, 0);
disk->part0.stamp = 0;
kobject_put(disk->part0.holder_dir);
kobject_put(disk->slave_dir);
disk->driverfs_dev = NULL;
if (!sysfs_deprecated)
sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk)));
device_del(disk_to_dev(disk));
}
EXPORT_SYMBOL(del_gendisk);
/**
* get_gendisk - get partitioning information for a given device
@ -735,7 +828,7 @@ static void *show_partition_start(struct seq_file *seqf, loff_t *pos)
static void *p;
p = disk_seqf_start(seqf, pos);
if (!IS_ERR(p) && p && !*pos)
if (!IS_ERR_OR_NULL(p) && !*pos)
seq_puts(seqf, "major minor #blocks name\n\n");
return p;
}
@ -1005,6 +1098,7 @@ static void disk_release(struct device *dev)
{
struct gendisk *disk = dev_to_disk(dev);
disk_release_events(disk);
kfree(disk->random);
disk_replace_part_tbl(disk, NULL);
free_part_stats(&disk->part0);
@ -1110,29 +1204,6 @@ static int __init proc_genhd_init(void)
module_init(proc_genhd_init);
#endif /* CONFIG_PROC_FS */
static void media_change_notify_thread(struct work_struct *work)
{
struct gendisk *gd = container_of(work, struct gendisk, async_notify);
char event[] = "MEDIA_CHANGE=1";
char *envp[] = { event, NULL };
/*
* set enviroment vars to indicate which event this is for
* so that user space will know to go check the media status.
*/
kobject_uevent_env(&disk_to_dev(gd)->kobj, KOBJ_CHANGE, envp);
put_device(gd->driverfs_dev);
}
#if 0
void genhd_media_change_notify(struct gendisk *disk)
{
get_device(disk->driverfs_dev);
schedule_work(&disk->async_notify);
}
EXPORT_SYMBOL_GPL(genhd_media_change_notify);
#endif /* 0 */
dev_t blk_lookup_devt(const char *name, int partno)
{
dev_t devt = MKDEV(0, 0);
@ -1193,13 +1264,13 @@ struct gendisk *alloc_disk_node(int minors, int node_id)
}
disk->part_tbl->part[0] = &disk->part0;
hd_ref_init(&disk->part0);
disk->minors = minors;
rand_initialize_disk(disk);
disk_to_dev(disk)->class = &block_class;
disk_to_dev(disk)->type = &disk_type;
device_initialize(disk_to_dev(disk));
INIT_WORK(&disk->async_notify,
media_change_notify_thread);
}
return disk;
}
@ -1291,3 +1362,422 @@ int invalidate_partition(struct gendisk *disk, int partno)
}
EXPORT_SYMBOL(invalidate_partition);
/*
* Disk events - monitor disk events like media change and eject request.
*/
struct disk_events {
struct list_head node; /* all disk_event's */
struct gendisk *disk; /* the associated disk */
spinlock_t lock;
int block; /* event blocking depth */
unsigned int pending; /* events already sent out */
unsigned int clearing; /* events being cleared */
long poll_msecs; /* interval, -1 for default */
struct delayed_work dwork;
};
static const char *disk_events_strs[] = {
[ilog2(DISK_EVENT_MEDIA_CHANGE)] = "media_change",
[ilog2(DISK_EVENT_EJECT_REQUEST)] = "eject_request",
};
static char *disk_uevents[] = {
[ilog2(DISK_EVENT_MEDIA_CHANGE)] = "DISK_MEDIA_CHANGE=1",
[ilog2(DISK_EVENT_EJECT_REQUEST)] = "DISK_EJECT_REQUEST=1",
};
/* list of all disk_events */
static DEFINE_MUTEX(disk_events_mutex);
static LIST_HEAD(disk_events);
/* disable in-kernel polling by default */
static unsigned long disk_events_dfl_poll_msecs = 0;
static unsigned long disk_events_poll_jiffies(struct gendisk *disk)
{
struct disk_events *ev = disk->ev;
long intv_msecs = 0;
/*
* If device-specific poll interval is set, always use it. If
* the default is being used, poll iff there are events which
* can't be monitored asynchronously.
*/
if (ev->poll_msecs >= 0)
intv_msecs = ev->poll_msecs;
else if (disk->events & ~disk->async_events)
intv_msecs = disk_events_dfl_poll_msecs;
return msecs_to_jiffies(intv_msecs);
}
static void __disk_block_events(struct gendisk *disk, bool sync)
{
struct disk_events *ev = disk->ev;
unsigned long flags;
bool cancel;
spin_lock_irqsave(&ev->lock, flags);
cancel = !ev->block++;
spin_unlock_irqrestore(&ev->lock, flags);
if (cancel) {
if (sync)
cancel_delayed_work_sync(&disk->ev->dwork);
else
cancel_delayed_work(&disk->ev->dwork);
}
}
static void __disk_unblock_events(struct gendisk *disk, bool check_now)
{
struct disk_events *ev = disk->ev;
unsigned long intv;
unsigned long flags;
spin_lock_irqsave(&ev->lock, flags);
if (WARN_ON_ONCE(ev->block <= 0))
goto out_unlock;
if (--ev->block)
goto out_unlock;
/*
* Not exactly a latency critical operation, set poll timer
* slack to 25% and kick event check.
*/
intv = disk_events_poll_jiffies(disk);
set_timer_slack(&ev->dwork.timer, intv / 4);
if (check_now)
queue_delayed_work(system_nrt_wq, &ev->dwork, 0);
else if (intv)
queue_delayed_work(system_nrt_wq, &ev->dwork, intv);
out_unlock:
spin_unlock_irqrestore(&ev->lock, flags);
}
/**
* disk_block_events - block and flush disk event checking
* @disk: disk to block events for
*
* On return from this function, it is guaranteed that event checking
* isn't in progress and won't happen until unblocked by
* disk_unblock_events(). Events blocking is counted and the actual
* unblocking happens after the matching number of unblocks are done.
*
* Note that this intentionally does not block event checking from
* disk_clear_events().
*
* CONTEXT:
* Might sleep.
*/
void disk_block_events(struct gendisk *disk)
{
if (disk->ev)
__disk_block_events(disk, true);
}
/**
* disk_unblock_events - unblock disk event checking
* @disk: disk to unblock events for
*
* Undo disk_block_events(). When the block count reaches zero, it
* starts events polling if configured.
*
* CONTEXT:
* Don't care. Safe to call from irq context.
*/
void disk_unblock_events(struct gendisk *disk)
{
if (disk->ev)
__disk_unblock_events(disk, true);
}
/**
* disk_check_events - schedule immediate event checking
* @disk: disk to check events for
*
* Schedule immediate event checking on @disk if not blocked.
*
* CONTEXT:
* Don't care. Safe to call from irq context.
*/
void disk_check_events(struct gendisk *disk)
{
if (disk->ev) {
__disk_block_events(disk, false);
__disk_unblock_events(disk, true);
}
}
EXPORT_SYMBOL_GPL(disk_check_events);
/**
* disk_clear_events - synchronously check, clear and return pending events
* @disk: disk to fetch and clear events from
* @mask: mask of events to be fetched and clearted
*
* Disk events are synchronously checked and pending events in @mask
* are cleared and returned. This ignores the block count.
*
* CONTEXT:
* Might sleep.
*/
unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask)
{
const struct block_device_operations *bdops = disk->fops;
struct disk_events *ev = disk->ev;
unsigned int pending;
if (!ev) {
/* for drivers still using the old ->media_changed method */
if ((mask & DISK_EVENT_MEDIA_CHANGE) &&
bdops->media_changed && bdops->media_changed(disk))
return DISK_EVENT_MEDIA_CHANGE;
return 0;
}
/* tell the workfn about the events being cleared */
spin_lock_irq(&ev->lock);
ev->clearing |= mask;
spin_unlock_irq(&ev->lock);
/* uncondtionally schedule event check and wait for it to finish */
__disk_block_events(disk, true);
queue_delayed_work(system_nrt_wq, &ev->dwork, 0);
flush_delayed_work(&ev->dwork);
__disk_unblock_events(disk, false);
/* then, fetch and clear pending events */
spin_lock_irq(&ev->lock);
WARN_ON_ONCE(ev->clearing & mask); /* cleared by workfn */
pending = ev->pending & mask;
ev->pending &= ~mask;
spin_unlock_irq(&ev->lock);
return pending;
}
static void disk_events_workfn(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
struct disk_events *ev = container_of(dwork, struct disk_events, dwork);
struct gendisk *disk = ev->disk;
char *envp[ARRAY_SIZE(disk_uevents) + 1] = { };
unsigned int clearing = ev->clearing;
unsigned int events;
unsigned long intv;
int nr_events = 0, i;
/* check events */
events = disk->fops->check_events(disk, clearing);
/* accumulate pending events and schedule next poll if necessary */
spin_lock_irq(&ev->lock);
events &= ~ev->pending;
ev->pending |= events;
ev->clearing &= ~clearing;
intv = disk_events_poll_jiffies(disk);
if (!ev->block && intv)
queue_delayed_work(system_nrt_wq, &ev->dwork, intv);
spin_unlock_irq(&ev->lock);
/* tell userland about new events */
for (i = 0; i < ARRAY_SIZE(disk_uevents); i++)
if (events & (1 << i))
envp[nr_events++] = disk_uevents[i];
if (nr_events)
kobject_uevent_env(&disk_to_dev(disk)->kobj, KOBJ_CHANGE, envp);
}
/*
* A disk events enabled device has the following sysfs nodes under
* its /sys/block/X/ directory.
*
* events : list of all supported events
* events_async : list of events which can be detected w/o polling
* events_poll_msecs : polling interval, 0: disable, -1: system default
*/
static ssize_t __disk_events_show(unsigned int events, char *buf)
{
const char *delim = "";
ssize_t pos = 0;
int i;
for (i = 0; i < ARRAY_SIZE(disk_events_strs); i++)
if (events & (1 << i)) {
pos += sprintf(buf + pos, "%s%s",
delim, disk_events_strs[i]);
delim = " ";
}
if (pos)
pos += sprintf(buf + pos, "\n");
return pos;
}
static ssize_t disk_events_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct gendisk *disk = dev_to_disk(dev);
return __disk_events_show(disk->events, buf);
}
static ssize_t disk_events_async_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct gendisk *disk = dev_to_disk(dev);
return __disk_events_show(disk->async_events, buf);
}
static ssize_t disk_events_poll_msecs_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct gendisk *disk = dev_to_disk(dev);
return sprintf(buf, "%ld\n", disk->ev->poll_msecs);
}
static ssize_t disk_events_poll_msecs_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct gendisk *disk = dev_to_disk(dev);
long intv;
if (!count || !sscanf(buf, "%ld", &intv))
return -EINVAL;
if (intv < 0 && intv != -1)
return -EINVAL;
__disk_block_events(disk, true);
disk->ev->poll_msecs = intv;
__disk_unblock_events(disk, true);
return count;
}
static const DEVICE_ATTR(events, S_IRUGO, disk_events_show, NULL);
static const DEVICE_ATTR(events_async, S_IRUGO, disk_events_async_show, NULL);
static const DEVICE_ATTR(events_poll_msecs, S_IRUGO|S_IWUSR,
disk_events_poll_msecs_show,
disk_events_poll_msecs_store);
static const struct attribute *disk_events_attrs[] = {
&dev_attr_events.attr,
&dev_attr_events_async.attr,
&dev_attr_events_poll_msecs.attr,
NULL,
};
/*
* The default polling interval can be specified by the kernel
* parameter block.events_dfl_poll_msecs which defaults to 0
* (disable). This can also be modified runtime by writing to
* /sys/module/block/events_dfl_poll_msecs.
*/
static int disk_events_set_dfl_poll_msecs(const char *val,
const struct kernel_param *kp)
{
struct disk_events *ev;
int ret;
ret = param_set_ulong(val, kp);
if (ret < 0)
return ret;
mutex_lock(&disk_events_mutex);
list_for_each_entry(ev, &disk_events, node)
disk_check_events(ev->disk);
mutex_unlock(&disk_events_mutex);
return 0;
}
static const struct kernel_param_ops disk_events_dfl_poll_msecs_param_ops = {
.set = disk_events_set_dfl_poll_msecs,
.get = param_get_ulong,
};
#undef MODULE_PARAM_PREFIX
#define MODULE_PARAM_PREFIX "block."
module_param_cb(events_dfl_poll_msecs, &disk_events_dfl_poll_msecs_param_ops,
&disk_events_dfl_poll_msecs, 0644);
/*
* disk_{add|del|release}_events - initialize and destroy disk_events.
*/
static void disk_add_events(struct gendisk *disk)
{
struct disk_events *ev;
if (!disk->fops->check_events || !(disk->events | disk->async_events))
return;
ev = kzalloc(sizeof(*ev), GFP_KERNEL);
if (!ev) {
pr_warn("%s: failed to initialize events\n", disk->disk_name);
return;
}
if (sysfs_create_files(&disk_to_dev(disk)->kobj,
disk_events_attrs) < 0) {
pr_warn("%s: failed to create sysfs files for events\n",
disk->disk_name);
kfree(ev);
return;
}
disk->ev = ev;
INIT_LIST_HEAD(&ev->node);
ev->disk = disk;
spin_lock_init(&ev->lock);
ev->block = 1;
ev->poll_msecs = -1;
INIT_DELAYED_WORK(&ev->dwork, disk_events_workfn);
mutex_lock(&disk_events_mutex);
list_add_tail(&ev->node, &disk_events);
mutex_unlock(&disk_events_mutex);
/*
* Block count is initialized to 1 and the following initial
* unblock kicks it into action.
*/
__disk_unblock_events(disk, true);
}
static void disk_del_events(struct gendisk *disk)
{
if (!disk->ev)
return;
__disk_block_events(disk, true);
mutex_lock(&disk_events_mutex);
list_del_init(&disk->ev->node);
mutex_unlock(&disk_events_mutex);
sysfs_remove_files(&disk_to_dev(disk)->kobj, disk_events_attrs);
}
static void disk_release_events(struct gendisk *disk)
{
/* the block count should be 1 from disk_del_events() */
WARN_ON_ONCE(disk->ev && disk->ev->block != 1);
kfree(disk->ev);
}

View File

@ -294,11 +294,12 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
return -EINVAL;
if (get_user(n, (int __user *) arg))
return -EFAULT;
if (!(mode & FMODE_EXCL) && bd_claim(bdev, &bdev) < 0)
if (!(mode & FMODE_EXCL) &&
blkdev_get(bdev, mode | FMODE_EXCL, &bdev) < 0)
return -EBUSY;
ret = set_blocksize(bdev, n);
if (!(mode & FMODE_EXCL))
bd_release(bdev);
blkdev_put(bdev, mode | FMODE_EXCL);
return ret;
case BLKPG:
ret = blkpg_ioctl(bdev, (struct blkpg_ioctl_arg __user *) arg);

View File

@ -911,8 +911,6 @@ struct drbd_md {
struct drbd_backing_dev {
struct block_device *backing_bdev;
struct block_device *md_bdev;
struct file *lo_file;
struct file *md_file;
struct drbd_md md;
struct disk_conf dc; /* The user provided config... */
sector_t known_size; /* last known size of that backing device */

View File

@ -3372,11 +3372,8 @@ void drbd_free_bc(struct drbd_backing_dev *ldev)
if (ldev == NULL)
return;
bd_release(ldev->backing_bdev);
bd_release(ldev->md_bdev);
fput(ldev->lo_file);
fput(ldev->md_file);
blkdev_put(ldev->backing_bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL);
blkdev_put(ldev->md_bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL);
kfree(ldev);
}

View File

@ -855,7 +855,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
sector_t max_possible_sectors;
sector_t min_md_device_sectors;
struct drbd_backing_dev *nbc = NULL; /* new_backing_conf */
struct inode *inode, *inode2;
struct block_device *bdev;
struct lru_cache *resync_lru = NULL;
union drbd_state ns, os;
unsigned int max_seg_s;
@ -907,46 +907,40 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
}
}
nbc->lo_file = filp_open(nbc->dc.backing_dev, O_RDWR, 0);
if (IS_ERR(nbc->lo_file)) {
bdev = blkdev_get_by_path(nbc->dc.backing_dev,
FMODE_READ | FMODE_WRITE | FMODE_EXCL, mdev);
if (IS_ERR(bdev)) {
dev_err(DEV, "open(\"%s\") failed with %ld\n", nbc->dc.backing_dev,
PTR_ERR(nbc->lo_file));
nbc->lo_file = NULL;
PTR_ERR(bdev));
retcode = ERR_OPEN_DISK;
goto fail;
}
nbc->backing_bdev = bdev;
inode = nbc->lo_file->f_dentry->d_inode;
if (!S_ISBLK(inode->i_mode)) {
retcode = ERR_DISK_NOT_BDEV;
goto fail;
}
nbc->md_file = filp_open(nbc->dc.meta_dev, O_RDWR, 0);
if (IS_ERR(nbc->md_file)) {
/*
* meta_dev_idx >= 0: external fixed size, possibly multiple
* drbd sharing one meta device. TODO in that case, paranoia
* check that [md_bdev, meta_dev_idx] is not yet used by some
* other drbd minor! (if you use drbd.conf + drbdadm, that
* should check it for you already; but if you don't, or
* someone fooled it, we need to double check here)
*/
bdev = blkdev_get_by_path(nbc->dc.meta_dev,
FMODE_READ | FMODE_WRITE | FMODE_EXCL,
(nbc->dc.meta_dev_idx < 0) ?
(void *)mdev : (void *)drbd_m_holder);
if (IS_ERR(bdev)) {
dev_err(DEV, "open(\"%s\") failed with %ld\n", nbc->dc.meta_dev,
PTR_ERR(nbc->md_file));
nbc->md_file = NULL;
PTR_ERR(bdev));
retcode = ERR_OPEN_MD_DISK;
goto fail;
}
nbc->md_bdev = bdev;
inode2 = nbc->md_file->f_dentry->d_inode;
if (!S_ISBLK(inode2->i_mode)) {
retcode = ERR_MD_NOT_BDEV;
goto fail;
}
nbc->backing_bdev = inode->i_bdev;
if (bd_claim(nbc->backing_bdev, mdev)) {
printk(KERN_ERR "drbd: bd_claim(%p,%p); failed [%p;%p;%u]\n",
nbc->backing_bdev, mdev,
nbc->backing_bdev->bd_holder,
nbc->backing_bdev->bd_contains->bd_holder,
nbc->backing_bdev->bd_holders);
retcode = ERR_BDCLAIM_DISK;
if ((nbc->backing_bdev == nbc->md_bdev) !=
(nbc->dc.meta_dev_idx == DRBD_MD_INDEX_INTERNAL ||
nbc->dc.meta_dev_idx == DRBD_MD_INDEX_FLEX_INT)) {
retcode = ERR_MD_IDX_INVALID;
goto fail;
}
@ -955,28 +949,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
offsetof(struct bm_extent, lce));
if (!resync_lru) {
retcode = ERR_NOMEM;
goto release_bdev_fail;
}
/* meta_dev_idx >= 0: external fixed size,
* possibly multiple drbd sharing one meta device.
* TODO in that case, paranoia check that [md_bdev, meta_dev_idx] is
* not yet used by some other drbd minor!
* (if you use drbd.conf + drbdadm,
* that should check it for you already; but if you don't, or someone
* fooled it, we need to double check here) */
nbc->md_bdev = inode2->i_bdev;
if (bd_claim(nbc->md_bdev, (nbc->dc.meta_dev_idx < 0) ? (void *)mdev
: (void *) drbd_m_holder)) {
retcode = ERR_BDCLAIM_MD_DISK;
goto release_bdev_fail;
}
if ((nbc->backing_bdev == nbc->md_bdev) !=
(nbc->dc.meta_dev_idx == DRBD_MD_INDEX_INTERNAL ||
nbc->dc.meta_dev_idx == DRBD_MD_INDEX_FLEX_INT)) {
retcode = ERR_MD_IDX_INVALID;
goto release_bdev2_fail;
goto fail;
}
/* RT - for drbd_get_max_capacity() DRBD_MD_INDEX_FLEX_INT */
@ -987,7 +960,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
(unsigned long long) drbd_get_max_capacity(nbc),
(unsigned long long) nbc->dc.disk_size);
retcode = ERR_DISK_TO_SMALL;
goto release_bdev2_fail;
goto fail;
}
if (nbc->dc.meta_dev_idx < 0) {
@ -1004,7 +977,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
dev_warn(DEV, "refusing attach: md-device too small, "
"at least %llu sectors needed for this meta-disk type\n",
(unsigned long long) min_md_device_sectors);
goto release_bdev2_fail;
goto fail;
}
/* Make sure the new disk is big enough
@ -1012,7 +985,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
if (drbd_get_max_capacity(nbc) <
drbd_get_capacity(mdev->this_bdev)) {
retcode = ERR_DISK_TO_SMALL;
goto release_bdev2_fail;
goto fail;
}
nbc->known_size = drbd_get_capacity(nbc->backing_bdev);
@ -1035,7 +1008,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
retcode = _drbd_request_state(mdev, NS(disk, D_ATTACHING), CS_VERBOSE);
drbd_resume_io(mdev);
if (retcode < SS_SUCCESS)
goto release_bdev2_fail;
goto fail;
if (!get_ldev_if_state(mdev, D_ATTACHING))
goto force_diskless;
@ -1269,18 +1242,14 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
force_diskless:
drbd_force_state(mdev, NS(disk, D_FAILED));
drbd_md_sync(mdev);
release_bdev2_fail:
if (nbc)
bd_release(nbc->md_bdev);
release_bdev_fail:
if (nbc)
bd_release(nbc->backing_bdev);
fail:
if (nbc) {
if (nbc->lo_file)
fput(nbc->lo_file);
if (nbc->md_file)
fput(nbc->md_file);
if (nbc->backing_bdev)
blkdev_put(nbc->backing_bdev,
FMODE_READ | FMODE_WRITE | FMODE_EXCL);
if (nbc->md_bdev)
blkdev_put(nbc->md_bdev,
FMODE_READ | FMODE_WRITE | FMODE_EXCL);
kfree(nbc);
}
lc_destroy(resync_lru);

View File

@ -395,11 +395,7 @@ lo_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
struct loop_device *lo = p->lo;
struct page *page = buf->page;
sector_t IV;
int size, ret;
ret = buf->ops->confirm(pipe, buf);
if (unlikely(ret))
return ret;
int size;
IV = ((sector_t) page->index << (PAGE_CACHE_SHIFT - 9)) +
(buf->offset >> 9);

View File

@ -2296,15 +2296,12 @@ static int pkt_open_dev(struct pktcdvd_device *pd, fmode_t write)
* so bdget() can't fail.
*/
bdget(pd->bdev->bd_dev);
if ((ret = blkdev_get(pd->bdev, FMODE_READ)))
if ((ret = blkdev_get(pd->bdev, FMODE_READ | FMODE_EXCL, pd)))
goto out;
if ((ret = bd_claim(pd->bdev, pd)))
goto out_putdev;
if ((ret = pkt_get_last_written(pd, &lba))) {
printk(DRIVER_NAME": pkt_get_last_written failed\n");
goto out_unclaim;
goto out_putdev;
}
set_capacity(pd->disk, lba << 2);
@ -2314,7 +2311,7 @@ static int pkt_open_dev(struct pktcdvd_device *pd, fmode_t write)
q = bdev_get_queue(pd->bdev);
if (write) {
if ((ret = pkt_open_write(pd)))
goto out_unclaim;
goto out_putdev;
/*
* Some CDRW drives can not handle writes larger than one packet,
* even if the size is a multiple of the packet size.
@ -2329,23 +2326,21 @@ static int pkt_open_dev(struct pktcdvd_device *pd, fmode_t write)
}
if ((ret = pkt_set_segment_merging(pd, q)))
goto out_unclaim;
goto out_putdev;
if (write) {
if (!pkt_grow_pktlist(pd, CONFIG_CDROM_PKTCDVD_BUFFERS)) {
printk(DRIVER_NAME": not enough memory for buffers\n");
ret = -ENOMEM;
goto out_unclaim;
goto out_putdev;
}
printk(DRIVER_NAME": %lukB available on disc\n", lba << 1);
}
return 0;
out_unclaim:
bd_release(pd->bdev);
out_putdev:
blkdev_put(pd->bdev, FMODE_READ);
blkdev_put(pd->bdev, FMODE_READ | FMODE_EXCL);
out:
return ret;
}
@ -2362,8 +2357,7 @@ static void pkt_release_dev(struct pktcdvd_device *pd, int flush)
pkt_lock_door(pd, 0);
pkt_set_speed(pd, MAX_SPEED, MAX_SPEED);
bd_release(pd->bdev);
blkdev_put(pd->bdev, FMODE_READ);
blkdev_put(pd->bdev, FMODE_READ | FMODE_EXCL);
pkt_shrink_pktlist(pd);
}
@ -2733,7 +2727,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
bdev = bdget(dev);
if (!bdev)
return -ENOMEM;
ret = blkdev_get(bdev, FMODE_READ | FMODE_NDELAY);
ret = blkdev_get(bdev, FMODE_READ | FMODE_NDELAY, NULL);
if (ret)
return ret;

View File

@ -1348,7 +1348,10 @@ static int cdrom_select_disc(struct cdrom_device_info *cdi, int slot)
if (!CDROM_CAN(CDC_SELECT_DISC))
return -EDRIVE_CANT_DO_THIS;
(void) cdi->ops->media_changed(cdi, slot);
if (cdi->ops->check_events)
cdi->ops->check_events(cdi, 0, slot);
else
cdi->ops->media_changed(cdi, slot);
if (slot == CDSL_NONE) {
/* set media changed bits, on both queues */
@ -1392,6 +1395,42 @@ static int cdrom_select_disc(struct cdrom_device_info *cdi, int slot)
return slot;
}
/*
* As cdrom implements an extra ioctl consumer for media changed
* event, it needs to buffer ->check_events() output, such that event
* is not lost for both the usual VFS and ioctl paths.
* cdi->{vfs|ioctl}_events are used to buffer pending events for each
* path.
*
* XXX: Locking is non-existent. cdi->ops->check_events() can be
* called in parallel and buffering fields are accessed without any
* exclusion. The original media_changed code had the same problem.
* It might be better to simply deprecate CDROM_MEDIA_CHANGED ioctl
* and remove this cruft altogether. It doesn't have much usefulness
* at this point.
*/
static void cdrom_update_events(struct cdrom_device_info *cdi,
unsigned int clearing)
{
unsigned int events;
events = cdi->ops->check_events(cdi, clearing, CDSL_CURRENT);
cdi->vfs_events |= events;
cdi->ioctl_events |= events;
}
unsigned int cdrom_check_events(struct cdrom_device_info *cdi,
unsigned int clearing)
{
unsigned int events;
cdrom_update_events(cdi, clearing);
events = cdi->vfs_events;
cdi->vfs_events = 0;
return events;
}
EXPORT_SYMBOL(cdrom_check_events);
/* We want to make media_changed accessible to the user through an
* ioctl. The main problem now is that we must double-buffer the
* low-level implementation, to assure that the VFS and the user both
@ -1403,15 +1442,26 @@ int media_changed(struct cdrom_device_info *cdi, int queue)
{
unsigned int mask = (1 << (queue & 1));
int ret = !!(cdi->mc_flags & mask);
bool changed;
if (!CDROM_CAN(CDC_MEDIA_CHANGED))
return ret;
return ret;
/* changed since last call? */
if (cdi->ops->media_changed(cdi, CDSL_CURRENT)) {
if (cdi->ops->check_events) {
BUG_ON(!queue); /* shouldn't be called from VFS path */
cdrom_update_events(cdi, DISK_EVENT_MEDIA_CHANGE);
changed = cdi->ioctl_events & DISK_EVENT_MEDIA_CHANGE;
cdi->ioctl_events = 0;
} else
changed = cdi->ops->media_changed(cdi, CDSL_CURRENT);
if (changed) {
cdi->mc_flags = 0x3; /* set bit on both queues */
ret |= 1;
cdi->media_written = 0;
}
cdi->mc_flags &= ~mask; /* clear bit */
return ret;
}

View File

@ -65,15 +65,12 @@ static int raw_open(struct inode *inode, struct file *filp)
if (!bdev)
goto out;
igrab(bdev->bd_inode);
err = blkdev_get(bdev, filp->f_mode);
err = blkdev_get(bdev, filp->f_mode | FMODE_EXCL, raw_open);
if (err)
goto out;
err = bd_claim(bdev, raw_open);
if (err)
goto out1;
err = set_blocksize(bdev, bdev_logical_block_size(bdev));
if (err)
goto out2;
goto out1;
filp->f_flags |= O_DIRECT;
filp->f_mapping = bdev->bd_inode->i_mapping;
if (++raw_devices[minor].inuse == 1)
@ -83,10 +80,8 @@ static int raw_open(struct inode *inode, struct file *filp)
mutex_unlock(&raw_mutex);
return 0;
out2:
bd_release(bdev);
out1:
blkdev_put(bdev, filp->f_mode);
blkdev_put(bdev, filp->f_mode | FMODE_EXCL);
out:
mutex_unlock(&raw_mutex);
return err;
@ -110,8 +105,7 @@ static int raw_release(struct inode *inode, struct file *filp)
}
mutex_unlock(&raw_mutex);
bd_release(bdev);
blkdev_put(bdev, filp->f_mode);
blkdev_put(bdev, filp->f_mode | FMODE_EXCL);
return 0;
}

View File

@ -325,15 +325,18 @@ static int open_dev(struct dm_dev_internal *d, dev_t dev,
BUG_ON(d->dm_dev.bdev);
bdev = open_by_devnum(dev, d->dm_dev.mode);
bdev = blkdev_get_by_dev(dev, d->dm_dev.mode | FMODE_EXCL, _claim_ptr);
if (IS_ERR(bdev))
return PTR_ERR(bdev);
r = bd_claim_by_disk(bdev, _claim_ptr, dm_disk(md));
if (r)
blkdev_put(bdev, d->dm_dev.mode);
else
d->dm_dev.bdev = bdev;
return r;
r = bd_link_disk_holder(bdev, dm_disk(md));
if (r) {
blkdev_put(bdev, d->dm_dev.mode | FMODE_EXCL);
return r;
}
d->dm_dev.bdev = bdev;
return 0;
}
/*
@ -344,8 +347,7 @@ static void close_dev(struct dm_dev_internal *d, struct mapped_device *md)
if (!d->dm_dev.bdev)
return;
bd_release_from_disk(d->dm_dev.bdev, dm_disk(md));
blkdev_put(d->dm_dev.bdev, d->dm_dev.mode);
blkdev_put(d->dm_dev.bdev, d->dm_dev.mode | FMODE_EXCL);
d->dm_dev.bdev = NULL;
}

View File

@ -630,7 +630,7 @@ static void dec_pending(struct dm_io *io, int error)
queue_io(md, bio);
} else {
/* done with normal IO or empty flush */
trace_block_bio_complete(md->queue, bio);
trace_block_bio_complete(md->queue, bio, io_error);
bio_endio(bio, io_error);
}
}
@ -990,8 +990,8 @@ static void __map_bio(struct dm_target *ti, struct bio *clone,
if (r == DM_MAPIO_REMAPPED) {
/* the bio has been remapped so dispatch it */
trace_block_remap(bdev_get_queue(clone->bi_bdev), clone,
tio->io->bio->bi_bdev->bd_dev, sector);
trace_block_bio_remap(bdev_get_queue(clone->bi_bdev), clone,
tio->io->bio->bi_bdev->bd_dev, sector);
generic_make_request(clone);
} else if (r < 0 || r == DM_MAPIO_REQUEUE) {

View File

@ -1879,7 +1879,7 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
rdev->sysfs_state = sysfs_get_dirent_safe(rdev->kobj.sd, "state");
list_add_rcu(&rdev->same_set, &mddev->disks);
bd_claim_by_disk(rdev->bdev, rdev->bdev->bd_holder, mddev->gendisk);
bd_link_disk_holder(rdev->bdev, mddev->gendisk);
/* May as well allow recovery to be retried once */
mddev->recovery_disabled = 0;
@ -1906,7 +1906,6 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev)
MD_BUG();
return;
}
bd_release_from_disk(rdev->bdev, rdev->mddev->gendisk);
list_del_rcu(&rdev->same_set);
printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b));
rdev->mddev = NULL;
@ -1934,19 +1933,13 @@ static int lock_rdev(mdk_rdev_t *rdev, dev_t dev, int shared)
struct block_device *bdev;
char b[BDEVNAME_SIZE];
bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE);
bdev = blkdev_get_by_dev(dev, FMODE_READ|FMODE_WRITE|FMODE_EXCL,
shared ? (mdk_rdev_t *)lock_rdev : rdev);
if (IS_ERR(bdev)) {
printk(KERN_ERR "md: could not open %s.\n",
__bdevname(dev, b));
return PTR_ERR(bdev);
}
err = bd_claim(bdev, shared ? (mdk_rdev_t *)lock_rdev : rdev);
if (err) {
printk(KERN_ERR "md: could not bd_claim %s.\n",
bdevname(bdev, b));
blkdev_put(bdev, FMODE_READ|FMODE_WRITE);
return err;
}
if (!shared)
set_bit(AllReserved, &rdev->flags);
rdev->bdev = bdev;
@ -1959,8 +1952,7 @@ static void unlock_rdev(mdk_rdev_t *rdev)
rdev->bdev = NULL;
if (!bdev)
MD_BUG();
bd_release(bdev);
blkdev_put(bdev, FMODE_READ|FMODE_WRITE);
blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
}
void md_autodetect_dev(dev_t dev);

View File

@ -224,7 +224,7 @@ static void block2mtd_free_device(struct block2mtd_dev *dev)
if (dev->blkdev) {
invalidate_mapping_pages(dev->blkdev->bd_inode->i_mapping,
0, -1);
close_bdev_exclusive(dev->blkdev, FMODE_READ|FMODE_WRITE);
blkdev_put(dev->blkdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
}
kfree(dev);
@ -234,6 +234,7 @@ static void block2mtd_free_device(struct block2mtd_dev *dev)
/* FIXME: ensure that mtd->size % erase_size == 0 */
static struct block2mtd_dev *add_device(char *devname, int erase_size)
{
const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL;
struct block_device *bdev;
struct block2mtd_dev *dev;
char *name;
@ -246,7 +247,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
return NULL;
/* Get a handle on the device */
bdev = open_bdev_exclusive(devname, FMODE_READ|FMODE_WRITE, NULL);
bdev = blkdev_get_by_path(devname, mode, dev);
#ifndef MODULE
if (IS_ERR(bdev)) {
@ -254,9 +255,8 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
to resolve the device name by other means. */
dev_t devt = name_to_dev_t(devname);
if (devt) {
bdev = open_by_devnum(devt, FMODE_WRITE | FMODE_READ);
}
if (devt)
bdev = blkdev_get_by_dev(devt, mode, dev);
}
#endif

View File

@ -103,7 +103,7 @@ int dasd_scan_partitions(struct dasd_block *block)
struct block_device *bdev;
bdev = bdget_disk(block->gdp, 0);
if (!bdev || blkdev_get(bdev, FMODE_READ) < 0)
if (!bdev || blkdev_get(bdev, FMODE_READ, NULL) < 0)
return -ENODEV;
/*
* See fs/partition/check.c:register_disk,rescan_partitions

View File

@ -1977,8 +1977,7 @@ EXPORT_SYMBOL(scsi_mode_sense);
* in.
*
* Returns zero if unsuccessful or an error if TUR failed. For
* removable media, a return of NOT_READY or UNIT_ATTENTION is
* translated to success, with the ->changed flag updated.
* removable media, UNIT_ATTENTION sets ->changed flag.
**/
int
scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries,
@ -2005,16 +2004,6 @@ scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries,
} while (scsi_sense_valid(sshdr) &&
sshdr->sense_key == UNIT_ATTENTION && --retries);
if (!sshdr)
/* could not allocate sense buffer, so can't process it */
return result;
if (sdev->removable && scsi_sense_valid(sshdr) &&
(sshdr->sense_key == UNIT_ATTENTION ||
sshdr->sense_key == NOT_READY)) {
sdev->changed = 1;
result = 0;
}
if (!sshdr_external)
kfree(sshdr);
return result;

View File

@ -1043,15 +1043,7 @@ static int sd_media_changed(struct gendisk *disk)
sshdr);
}
/*
* Unable to test, unit probably not ready. This usually
* means there is no disc in the drive. Mark as changed,
* and we will figure it out later once the drive is
* available again.
*/
if (retval || (scsi_sense_valid(sshdr) &&
/* 0x3a is medium not present */
sshdr->asc == 0x3a)) {
if (retval) {
set_media_not_present(sdkp);
goto out;
}

View File

@ -104,14 +104,15 @@ static void sr_release(struct cdrom_device_info *);
static void get_sectorsize(struct scsi_cd *);
static void get_capabilities(struct scsi_cd *);
static int sr_media_change(struct cdrom_device_info *, int);
static unsigned int sr_check_events(struct cdrom_device_info *cdi,
unsigned int clearing, int slot);
static int sr_packet(struct cdrom_device_info *, struct packet_command *);
static struct cdrom_device_ops sr_dops = {
.open = sr_open,
.release = sr_release,
.drive_status = sr_drive_status,
.media_changed = sr_media_change,
.check_events = sr_check_events,
.tray_move = sr_tray_move,
.lock_door = sr_lock_door,
.select_speed = sr_select_speed,
@ -165,90 +166,96 @@ static void scsi_cd_put(struct scsi_cd *cd)
mutex_unlock(&sr_ref_mutex);
}
/* identical to scsi_test_unit_ready except that it doesn't
* eat the NOT_READY returns for removable media */
int sr_test_unit_ready(struct scsi_device *sdev, struct scsi_sense_hdr *sshdr)
static unsigned int sr_get_events(struct scsi_device *sdev)
{
int retries = MAX_RETRIES;
int the_result;
u8 cmd[] = {TEST_UNIT_READY, 0, 0, 0, 0, 0 };
u8 buf[8];
u8 cmd[] = { GET_EVENT_STATUS_NOTIFICATION,
1, /* polled */
0, 0, /* reserved */
1 << 4, /* notification class: media */
0, 0, /* reserved */
0, sizeof(buf), /* allocation length */
0, /* control */
};
struct event_header *eh = (void *)buf;
struct media_event_desc *med = (void *)(buf + 4);
struct scsi_sense_hdr sshdr;
int result;
/* issue TEST_UNIT_READY until the initial startup UNIT_ATTENTION
* conditions are gone, or a timeout happens
*/
do {
the_result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL,
0, sshdr, SR_TIMEOUT,
retries--, NULL);
if (scsi_sense_valid(sshdr) &&
sshdr->sense_key == UNIT_ATTENTION)
sdev->changed = 1;
result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, sizeof(buf),
&sshdr, SR_TIMEOUT, MAX_RETRIES, NULL);
if (scsi_sense_valid(&sshdr) && sshdr.sense_key == UNIT_ATTENTION)
return DISK_EVENT_MEDIA_CHANGE;
} while (retries > 0 &&
(!scsi_status_is_good(the_result) ||
(scsi_sense_valid(sshdr) &&
sshdr->sense_key == UNIT_ATTENTION)));
return the_result;
if (result || be16_to_cpu(eh->data_len) < sizeof(*med))
return 0;
if (eh->nea || eh->notification_class != 0x4)
return 0;
if (med->media_event_code == 1)
return DISK_EVENT_EJECT_REQUEST;
else if (med->media_event_code == 2)
return DISK_EVENT_MEDIA_CHANGE;
return 0;
}
/*
* This function checks to see if the media has been changed in the
* CDROM drive. It is possible that we have already sensed a change,
* or the drive may have sensed one and not yet reported it. We must
* be ready for either case. This function always reports the current
* value of the changed bit. If flag is 0, then the changed bit is reset.
* This function could be done as an ioctl, but we would need to have
* an inode for that to work, and we do not always have one.
* This function checks to see if the media has been changed or eject
* button has been pressed. It is possible that we have already
* sensed a change, or the drive may have sensed one and not yet
* reported it. The past events are accumulated in sdev->changed and
* returned together with the current state.
*/
static int sr_media_change(struct cdrom_device_info *cdi, int slot)
static unsigned int sr_check_events(struct cdrom_device_info *cdi,
unsigned int clearing, int slot)
{
struct scsi_cd *cd = cdi->handle;
int retval;
struct scsi_sense_hdr *sshdr;
bool last_present;
struct scsi_sense_hdr sshdr;
unsigned int events;
int ret;
if (CDSL_CURRENT != slot) {
/* no changer support */
return -EINVAL;
/* no changer support */
if (CDSL_CURRENT != slot)
return 0;
events = sr_get_events(cd->device);
/*
* GET_EVENT_STATUS_NOTIFICATION is enough unless MEDIA_CHANGE
* is being cleared. Note that there are devices which hang
* if asked to execute TUR repeatedly.
*/
if (!(clearing & DISK_EVENT_MEDIA_CHANGE))
goto skip_tur;
/* let's see whether the media is there with TUR */
last_present = cd->media_present;
ret = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr);
/*
* Media is considered to be present if TUR succeeds or fails with
* sense data indicating something other than media-not-present
* (ASC 0x3a).
*/
cd->media_present = scsi_status_is_good(ret) ||
(scsi_sense_valid(&sshdr) && sshdr.asc != 0x3a);
if (last_present != cd->media_present)
events |= DISK_EVENT_MEDIA_CHANGE;
skip_tur:
if (cd->device->changed) {
events |= DISK_EVENT_MEDIA_CHANGE;
cd->device->changed = 0;
}
sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL);
retval = sr_test_unit_ready(cd->device, sshdr);
if (retval || (scsi_sense_valid(sshdr) &&
/* 0x3a is medium not present */
sshdr->asc == 0x3a)) {
/* Media not present or unable to test, unit probably not
* ready. This usually means there is no disc in the drive.
* Mark as changed, and we will figure it out later once
* the drive is available again.
*/
cd->device->changed = 1;
/* This will force a flush, if called from check_disk_change */
retval = 1;
goto out;
};
retval = cd->device->changed;
cd->device->changed = 0;
/* If the disk changed, the capacity will now be different,
* so we force a re-read of this information */
if (retval) {
/* check multisession offset etc */
sr_cd_check(cdi);
get_sectorsize(cd);
}
out:
/* Notify userspace, that media has changed. */
if (retval != cd->previous_state)
/* for backward compatibility */
if (events & DISK_EVENT_MEDIA_CHANGE)
sdev_evt_send_simple(cd->device, SDEV_EVT_MEDIA_CHANGE,
GFP_KERNEL);
cd->previous_state = retval;
kfree(sshdr);
return retval;
return events;
}
/*
* sr_done is the interrupt routine for the device driver.
*
@ -533,10 +540,25 @@ out:
return ret;
}
static int sr_block_media_changed(struct gendisk *disk)
static unsigned int sr_block_check_events(struct gendisk *disk,
unsigned int clearing)
{
struct scsi_cd *cd = scsi_cd(disk);
return cdrom_media_changed(&cd->cdi);
return cdrom_check_events(&cd->cdi, clearing);
}
static int sr_block_revalidate_disk(struct gendisk *disk)
{
struct scsi_cd *cd = scsi_cd(disk);
struct scsi_sense_hdr sshdr;
/* if the unit is not ready, nothing more to do */
if (scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr))
return 0;
sr_cd_check(&cd->cdi);
get_sectorsize(cd);
return 0;
}
static const struct block_device_operations sr_bdops =
@ -545,7 +567,8 @@ static const struct block_device_operations sr_bdops =
.open = sr_block_open,
.release = sr_block_release,
.ioctl = sr_block_ioctl,
.media_changed = sr_block_media_changed,
.check_events = sr_block_check_events,
.revalidate_disk = sr_block_revalidate_disk,
/*
* No compat_ioctl for now because sr_block_ioctl never
* seems to pass arbitary ioctls down to host drivers.
@ -618,6 +641,7 @@ static int sr_probe(struct device *dev)
sprintf(disk->disk_name, "sr%d", minor);
disk->fops = &sr_bdops;
disk->flags = GENHD_FL_CD;
disk->events = DISK_EVENT_MEDIA_CHANGE | DISK_EVENT_EJECT_REQUEST;
blk_queue_rq_timeout(sdev->request_queue, SR_TIMEOUT);
@ -627,7 +651,7 @@ static int sr_probe(struct device *dev)
cd->disk = disk;
cd->capacity = 0x1fffff;
cd->device->changed = 1; /* force recheck CD type */
cd->previous_state = 1;
cd->media_present = 1;
cd->use = 1;
cd->readcd_known = 0;
cd->readcd_cdda = 0;
@ -780,7 +804,7 @@ static void get_capabilities(struct scsi_cd *cd)
}
/* eat unit attentions */
sr_test_unit_ready(cd->device, &sshdr);
scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr);
/* ask for mode page 0x2a */
rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, 128,

View File

@ -40,7 +40,7 @@ typedef struct scsi_cd {
unsigned xa_flag:1; /* CD has XA sectors ? */
unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */
unsigned readcd_cdda:1; /* reading audio data using READ_CD */
unsigned previous_state:1; /* media has changed */
unsigned media_present:1; /* media is present */
struct cdrom_device_info cdi;
/* We hold gendisk and scsi_device references on probe and use
* the refs on this kref to decide when to release them */
@ -61,7 +61,6 @@ int sr_select_speed(struct cdrom_device_info *cdi, int speed);
int sr_audio_ioctl(struct cdrom_device_info *, unsigned int, void *);
int sr_is_xa(Scsi_CD *);
int sr_test_unit_ready(struct scsi_device *sdev, struct scsi_sense_hdr *sshdr);
/* sr_vendor.c */
void sr_vendor_init(Scsi_CD *);

View File

@ -307,7 +307,7 @@ int sr_drive_status(struct cdrom_device_info *cdi, int slot)
/* we have no changer support */
return -EINVAL;
}
if (0 == sr_test_unit_ready(cd->device, &sshdr))
if (!scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr))
return CDS_DISC_OK;
/* SK/ASC/ASCQ of 2/4/1 means "unit is becoming ready" */

View File

@ -543,7 +543,7 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
ro = curlun->initially_ro;
if (!ro) {
filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0);
if (-EROFS == PTR_ERR(filp))
if (PTR_ERR(filp) == -EROFS || PTR_ERR(filp) == -EACCES)
ro = 1;
}
if (ro)
@ -558,10 +558,7 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
if (filp->f_path.dentry)
inode = filp->f_path.dentry->d_inode;
if (inode && S_ISBLK(inode->i_mode)) {
if (bdev_read_only(inode->i_bdev))
ro = 1;
} else if (!inode || !S_ISREG(inode->i_mode)) {
if (!inode || (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))) {
LINFO(curlun, "invalid file type: %s\n", filename);
goto out;
}

View File

@ -782,7 +782,12 @@ void __init bio_integrity_init(void)
{
unsigned int i;
kintegrityd_wq = create_workqueue("kintegrityd");
/*
* kintegrityd won't block much but may burn a lot of CPU cycles.
* Make it highpri CPU intensive wq with max concurrency of 1.
*/
kintegrityd_wq = alloc_workqueue("kintegrityd", WQ_MEM_RECLAIM |
WQ_HIGHPRI | WQ_CPU_INTENSIVE, 1);
if (!kintegrityd_wq)
panic("Failed to create kintegrityd\n");

View File

@ -432,9 +432,6 @@ static void init_once(void *foo)
mutex_init(&bdev->bd_mutex);
INIT_LIST_HEAD(&bdev->bd_inodes);
INIT_LIST_HEAD(&bdev->bd_list);
#ifdef CONFIG_SYSFS
INIT_LIST_HEAD(&bdev->bd_holder_list);
#endif
inode_init_once(&ei->vfs_inode);
/* Initialize mutex for freeze. */
mutex_init(&bdev->bd_fsfreeze_mutex);
@ -669,7 +666,7 @@ static bool bd_may_claim(struct block_device *bdev, struct block_device *whole,
else if (bdev->bd_contains == bdev)
return true; /* is a whole device which isn't held */
else if (whole->bd_holder == bd_claim)
else if (whole->bd_holder == bd_may_claim)
return true; /* is a partition of a device that is being partitioned */
else if (whole->bd_holder != NULL)
return false; /* is a partition of a held device */
@ -781,440 +778,88 @@ static struct block_device *bd_start_claiming(struct block_device *bdev,
}
}
/* releases bdev_lock */
static void __bd_abort_claiming(struct block_device *whole, void *holder)
{
BUG_ON(whole->bd_claiming != holder);
whole->bd_claiming = NULL;
wake_up_bit(&whole->bd_claiming, 0);
spin_unlock(&bdev_lock);
bdput(whole);
}
/**
* bd_abort_claiming - abort claiming a block device
* @whole: whole block device returned by bd_start_claiming()
* @holder: holder trying to claim @bdev
*
* Abort a claiming block started by bd_start_claiming(). Note that
* @whole is not the block device to be claimed but the whole device
* returned by bd_start_claiming().
*
* CONTEXT:
* Grabs and releases bdev_lock.
*/
static void bd_abort_claiming(struct block_device *whole, void *holder)
{
spin_lock(&bdev_lock);
__bd_abort_claiming(whole, holder); /* releases bdev_lock */
}
/* increment holders when we have a legitimate claim. requires bdev_lock */
static void __bd_claim(struct block_device *bdev, struct block_device *whole,
void *holder)
{
/* note that for a whole device bd_holders
* will be incremented twice, and bd_holder will
* be set to bd_claim before being set to holder
*/
whole->bd_holders++;
whole->bd_holder = bd_claim;
bdev->bd_holders++;
bdev->bd_holder = holder;
}
/**
* bd_finish_claiming - finish claiming a block device
* @bdev: block device of interest (passed to bd_start_claiming())
* @whole: whole block device returned by bd_start_claiming()
* @holder: holder trying to claim @bdev
*
* Finish a claiming block started by bd_start_claiming().
*
* CONTEXT:
* Grabs and releases bdev_lock.
*/
static void bd_finish_claiming(struct block_device *bdev,
struct block_device *whole, void *holder)
{
spin_lock(&bdev_lock);
BUG_ON(!bd_may_claim(bdev, whole, holder));
__bd_claim(bdev, whole, holder);
__bd_abort_claiming(whole, holder); /* not actually an abort */
}
/**
* bd_claim - claim a block device
* @bdev: block device to claim
* @holder: holder trying to claim @bdev
*
* Try to claim @bdev which must have been opened successfully.
*
* CONTEXT:
* Might sleep.
*
* RETURNS:
* 0 if successful, -EBUSY if @bdev is already claimed.
*/
int bd_claim(struct block_device *bdev, void *holder)
{
struct block_device *whole = bdev->bd_contains;
int res;
might_sleep();
spin_lock(&bdev_lock);
res = bd_prepare_to_claim(bdev, whole, holder);
if (res == 0)
__bd_claim(bdev, whole, holder);
spin_unlock(&bdev_lock);
return res;
}
EXPORT_SYMBOL(bd_claim);
void bd_release(struct block_device *bdev)
{
spin_lock(&bdev_lock);
if (!--bdev->bd_contains->bd_holders)
bdev->bd_contains->bd_holder = NULL;
if (!--bdev->bd_holders)
bdev->bd_holder = NULL;
spin_unlock(&bdev_lock);
}
EXPORT_SYMBOL(bd_release);
#ifdef CONFIG_SYSFS
/*
* Functions for bd_claim_by_kobject / bd_release_from_kobject
*
* If a kobject is passed to bd_claim_by_kobject()
* and the kobject has a parent directory,
* following symlinks are created:
* o from the kobject to the claimed bdev
* o from "holders" directory of the bdev to the parent of the kobject
* bd_release_from_kobject() removes these symlinks.
*
* Example:
* If /dev/dm-0 maps to /dev/sda, kobject corresponding to
* /sys/block/dm-0/slaves is passed to bd_claim_by_kobject(), then:
* /sys/block/dm-0/slaves/sda --> /sys/block/sda
* /sys/block/sda/holders/dm-0 --> /sys/block/dm-0
*/
static int add_symlink(struct kobject *from, struct kobject *to)
{
if (!from || !to)
return 0;
return sysfs_create_link(from, to, kobject_name(to));
}
static void del_symlink(struct kobject *from, struct kobject *to)
{
if (!from || !to)
return;
sysfs_remove_link(from, kobject_name(to));
}
/*
* 'struct bd_holder' contains pointers to kobjects symlinked by
* bd_claim_by_kobject.
* It's connected to bd_holder_list which is protected by bdev->bd_sem.
*/
struct bd_holder {
struct list_head list; /* chain of holders of the bdev */
int count; /* references from the holder */
struct kobject *sdir; /* holder object, e.g. "/block/dm-0/slaves" */
struct kobject *hdev; /* e.g. "/block/dm-0" */
struct kobject *hdir; /* e.g. "/block/sda/holders" */
struct kobject *sdev; /* e.g. "/block/sda" */
};
/*
* Get references of related kobjects at once.
* Returns 1 on success. 0 on failure.
*
* Should call bd_holder_release_dirs() after successful use.
*/
static int bd_holder_grab_dirs(struct block_device *bdev,
struct bd_holder *bo)
{
if (!bdev || !bo)
return 0;
bo->sdir = kobject_get(bo->sdir);
if (!bo->sdir)
return 0;
bo->hdev = kobject_get(bo->sdir->parent);
if (!bo->hdev)
goto fail_put_sdir;
bo->sdev = kobject_get(&part_to_dev(bdev->bd_part)->kobj);
if (!bo->sdev)
goto fail_put_hdev;
bo->hdir = kobject_get(bdev->bd_part->holder_dir);
if (!bo->hdir)
goto fail_put_sdev;
return 1;
fail_put_sdev:
kobject_put(bo->sdev);
fail_put_hdev:
kobject_put(bo->hdev);
fail_put_sdir:
kobject_put(bo->sdir);
return 0;
}
/* Put references of related kobjects at once. */
static void bd_holder_release_dirs(struct bd_holder *bo)
{
kobject_put(bo->hdir);
kobject_put(bo->sdev);
kobject_put(bo->hdev);
kobject_put(bo->sdir);
}
static struct bd_holder *alloc_bd_holder(struct kobject *kobj)
{
struct bd_holder *bo;
bo = kzalloc(sizeof(*bo), GFP_KERNEL);
if (!bo)
return NULL;
bo->count = 1;
bo->sdir = kobj;
return bo;
}
static void free_bd_holder(struct bd_holder *bo)
{
kfree(bo);
}
/**
* find_bd_holder - find matching struct bd_holder from the block device
* bd_link_disk_holder - create symlinks between holding disk and slave bdev
* @bdev: the claimed slave bdev
* @disk: the holding disk
*
* @bdev: struct block device to be searched
* @bo: target struct bd_holder
* This functions creates the following sysfs symlinks.
*
* Returns matching entry with @bo in @bdev->bd_holder_list.
* If found, increment the reference count and return the pointer.
* If not found, returns NULL.
* - from "slaves" directory of the holder @disk to the claimed @bdev
* - from "holders" directory of the @bdev to the holder @disk
*
* For example, if /dev/dm-0 maps to /dev/sda and disk for dm-0 is
* passed to bd_link_disk_holder(), then:
*
* /sys/block/dm-0/slaves/sda --> /sys/block/sda
* /sys/block/sda/holders/dm-0 --> /sys/block/dm-0
*
* The caller must have claimed @bdev before calling this function and
* ensure that both @bdev and @disk are valid during the creation and
* lifetime of these symlinks.
*
* CONTEXT:
* Might sleep.
*
* RETURNS:
* 0 on success, -errno on failure.
*/
static struct bd_holder *find_bd_holder(struct block_device *bdev,
struct bd_holder *bo)
int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk)
{
struct bd_holder *tmp;
list_for_each_entry(tmp, &bdev->bd_holder_list, list)
if (tmp->sdir == bo->sdir) {
tmp->count++;
return tmp;
}
return NULL;
}
/**
* add_bd_holder - create sysfs symlinks for bd_claim() relationship
*
* @bdev: block device to be bd_claimed
* @bo: preallocated and initialized by alloc_bd_holder()
*
* Add @bo to @bdev->bd_holder_list, create symlinks.
*
* Returns 0 if symlinks are created.
* Returns -ve if something fails.
*/
static int add_bd_holder(struct block_device *bdev, struct bd_holder *bo)
{
int err;
if (!bo)
return -EINVAL;
if (!bd_holder_grab_dirs(bdev, bo))
return -EBUSY;
err = add_symlink(bo->sdir, bo->sdev);
if (err)
return err;
err = add_symlink(bo->hdir, bo->hdev);
if (err) {
del_symlink(bo->sdir, bo->sdev);
return err;
}
list_add_tail(&bo->list, &bdev->bd_holder_list);
return 0;
}
/**
* del_bd_holder - delete sysfs symlinks for bd_claim() relationship
*
* @bdev: block device to be bd_claimed
* @kobj: holder's kobject
*
* If there is matching entry with @kobj in @bdev->bd_holder_list
* and no other bd_claim() from the same kobject,
* remove the struct bd_holder from the list, delete symlinks for it.
*
* Returns a pointer to the struct bd_holder when it's removed from the list
* and ready to be freed.
* Returns NULL if matching claim isn't found or there is other bd_claim()
* by the same kobject.
*/
static struct bd_holder *del_bd_holder(struct block_device *bdev,
struct kobject *kobj)
{
struct bd_holder *bo;
list_for_each_entry(bo, &bdev->bd_holder_list, list) {
if (bo->sdir == kobj) {
bo->count--;
BUG_ON(bo->count < 0);
if (!bo->count) {
list_del(&bo->list);
del_symlink(bo->sdir, bo->sdev);
del_symlink(bo->hdir, bo->hdev);
bd_holder_release_dirs(bo);
return bo;
}
break;
}
}
return NULL;
}
/**
* bd_claim_by_kobject - bd_claim() with additional kobject signature
*
* @bdev: block device to be claimed
* @holder: holder's signature
* @kobj: holder's kobject
*
* Do bd_claim() and if it succeeds, create sysfs symlinks between
* the bdev and the holder's kobject.
* Use bd_release_from_kobject() when relesing the claimed bdev.
*
* Returns 0 on success. (same as bd_claim())
* Returns errno on failure.
*/
static int bd_claim_by_kobject(struct block_device *bdev, void *holder,
struct kobject *kobj)
{
int err;
struct bd_holder *bo, *found;
if (!kobj)
return -EINVAL;
bo = alloc_bd_holder(kobj);
if (!bo)
return -ENOMEM;
int ret = 0;
mutex_lock(&bdev->bd_mutex);
err = bd_claim(bdev, holder);
if (err)
goto fail;
WARN_ON_ONCE(!bdev->bd_holder || bdev->bd_holder_disk);
found = find_bd_holder(bdev, bo);
if (found)
goto fail;
/* FIXME: remove the following once add_disk() handles errors */
if (WARN_ON(!disk->slave_dir || !bdev->bd_part->holder_dir))
goto out_unlock;
err = add_bd_holder(bdev, bo);
if (err)
bd_release(bdev);
else
bo = NULL;
fail:
ret = add_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
if (ret)
goto out_unlock;
ret = add_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj);
if (ret) {
del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
goto out_unlock;
}
bdev->bd_holder_disk = disk;
out_unlock:
mutex_unlock(&bdev->bd_mutex);
free_bd_holder(bo);
return err;
return ret;
}
EXPORT_SYMBOL_GPL(bd_link_disk_holder);
/**
* bd_release_from_kobject - bd_release() with additional kobject signature
*
* @bdev: block device to be released
* @kobj: holder's kobject
*
* Do bd_release() and remove sysfs symlinks created by bd_claim_by_kobject().
*/
static void bd_release_from_kobject(struct block_device *bdev,
struct kobject *kobj)
static void bd_unlink_disk_holder(struct block_device *bdev)
{
if (!kobj)
struct gendisk *disk = bdev->bd_holder_disk;
bdev->bd_holder_disk = NULL;
if (!disk)
return;
mutex_lock(&bdev->bd_mutex);
bd_release(bdev);
free_bd_holder(del_bd_holder(bdev, kobj));
mutex_unlock(&bdev->bd_mutex);
del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
del_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj);
}
/**
* bd_claim_by_disk - wrapper function for bd_claim_by_kobject()
*
* @bdev: block device to be claimed
* @holder: holder's signature
* @disk: holder's gendisk
*
* Call bd_claim_by_kobject() with getting @disk->slave_dir.
*/
int bd_claim_by_disk(struct block_device *bdev, void *holder,
struct gendisk *disk)
{
return bd_claim_by_kobject(bdev, holder, kobject_get(disk->slave_dir));
}
EXPORT_SYMBOL_GPL(bd_claim_by_disk);
/**
* bd_release_from_disk - wrapper function for bd_release_from_kobject()
*
* @bdev: block device to be claimed
* @disk: holder's gendisk
*
* Call bd_release_from_kobject() and put @disk->slave_dir.
*/
void bd_release_from_disk(struct block_device *bdev, struct gendisk *disk)
{
bd_release_from_kobject(bdev, disk->slave_dir);
kobject_put(disk->slave_dir);
}
EXPORT_SYMBOL_GPL(bd_release_from_disk);
#else
static inline void bd_unlink_disk_holder(struct block_device *bdev)
{ }
#endif
/*
* Tries to open block device by device number. Use it ONLY if you
* really do not have anything better - i.e. when you are behind a
* truly sucky interface and all you are given is a device number. _Never_
* to be used for internal purposes. If you ever need it - reconsider
* your API.
*/
struct block_device *open_by_devnum(dev_t dev, fmode_t mode)
{
struct block_device *bdev = bdget(dev);
int err = -ENOMEM;
if (bdev)
err = blkdev_get(bdev, mode);
return err ? ERR_PTR(err) : bdev;
}
EXPORT_SYMBOL(open_by_devnum);
/**
* flush_disk - invalidates all buffer-cache entries on a disk
*
@ -1309,10 +954,11 @@ int check_disk_change(struct block_device *bdev)
{
struct gendisk *disk = bdev->bd_disk;
const struct block_device_operations *bdops = disk->fops;
unsigned int events;
if (!bdops->media_changed)
return 0;
if (!bdops->media_changed(bdev->bd_disk))
events = disk_clear_events(disk, DISK_EVENT_MEDIA_CHANGE |
DISK_EVENT_EJECT_REQUEST);
if (!(events & DISK_EVENT_MEDIA_CHANGE))
return 0;
flush_disk(bdev);
@ -1475,17 +1121,171 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
return ret;
}
int blkdev_get(struct block_device *bdev, fmode_t mode)
/**
* blkdev_get - open a block device
* @bdev: block_device to open
* @mode: FMODE_* mask
* @holder: exclusive holder identifier
*
* Open @bdev with @mode. If @mode includes %FMODE_EXCL, @bdev is
* open with exclusive access. Specifying %FMODE_EXCL with %NULL
* @holder is invalid. Exclusive opens may nest for the same @holder.
*
* On success, the reference count of @bdev is unchanged. On failure,
* @bdev is put.
*
* CONTEXT:
* Might sleep.
*
* RETURNS:
* 0 on success, -errno on failure.
*/
int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder)
{
return __blkdev_get(bdev, mode, 0);
struct block_device *whole = NULL;
int res;
WARN_ON_ONCE((mode & FMODE_EXCL) && !holder);
if ((mode & FMODE_EXCL) && holder) {
whole = bd_start_claiming(bdev, holder);
if (IS_ERR(whole)) {
bdput(bdev);
return PTR_ERR(whole);
}
}
res = __blkdev_get(bdev, mode, 0);
/* __blkdev_get() may alter read only status, check it afterwards */
if (!res && (mode & FMODE_WRITE) && bdev_read_only(bdev)) {
__blkdev_put(bdev, mode, 0);
res = -EACCES;
}
if (whole) {
/* finish claiming */
mutex_lock(&bdev->bd_mutex);
spin_lock(&bdev_lock);
if (!res) {
BUG_ON(!bd_may_claim(bdev, whole, holder));
/*
* Note that for a whole device bd_holders
* will be incremented twice, and bd_holder
* will be set to bd_may_claim before being
* set to holder
*/
whole->bd_holders++;
whole->bd_holder = bd_may_claim;
bdev->bd_holders++;
bdev->bd_holder = holder;
}
/* tell others that we're done */
BUG_ON(whole->bd_claiming != holder);
whole->bd_claiming = NULL;
wake_up_bit(&whole->bd_claiming, 0);
spin_unlock(&bdev_lock);
/*
* Block event polling for write claims. Any write
* holder makes the write_holder state stick until all
* are released. This is good enough and tracking
* individual writeable reference is too fragile given
* the way @mode is used in blkdev_get/put().
*/
if (!res && (mode & FMODE_WRITE) && !bdev->bd_write_holder) {
bdev->bd_write_holder = true;
disk_block_events(bdev->bd_disk);
}
mutex_unlock(&bdev->bd_mutex);
bdput(whole);
}
return res;
}
EXPORT_SYMBOL(blkdev_get);
/**
* blkdev_get_by_path - open a block device by name
* @path: path to the block device to open
* @mode: FMODE_* mask
* @holder: exclusive holder identifier
*
* Open the blockdevice described by the device file at @path. @mode
* and @holder are identical to blkdev_get().
*
* On success, the returned block_device has reference count of one.
*
* CONTEXT:
* Might sleep.
*
* RETURNS:
* Pointer to block_device on success, ERR_PTR(-errno) on failure.
*/
struct block_device *blkdev_get_by_path(const char *path, fmode_t mode,
void *holder)
{
struct block_device *bdev;
int err;
bdev = lookup_bdev(path);
if (IS_ERR(bdev))
return bdev;
err = blkdev_get(bdev, mode, holder);
if (err)
return ERR_PTR(err);
return bdev;
}
EXPORT_SYMBOL(blkdev_get_by_path);
/**
* blkdev_get_by_dev - open a block device by device number
* @dev: device number of block device to open
* @mode: FMODE_* mask
* @holder: exclusive holder identifier
*
* Open the blockdevice described by device number @dev. @mode and
* @holder are identical to blkdev_get().
*
* Use it ONLY if you really do not have anything better - i.e. when
* you are behind a truly sucky interface and all you are given is a
* device number. _Never_ to be used for internal purposes. If you
* ever need it - reconsider your API.
*
* On success, the returned block_device has reference count of one.
*
* CONTEXT:
* Might sleep.
*
* RETURNS:
* Pointer to block_device on success, ERR_PTR(-errno) on failure.
*/
struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode, void *holder)
{
struct block_device *bdev;
int err;
bdev = bdget(dev);
if (!bdev)
return ERR_PTR(-ENOMEM);
err = blkdev_get(bdev, mode, holder);
if (err)
return ERR_PTR(err);
return bdev;
}
EXPORT_SYMBOL(blkdev_get_by_dev);
static int blkdev_open(struct inode * inode, struct file * filp)
{
struct block_device *whole = NULL;
struct block_device *bdev;
int res;
/*
* Preserve backwards compatibility and allow large file access
@ -1506,26 +1306,9 @@ static int blkdev_open(struct inode * inode, struct file * filp)
if (bdev == NULL)
return -ENOMEM;
if (filp->f_mode & FMODE_EXCL) {
whole = bd_start_claiming(bdev, filp);
if (IS_ERR(whole)) {
bdput(bdev);
return PTR_ERR(whole);
}
}
filp->f_mapping = bdev->bd_inode->i_mapping;
res = blkdev_get(bdev, filp->f_mode);
if (whole) {
if (res == 0)
bd_finish_claiming(bdev, whole, filp);
else
bd_abort_claiming(whole, filp);
}
return res;
return blkdev_get(bdev, filp->f_mode, filp);
}
static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part)
@ -1539,6 +1322,7 @@ static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part)
bdev->bd_part_count--;
if (!--bdev->bd_openers) {
WARN_ON_ONCE(bdev->bd_holders);
sync_blockdev(bdev);
kill_bdev(bdev);
}
@ -1569,6 +1353,45 @@ static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part)
int blkdev_put(struct block_device *bdev, fmode_t mode)
{
if (mode & FMODE_EXCL) {
bool bdev_free;
/*
* Release a claim on the device. The holder fields
* are protected with bdev_lock. bd_mutex is to
* synchronize disk_holder unlinking.
*/
mutex_lock(&bdev->bd_mutex);
spin_lock(&bdev_lock);
WARN_ON_ONCE(--bdev->bd_holders < 0);
WARN_ON_ONCE(--bdev->bd_contains->bd_holders < 0);
/* bd_contains might point to self, check in a separate step */
if ((bdev_free = !bdev->bd_holders))
bdev->bd_holder = NULL;
if (!bdev->bd_contains->bd_holders)
bdev->bd_contains->bd_holder = NULL;
spin_unlock(&bdev_lock);
/*
* If this was the last claim, remove holder link and
* unblock evpoll if it was a write holder.
*/
if (bdev_free) {
bd_unlink_disk_holder(bdev);
if (bdev->bd_write_holder) {
disk_unblock_events(bdev->bd_disk);
bdev->bd_write_holder = false;
} else
disk_check_events(bdev->bd_disk);
}
mutex_unlock(&bdev->bd_mutex);
} else
disk_check_events(bdev->bd_disk);
return __blkdev_put(bdev, mode, 0);
}
EXPORT_SYMBOL(blkdev_put);
@ -1576,8 +1399,7 @@ EXPORT_SYMBOL(blkdev_put);
static int blkdev_close(struct inode * inode, struct file * filp)
{
struct block_device *bdev = I_BDEV(filp->f_mapping->host);
if (bdev->bd_holder == filp)
bd_release(bdev);
return blkdev_put(bdev, filp->f_mode);
}
@ -1722,67 +1544,6 @@ fail:
}
EXPORT_SYMBOL(lookup_bdev);
/**
* open_bdev_exclusive - open a block device by name and set it up for use
*
* @path: special file representing the block device
* @mode: FMODE_... combination to pass be used
* @holder: owner for exclusion
*
* Open the blockdevice described by the special file at @path, claim it
* for the @holder.
*/
struct block_device *open_bdev_exclusive(const char *path, fmode_t mode, void *holder)
{
struct block_device *bdev, *whole;
int error;
bdev = lookup_bdev(path);
if (IS_ERR(bdev))
return bdev;
whole = bd_start_claiming(bdev, holder);
if (IS_ERR(whole)) {
bdput(bdev);
return whole;
}
error = blkdev_get(bdev, mode);
if (error)
goto out_abort_claiming;
error = -EACCES;
if ((mode & FMODE_WRITE) && bdev_read_only(bdev))
goto out_blkdev_put;
bd_finish_claiming(bdev, whole, holder);
return bdev;
out_blkdev_put:
blkdev_put(bdev, mode);
out_abort_claiming:
bd_abort_claiming(whole, holder);
return ERR_PTR(error);
}
EXPORT_SYMBOL(open_bdev_exclusive);
/**
* close_bdev_exclusive - close a blockdevice opened by open_bdev_exclusive()
*
* @bdev: blockdevice to close
* @mode: mode, must match that used to open.
*
* This is the counterpart to open_bdev_exclusive().
*/
void close_bdev_exclusive(struct block_device *bdev, fmode_t mode)
{
bd_release(bdev);
blkdev_put(bdev, mode);
}
EXPORT_SYMBOL(close_bdev_exclusive);
int __invalidate_device(struct block_device *bdev)
{
struct super_block *sb = get_super(bdev);

View File

@ -493,7 +493,7 @@ again:
continue;
if (device->bdev) {
close_bdev_exclusive(device->bdev, device->mode);
blkdev_put(device->bdev, device->mode);
device->bdev = NULL;
fs_devices->open_devices--;
}
@ -527,7 +527,7 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
list_for_each_entry(device, &fs_devices->devices, dev_list) {
if (device->bdev) {
close_bdev_exclusive(device->bdev, device->mode);
blkdev_put(device->bdev, device->mode);
fs_devices->open_devices--;
}
if (device->writeable) {
@ -584,13 +584,15 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
int seeding = 1;
int ret = 0;
flags |= FMODE_EXCL;
list_for_each_entry(device, head, dev_list) {
if (device->bdev)
continue;
if (!device->name)
continue;
bdev = open_bdev_exclusive(device->name, flags, holder);
bdev = blkdev_get_by_path(device->name, flags, holder);
if (IS_ERR(bdev)) {
printk(KERN_INFO "open %s failed\n", device->name);
goto error;
@ -642,7 +644,7 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
error_brelse:
brelse(bh);
error_close:
close_bdev_exclusive(bdev, FMODE_READ);
blkdev_put(bdev, flags);
error:
continue;
}
@ -688,7 +690,8 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
mutex_lock(&uuid_mutex);
bdev = open_bdev_exclusive(path, flags, holder);
flags |= FMODE_EXCL;
bdev = blkdev_get_by_path(path, flags, holder);
if (IS_ERR(bdev)) {
ret = PTR_ERR(bdev);
@ -720,7 +723,7 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
brelse(bh);
error_close:
close_bdev_exclusive(bdev, flags);
blkdev_put(bdev, flags);
error:
mutex_unlock(&uuid_mutex);
return ret;
@ -1183,8 +1186,8 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
goto out;
}
} else {
bdev = open_bdev_exclusive(device_path, FMODE_READ,
root->fs_info->bdev_holder);
bdev = blkdev_get_by_path(device_path, FMODE_READ | FMODE_EXCL,
root->fs_info->bdev_holder);
if (IS_ERR(bdev)) {
ret = PTR_ERR(bdev);
goto out;
@ -1251,7 +1254,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
root->fs_info->fs_devices->latest_bdev = next_device->bdev;
if (device->bdev) {
close_bdev_exclusive(device->bdev, device->mode);
blkdev_put(device->bdev, device->mode);
device->bdev = NULL;
device->fs_devices->open_devices--;
}
@ -1294,7 +1297,7 @@ error_brelse:
brelse(bh);
error_close:
if (bdev)
close_bdev_exclusive(bdev, FMODE_READ);
blkdev_put(bdev, FMODE_READ | FMODE_EXCL);
out:
mutex_unlock(&root->fs_info->volume_mutex);
mutex_unlock(&uuid_mutex);
@ -1446,7 +1449,8 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
if ((sb->s_flags & MS_RDONLY) && !root->fs_info->fs_devices->seeding)
return -EINVAL;
bdev = open_bdev_exclusive(device_path, 0, root->fs_info->bdev_holder);
bdev = blkdev_get_by_path(device_path, FMODE_EXCL,
root->fs_info->bdev_holder);
if (IS_ERR(bdev))
return PTR_ERR(bdev);
@ -1572,7 +1576,7 @@ out:
mutex_unlock(&root->fs_info->volume_mutex);
return ret;
error:
close_bdev_exclusive(bdev, 0);
blkdev_put(bdev, FMODE_EXCL);
if (seeding_dev) {
mutex_unlock(&uuid_mutex);
up_write(&sb->s_umount);

View File

@ -50,7 +50,7 @@ struct btrfs_device {
struct block_device *bdev;
/* the mode sent to open_bdev_exclusive */
/* the mode sent to blkdev_get */
fmode_t mode;
char *name;

View File

@ -59,7 +59,7 @@ static struct char_device_struct {
} *chrdevs[CHRDEV_MAJOR_HASH_SIZE];
/* index in the above */
static inline int major_to_index(int major)
static inline int major_to_index(unsigned major)
{
return major % CHRDEV_MAJOR_HASH_SIZE;
}

View File

@ -364,7 +364,7 @@ static struct block_device *ext3_blkdev_get(dev_t dev, struct super_block *sb)
struct block_device *bdev;
char b[BDEVNAME_SIZE];
bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE);
bdev = blkdev_get_by_dev(dev, FMODE_READ|FMODE_WRITE|FMODE_EXCL, sb);
if (IS_ERR(bdev))
goto fail;
return bdev;
@ -381,8 +381,7 @@ fail:
*/
static int ext3_blkdev_put(struct block_device *bdev)
{
bd_release(bdev);
return blkdev_put(bdev, FMODE_READ|FMODE_WRITE);
return blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
}
static int ext3_blkdev_remove(struct ext3_sb_info *sbi)
@ -2162,13 +2161,6 @@ static journal_t *ext3_get_dev_journal(struct super_block *sb,
if (bdev == NULL)
return NULL;
if (bd_claim(bdev, sb)) {
ext3_msg(sb, KERN_ERR,
"error: failed to claim external journal device");
blkdev_put(bdev, FMODE_READ|FMODE_WRITE);
return NULL;
}
blocksize = sb->s_blocksize;
hblock = bdev_logical_block_size(bdev);
if (blocksize < hblock) {

View File

@ -657,7 +657,7 @@ static struct block_device *ext4_blkdev_get(dev_t dev, struct super_block *sb)
struct block_device *bdev;
char b[BDEVNAME_SIZE];
bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE);
bdev = blkdev_get_by_dev(dev, FMODE_READ|FMODE_WRITE|FMODE_EXCL, sb);
if (IS_ERR(bdev))
goto fail;
return bdev;
@ -673,8 +673,7 @@ fail:
*/
static int ext4_blkdev_put(struct block_device *bdev)
{
bd_release(bdev);
return blkdev_put(bdev, FMODE_READ|FMODE_WRITE);
return blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
}
static int ext4_blkdev_remove(struct ext4_sb_info *sbi)
@ -3778,13 +3777,6 @@ static journal_t *ext4_get_dev_journal(struct super_block *sb,
if (bdev == NULL)
return NULL;
if (bd_claim(bdev, sb)) {
ext4_msg(sb, KERN_ERR,
"failed to claim external journal device");
blkdev_put(bdev, FMODE_READ|FMODE_WRITE);
return NULL;
}
blocksize = sb->s_blocksize;
hblock = bdev_logical_block_size(bdev);
if (blocksize < hblock) {

View File

@ -1268,7 +1268,7 @@ static struct dentry *gfs2_mount(struct file_system_type *fs_type, int flags,
{
struct block_device *bdev;
struct super_block *s;
fmode_t mode = FMODE_READ;
fmode_t mode = FMODE_READ | FMODE_EXCL;
int error;
struct gfs2_args args;
struct gfs2_sbd *sdp;
@ -1276,7 +1276,7 @@ static struct dentry *gfs2_mount(struct file_system_type *fs_type, int flags,
if (!(flags & MS_RDONLY))
mode |= FMODE_WRITE;
bdev = open_bdev_exclusive(dev_name, mode, fs_type);
bdev = blkdev_get_by_path(dev_name, mode, fs_type);
if (IS_ERR(bdev))
return ERR_CAST(bdev);
@ -1298,7 +1298,7 @@ static struct dentry *gfs2_mount(struct file_system_type *fs_type, int flags,
goto error_bdev;
if (s->s_root)
close_bdev_exclusive(bdev, mode);
blkdev_put(bdev, mode);
memset(&args, 0, sizeof(args));
args.ar_quota = GFS2_QUOTA_DEFAULT;
@ -1342,7 +1342,7 @@ error_super:
deactivate_locked_super(s);
return ERR_PTR(error);
error_bdev:
close_bdev_exclusive(bdev, mode);
blkdev_put(bdev, mode);
return ERR_PTR(error);
}

View File

@ -1120,16 +1120,13 @@ int lmLogOpen(struct super_block *sb)
* file systems to log may have n-to-1 relationship;
*/
bdev = open_by_devnum(sbi->logdev, FMODE_READ|FMODE_WRITE);
bdev = blkdev_get_by_dev(sbi->logdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL,
log);
if (IS_ERR(bdev)) {
rc = -PTR_ERR(bdev);
goto free;
}
if ((rc = bd_claim(bdev, log))) {
goto close;
}
log->bdev = bdev;
memcpy(log->uuid, sbi->loguuid, sizeof(log->uuid));
@ -1137,7 +1134,7 @@ int lmLogOpen(struct super_block *sb)
* initialize log:
*/
if ((rc = lmLogInit(log)))
goto unclaim;
goto close;
list_add(&log->journal_list, &jfs_external_logs);
@ -1163,11 +1160,8 @@ journal_found:
list_del(&log->journal_list);
lbmLogShutdown(log);
unclaim:
bd_release(bdev);
close: /* close external log device */
blkdev_put(bdev, FMODE_READ|FMODE_WRITE);
blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
free: /* free log descriptor */
mutex_unlock(&jfs_log_mutex);
@ -1512,8 +1506,7 @@ int lmLogClose(struct super_block *sb)
bdev = log->bdev;
rc = lmLogShutdown(log);
bd_release(bdev);
blkdev_put(bdev, FMODE_READ|FMODE_WRITE);
blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
kfree(log);

View File

@ -300,7 +300,7 @@ static int bdev_write_sb(struct super_block *sb, struct page *page)
static void bdev_put_device(struct logfs_super *s)
{
close_bdev_exclusive(s->s_bdev, FMODE_READ|FMODE_WRITE);
blkdev_put(s->s_bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
}
static int bdev_can_write_buf(struct super_block *sb, u64 ofs)
@ -325,13 +325,14 @@ int logfs_get_sb_bdev(struct logfs_super *p, struct file_system_type *type,
{
struct block_device *bdev;
bdev = open_bdev_exclusive(devname, FMODE_READ|FMODE_WRITE, type);
bdev = blkdev_get_by_path(devname, FMODE_READ|FMODE_WRITE|FMODE_EXCL,
type);
if (IS_ERR(bdev))
return PTR_ERR(bdev);
if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
int mtdnr = MINOR(bdev->bd_dev);
close_bdev_exclusive(bdev, FMODE_READ|FMODE_WRITE);
blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
return logfs_get_sb_mtd(p, mtdnr);
}

View File

@ -845,11 +845,6 @@ nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
struct page **pp = rqstp->rq_respages + rqstp->rq_resused;
struct page *page = buf->page;
size_t size;
int ret;
ret = buf->ops->confirm(pipe, buf);
if (unlikely(ret))
return ret;
size = sd->len;

View File

@ -1163,14 +1163,14 @@ nilfs_mount(struct file_system_type *fs_type, int flags,
{
struct nilfs_super_data sd;
struct super_block *s;
fmode_t mode = FMODE_READ;
fmode_t mode = FMODE_READ | FMODE_EXCL;
struct dentry *root_dentry;
int err, s_new = false;
if (!(flags & MS_RDONLY))
mode |= FMODE_WRITE;
sd.bdev = open_bdev_exclusive(dev_name, mode, fs_type);
sd.bdev = blkdev_get_by_path(dev_name, mode, fs_type);
if (IS_ERR(sd.bdev))
return ERR_CAST(sd.bdev);
@ -1249,7 +1249,7 @@ nilfs_mount(struct file_system_type *fs_type, int flags,
}
if (!s_new)
close_bdev_exclusive(sd.bdev, mode);
blkdev_put(sd.bdev, mode);
return root_dentry;
@ -1258,7 +1258,7 @@ nilfs_mount(struct file_system_type *fs_type, int flags,
failed:
if (!s_new)
close_bdev_exclusive(sd.bdev, mode);
blkdev_put(sd.bdev, mode);
return ERR_PTR(err);
}

View File

@ -1729,7 +1729,7 @@ static ssize_t o2hb_region_dev_write(struct o2hb_region *reg,
goto out;
reg->hr_bdev = I_BDEV(filp->f_mapping->host);
ret = blkdev_get(reg->hr_bdev, FMODE_WRITE | FMODE_READ);
ret = blkdev_get(reg->hr_bdev, FMODE_WRITE | FMODE_READ, NULL);
if (ret) {
reg->hr_bdev = NULL;
goto out;

View File

@ -237,6 +237,13 @@ ssize_t part_size_show(struct device *dev,
return sprintf(buf, "%llu\n",(unsigned long long)p->nr_sects);
}
ssize_t part_ro_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct hd_struct *p = dev_to_part(dev);
return sprintf(buf, "%d\n", p->policy ? 1 : 0);
}
ssize_t part_alignment_offset_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@ -312,6 +319,7 @@ ssize_t part_fail_store(struct device *dev,
static DEVICE_ATTR(partition, S_IRUGO, part_partition_show, NULL);
static DEVICE_ATTR(start, S_IRUGO, part_start_show, NULL);
static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL);
static DEVICE_ATTR(ro, S_IRUGO, part_ro_show, NULL);
static DEVICE_ATTR(alignment_offset, S_IRUGO, part_alignment_offset_show, NULL);
static DEVICE_ATTR(discard_alignment, S_IRUGO, part_discard_alignment_show,
NULL);
@ -326,6 +334,7 @@ static struct attribute *part_attrs[] = {
&dev_attr_partition.attr,
&dev_attr_start.attr,
&dev_attr_size.attr,
&dev_attr_ro.attr,
&dev_attr_alignment_offset.attr,
&dev_attr_discard_alignment.attr,
&dev_attr_stat.attr,
@ -372,6 +381,11 @@ static void delete_partition_rcu_cb(struct rcu_head *head)
put_device(part_to_dev(part));
}
void __delete_partition(struct hd_struct *part)
{
call_rcu(&part->rcu_head, delete_partition_rcu_cb);
}
void delete_partition(struct gendisk *disk, int partno)
{
struct disk_part_tbl *ptbl = disk->part_tbl;
@ -390,7 +404,7 @@ void delete_partition(struct gendisk *disk, int partno)
kobject_put(part->holder_dir);
device_del(part_to_dev(part));
call_rcu(&part->rcu_head, delete_partition_rcu_cb);
hd_struct_put(part);
}
static ssize_t whole_disk_show(struct device *dev,
@ -489,6 +503,7 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno,
if (!dev_get_uevent_suppress(ddev))
kobject_uevent(&pdev->kobj, KOBJ_ADD);
hd_ref_init(p);
return p;
out_free_info:
@ -507,65 +522,6 @@ out_put:
return ERR_PTR(err);
}
/* Not exported, helper to add_disk(). */
void register_disk(struct gendisk *disk)
{
struct device *ddev = disk_to_dev(disk);
struct block_device *bdev;
struct disk_part_iter piter;
struct hd_struct *part;
int err;
ddev->parent = disk->driverfs_dev;
dev_set_name(ddev, disk->disk_name);
/* delay uevents, until we scanned partition table */
dev_set_uevent_suppress(ddev, 1);
if (device_add(ddev))
return;
if (!sysfs_deprecated) {
err = sysfs_create_link(block_depr, &ddev->kobj,
kobject_name(&ddev->kobj));
if (err) {
device_del(ddev);
return;
}
}
disk->part0.holder_dir = kobject_create_and_add("holders", &ddev->kobj);
disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj);
/* No minors to use for partitions */
if (!disk_partitionable(disk))
goto exit;
/* No such device (e.g., media were just removed) */
if (!get_capacity(disk))
goto exit;
bdev = bdget_disk(disk, 0);
if (!bdev)
goto exit;
bdev->bd_invalidated = 1;
err = blkdev_get(bdev, FMODE_READ);
if (err < 0)
goto exit;
blkdev_put(bdev, FMODE_READ);
exit:
/* announce disk after possible partitions are created */
dev_set_uevent_suppress(ddev, 0);
kobject_uevent(&ddev->kobj, KOBJ_ADD);
/* announce possible partitions */
disk_part_iter_init(&piter, disk, 0);
while ((part = disk_part_iter_next(&piter)))
kobject_uevent(&part_to_dev(part)->kobj, KOBJ_ADD);
disk_part_iter_exit(&piter);
}
static bool disk_unlock_native_capacity(struct gendisk *disk)
{
const struct block_device_operations *bdops = disk->fops;
@ -728,33 +684,3 @@ fail:
}
EXPORT_SYMBOL(read_dev_sector);
void del_gendisk(struct gendisk *disk)
{
struct disk_part_iter piter;
struct hd_struct *part;
/* invalidate stuff */
disk_part_iter_init(&piter, disk,
DISK_PITER_INCL_EMPTY | DISK_PITER_REVERSE);
while ((part = disk_part_iter_next(&piter))) {
invalidate_partition(disk, part->partno);
delete_partition(disk, part->partno);
}
disk_part_iter_exit(&piter);
invalidate_partition(disk, 0);
blk_free_devt(disk_to_dev(disk)->devt);
set_capacity(disk, 0);
disk->flags &= ~GENHD_FL_UP;
unlink_gendisk(disk);
part_stat_set_all(&disk->part0, 0);
disk->part0.stamp = 0;
kobject_put(disk->part0.holder_dir);
kobject_put(disk->slave_dir);
disk->driverfs_dev = NULL;
if (!sysfs_deprecated)
sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk)));
device_del(disk_to_dev(disk));
}

View File

@ -2551,8 +2551,6 @@ static int release_journal_dev(struct super_block *super,
result = 0;
if (journal->j_dev_bd != NULL) {
if (journal->j_dev_bd->bd_dev != super->s_dev)
bd_release(journal->j_dev_bd);
result = blkdev_put(journal->j_dev_bd, journal->j_dev_mode);
journal->j_dev_bd = NULL;
}
@ -2570,7 +2568,7 @@ static int journal_init_dev(struct super_block *super,
{
int result;
dev_t jdev;
fmode_t blkdev_mode = FMODE_READ | FMODE_WRITE;
fmode_t blkdev_mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL;
char b[BDEVNAME_SIZE];
result = 0;
@ -2584,7 +2582,10 @@ static int journal_init_dev(struct super_block *super,
/* there is no "jdev" option and journal is on separate device */
if ((!jdev_name || !jdev_name[0])) {
journal->j_dev_bd = open_by_devnum(jdev, blkdev_mode);
if (jdev == super->s_dev)
blkdev_mode &= ~FMODE_EXCL;
journal->j_dev_bd = blkdev_get_by_dev(jdev, blkdev_mode,
journal);
journal->j_dev_mode = blkdev_mode;
if (IS_ERR(journal->j_dev_bd)) {
result = PTR_ERR(journal->j_dev_bd);
@ -2593,22 +2594,14 @@ static int journal_init_dev(struct super_block *super,
"cannot init journal device '%s': %i",
__bdevname(jdev, b), result);
return result;
} else if (jdev != super->s_dev) {
result = bd_claim(journal->j_dev_bd, journal);
if (result) {
blkdev_put(journal->j_dev_bd, blkdev_mode);
return result;
}
} else if (jdev != super->s_dev)
set_blocksize(journal->j_dev_bd, super->s_blocksize);
}
return 0;
}
journal->j_dev_mode = blkdev_mode;
journal->j_dev_bd = open_bdev_exclusive(jdev_name,
blkdev_mode, journal);
journal->j_dev_bd = blkdev_get_by_path(jdev_name, blkdev_mode, journal);
if (IS_ERR(journal->j_dev_bd)) {
result = PTR_ERR(journal->j_dev_bd);
journal->j_dev_bd = NULL;

View File

@ -682,19 +682,14 @@ static int pipe_to_sendpage(struct pipe_inode_info *pipe,
{
struct file *file = sd->u.file;
loff_t pos = sd->pos;
int ret, more;
int more;
ret = buf->ops->confirm(pipe, buf);
if (!ret) {
more = (sd->flags & SPLICE_F_MORE) || sd->len < sd->total_len;
if (file->f_op && file->f_op->sendpage)
ret = file->f_op->sendpage(file, buf->page, buf->offset,
sd->len, &pos, more);
else
ret = -EINVAL;
}
if (!likely(file->f_op && file->f_op->sendpage))
return -EINVAL;
return ret;
more = (sd->flags & SPLICE_F_MORE) || sd->len < sd->total_len;
return file->f_op->sendpage(file, buf->page, buf->offset,
sd->len, &pos, more);
}
/*
@ -727,13 +722,6 @@ int pipe_to_file(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
void *fsdata;
int ret;
/*
* make sure the data in this buffer is uptodate
*/
ret = buf->ops->confirm(pipe, buf);
if (unlikely(ret))
return ret;
offset = sd->pos & ~PAGE_CACHE_MASK;
this_len = sd->len;
@ -805,12 +793,17 @@ int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_desc *sd,
if (sd->len > sd->total_len)
sd->len = sd->total_len;
ret = actor(pipe, buf, sd);
if (ret <= 0) {
ret = buf->ops->confirm(pipe, buf);
if (unlikely(ret)) {
if (ret == -ENODATA)
ret = 0;
return ret;
}
ret = actor(pipe, buf, sd);
if (ret <= 0)
return ret;
buf->offset += ret;
buf->len -= ret;
@ -1044,10 +1037,6 @@ static int write_pipe_buf(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
int ret;
void *data;
ret = buf->ops->confirm(pipe, buf);
if (ret)
return ret;
data = buf->ops->map(pipe, buf, 0);
ret = kernel_write(sd->u.file, data + buf->offset, sd->len, sd->pos);
buf->ops->unmap(pipe, buf, data);
@ -1495,10 +1484,6 @@ static int pipe_to_user(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
char *src;
int ret;
ret = buf->ops->confirm(pipe, buf);
if (unlikely(ret))
return ret;
/*
* See if we can use the atomic maps, by prefaulting in the
* pages and doing an atomic copy

View File

@ -767,13 +767,13 @@ struct dentry *mount_bdev(struct file_system_type *fs_type,
{
struct block_device *bdev;
struct super_block *s;
fmode_t mode = FMODE_READ;
fmode_t mode = FMODE_READ | FMODE_EXCL;
int error = 0;
if (!(flags & MS_RDONLY))
mode |= FMODE_WRITE;
bdev = open_bdev_exclusive(dev_name, mode, fs_type);
bdev = blkdev_get_by_path(dev_name, mode, fs_type);
if (IS_ERR(bdev))
return ERR_CAST(bdev);
@ -802,13 +802,13 @@ struct dentry *mount_bdev(struct file_system_type *fs_type,
/*
* s_umount nests inside bd_mutex during
* __invalidate_device(). close_bdev_exclusive()
* acquires bd_mutex and can't be called under
* s_umount. Drop s_umount temporarily. This is safe
* as we're holding an active reference.
* __invalidate_device(). blkdev_put() acquires
* bd_mutex and can't be called under s_umount. Drop
* s_umount temporarily. This is safe as we're
* holding an active reference.
*/
up_write(&s->s_umount);
close_bdev_exclusive(bdev, mode);
blkdev_put(bdev, mode);
down_write(&s->s_umount);
} else {
char b[BDEVNAME_SIZE];
@ -832,7 +832,7 @@ struct dentry *mount_bdev(struct file_system_type *fs_type,
error_s:
error = PTR_ERR(s);
error_bdev:
close_bdev_exclusive(bdev, mode);
blkdev_put(bdev, mode);
error:
return ERR_PTR(error);
}
@ -863,7 +863,8 @@ void kill_block_super(struct super_block *sb)
bdev->bd_super = NULL;
generic_shutdown_super(sb);
sync_blockdev(bdev);
close_bdev_exclusive(bdev, mode);
WARN_ON_ONCE(!(mode & FMODE_EXCL));
blkdev_put(bdev, mode | FMODE_EXCL);
}
EXPORT_SYMBOL(kill_block_super);

View File

@ -606,7 +606,8 @@ xfs_blkdev_get(
{
int error = 0;
*bdevp = open_bdev_exclusive(name, FMODE_READ|FMODE_WRITE, mp);
*bdevp = blkdev_get_by_path(name, FMODE_READ|FMODE_WRITE|FMODE_EXCL,
mp);
if (IS_ERR(*bdevp)) {
error = PTR_ERR(*bdevp);
printk("XFS: Invalid device [%s], error=%d\n", name, error);
@ -620,7 +621,7 @@ xfs_blkdev_put(
struct block_device *bdev)
{
if (bdev)
close_bdev_exclusive(bdev, FMODE_READ|FMODE_WRITE);
blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
}
/*

View File

@ -115,6 +115,7 @@ struct request {
void *elevator_private3;
struct gendisk *rq_disk;
struct hd_struct *part;
unsigned long start_time;
#ifdef CONFIG_BLK_CGROUP
unsigned long long start_time_ns;
@ -646,7 +647,6 @@ static inline void rq_flush_dcache_pages(struct request *rq)
extern int blk_register_queue(struct gendisk *disk);
extern void blk_unregister_queue(struct gendisk *disk);
extern void register_disk(struct gendisk *dev);
extern void generic_make_request(struct bio *bio);
extern void blk_rq_init(struct request_queue *q, struct request *rq);
extern void blk_put_request(struct request *);
@ -1256,6 +1256,9 @@ struct block_device_operations {
int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
int (*direct_access) (struct block_device *, sector_t,
void **, unsigned long *);
unsigned int (*check_events) (struct gendisk *disk,
unsigned int clearing);
/* ->media_changed() is DEPRECATED, use ->check_events() instead */
int (*media_changed) (struct gendisk *);
void (*unlock_native_capacity) (struct gendisk *);
int (*revalidate_disk) (struct gendisk *);

View File

@ -946,6 +946,8 @@ struct cdrom_device_info {
/* device-related storage */
unsigned int options : 30; /* options flags */
unsigned mc_flags : 2; /* media change buffer flags */
unsigned int vfs_events; /* cached events for vfs path */
unsigned int ioctl_events; /* cached events for ioctl path */
int use_count; /* number of times device opened */
char name[20]; /* name of the device type */
/* per-device flags */
@ -965,6 +967,8 @@ struct cdrom_device_ops {
int (*open) (struct cdrom_device_info *, int);
void (*release) (struct cdrom_device_info *);
int (*drive_status) (struct cdrom_device_info *, int);
unsigned int (*check_events) (struct cdrom_device_info *cdi,
unsigned int clearing, int slot);
int (*media_changed) (struct cdrom_device_info *, int);
int (*tray_move) (struct cdrom_device_info *, int);
int (*lock_door) (struct cdrom_device_info *, int);
@ -993,6 +997,8 @@ extern int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev,
extern void cdrom_release(struct cdrom_device_info *cdi, fmode_t mode);
extern int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev,
fmode_t mode, unsigned int cmd, unsigned long arg);
extern unsigned int cdrom_check_events(struct cdrom_device_info *cdi,
unsigned int clearing);
extern int cdrom_media_changed(struct cdrom_device_info *);
extern int register_cdrom(struct cdrom_device_info *cdi);

View File

@ -664,8 +664,9 @@ struct block_device {
void * bd_claiming;
void * bd_holder;
int bd_holders;
bool bd_write_holder;
#ifdef CONFIG_SYSFS
struct list_head bd_holder_list;
struct gendisk * bd_holder_disk; /* for sysfs slave linkng */
#endif
struct block_device * bd_contains;
unsigned bd_block_size;
@ -2019,7 +2020,6 @@ extern struct block_device *bdgrab(struct block_device *bdev);
extern void bd_set_size(struct block_device *, loff_t size);
extern void bd_forget(struct inode *inode);
extern void bdput(struct block_device *);
extern struct block_device *open_by_devnum(dev_t, fmode_t);
extern void invalidate_bdev(struct block_device *);
extern int sync_blockdev(struct block_device *bdev);
extern struct super_block *freeze_bdev(struct block_device *);
@ -2050,16 +2050,20 @@ extern const struct file_operations def_fifo_fops;
extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long);
extern int blkdev_ioctl(struct block_device *, fmode_t, unsigned, unsigned long);
extern long compat_blkdev_ioctl(struct file *, unsigned, unsigned long);
extern int blkdev_get(struct block_device *, fmode_t);
extern int blkdev_put(struct block_device *, fmode_t);
extern int bd_claim(struct block_device *, void *);
extern void bd_release(struct block_device *);
extern int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder);
extern struct block_device *blkdev_get_by_path(const char *path, fmode_t mode,
void *holder);
extern struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode,
void *holder);
extern int blkdev_put(struct block_device *bdev, fmode_t mode);
#ifdef CONFIG_SYSFS
extern int bd_claim_by_disk(struct block_device *, void *, struct gendisk *);
extern void bd_release_from_disk(struct block_device *, struct gendisk *);
extern int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk);
#else
#define bd_claim_by_disk(bdev, holder, disk) bd_claim(bdev, holder)
#define bd_release_from_disk(bdev, disk) bd_release(bdev)
static inline int bd_link_disk_holder(struct block_device *bdev,
struct gendisk *disk)
{
return 0;
}
#endif
#endif
@ -2095,8 +2099,6 @@ static inline void unregister_chrdev(unsigned int major, const char *name)
extern const char *__bdevname(dev_t, char *buffer);
extern const char *bdevname(struct block_device *bdev, char *buffer);
extern struct block_device *lookup_bdev(const char *);
extern struct block_device *open_bdev_exclusive(const char *, fmode_t, void *);
extern void close_bdev_exclusive(struct block_device *, fmode_t);
extern void blkdev_show(struct seq_file *,off_t);
#else

View File

@ -115,6 +115,7 @@ struct hd_struct {
#else
struct disk_stats dkstats;
#endif
atomic_t ref;
struct rcu_head rcu_head;
};
@ -127,6 +128,11 @@ struct hd_struct {
#define GENHD_FL_EXT_DEVT 64 /* allow extended devt */
#define GENHD_FL_NATIVE_CAPACITY 128
enum {
DISK_EVENT_MEDIA_CHANGE = 1 << 0, /* media changed */
DISK_EVENT_EJECT_REQUEST = 1 << 1, /* eject requested */
};
#define BLK_SCSI_MAX_CMDS (256)
#define BLK_SCSI_CMD_PER_LONG (BLK_SCSI_MAX_CMDS / (sizeof(long) * 8))
@ -143,6 +149,8 @@ struct disk_part_tbl {
struct hd_struct __rcu *part[];
};
struct disk_events;
struct gendisk {
/* major, first_minor and minors are input parameters only,
* don't use directly. Use disk_devt() and disk_max_parts().
@ -154,6 +162,10 @@ struct gendisk {
char disk_name[DISK_NAME_LEN]; /* name of major driver */
char *(*devnode)(struct gendisk *gd, mode_t *mode);
unsigned int events; /* supported events */
unsigned int async_events; /* async events, subset of all */
/* Array of pointers to partitions indexed by partno.
* Protected with matching bdev lock but stat and other
* non-critical accesses use RCU. Always access through
@ -171,9 +183,8 @@ struct gendisk {
struct kobject *slave_dir;
struct timer_rand_state *random;
atomic_t sync_io; /* RAID */
struct work_struct async_notify;
struct disk_events *ev;
#ifdef CONFIG_BLK_DEV_INTEGRITY
struct blk_integrity *integrity;
#endif
@ -395,7 +406,6 @@ extern void part_round_stats(int cpu, struct hd_struct *part);
/* block/genhd.c */
extern void add_disk(struct gendisk *disk);
extern void del_gendisk(struct gendisk *gp);
extern void unlink_gendisk(struct gendisk *gp);
extern struct gendisk *get_gendisk(dev_t dev, int *partno);
extern struct block_device *bdget_disk(struct gendisk *disk, int partno);
@ -407,6 +417,11 @@ static inline int get_disk_ro(struct gendisk *disk)
return disk->part0.policy;
}
extern void disk_block_events(struct gendisk *disk);
extern void disk_unblock_events(struct gendisk *disk);
extern void disk_check_events(struct gendisk *disk);
extern unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask);
/* drivers/char/random.c */
extern void add_disk_randomness(struct gendisk *disk);
extern void rand_initialize_disk(struct gendisk *disk);
@ -583,6 +598,7 @@ extern struct hd_struct * __must_check add_partition(struct gendisk *disk,
sector_t len, int flags,
struct partition_meta_info
*info);
extern void __delete_partition(struct hd_struct *);
extern void delete_partition(struct gendisk *, int);
extern void printk_all_partitions(void);
@ -611,6 +627,29 @@ extern ssize_t part_fail_store(struct device *dev,
const char *buf, size_t count);
#endif /* CONFIG_FAIL_MAKE_REQUEST */
static inline void hd_ref_init(struct hd_struct *part)
{
atomic_set(&part->ref, 1);
smp_mb();
}
static inline void hd_struct_get(struct hd_struct *part)
{
atomic_inc(&part->ref);
smp_mb__after_atomic_inc();
}
static inline int hd_struct_try_get(struct hd_struct *part)
{
return atomic_inc_not_zero(&part->ref);
}
static inline void hd_struct_put(struct hd_struct *part)
{
if (atomic_dec_and_test(&part->ref))
__delete_partition(part);
}
#else /* CONFIG_BLOCK */
static inline void printk_all_partitions(void) { }

View File

@ -104,6 +104,7 @@ struct scsi_cmnd;
#define UNMAP 0x42
#define READ_TOC 0x43
#define READ_HEADER 0x44
#define GET_EVENT_STATUS_NOTIFICATION 0x4a
#define LOG_SELECT 0x4c
#define LOG_SENSE 0x4d
#define XDWRITEREAD_10 0x53

View File

@ -206,15 +206,16 @@ TRACE_EVENT(block_bio_bounce,
* block_bio_complete - completed all work on the block operation
* @q: queue holding the block operation
* @bio: block operation completed
* @error: io error value
*
* This tracepoint indicates there is no further work to do on this
* block IO operation @bio.
*/
TRACE_EVENT(block_bio_complete,
TP_PROTO(struct request_queue *q, struct bio *bio),
TP_PROTO(struct request_queue *q, struct bio *bio, int error),
TP_ARGS(q, bio),
TP_ARGS(q, bio, error),
TP_STRUCT__entry(
__field( dev_t, dev )
@ -228,6 +229,7 @@ TRACE_EVENT(block_bio_complete,
__entry->dev = bio->bi_bdev->bd_dev;
__entry->sector = bio->bi_sector;
__entry->nr_sector = bio->bi_size >> 9;
__entry->error = error;
blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size);
),
@ -486,16 +488,16 @@ TRACE_EVENT(block_split,
);
/**
* block_remap - map request for a partition to the raw device
* block_bio_remap - map request for a logical device to the raw device
* @q: queue holding the operation
* @bio: revised operation
* @dev: device for the operation
* @from: original sector for the operation
*
* An operation for a partition on a block device has been mapped to the
* An operation for a logical device has been mapped to the
* raw block device.
*/
TRACE_EVENT(block_remap,
TRACE_EVENT(block_bio_remap,
TP_PROTO(struct request_queue *q, struct bio *bio, dev_t dev,
sector_t from),

View File

@ -224,7 +224,7 @@ static int swsusp_swap_check(void)
return res;
root_swap = res;
res = blkdev_get(hib_resume_bdev, FMODE_WRITE);
res = blkdev_get(hib_resume_bdev, FMODE_WRITE, NULL);
if (res)
return res;
@ -930,7 +930,8 @@ int swsusp_check(void)
{
int error;
hib_resume_bdev = open_by_devnum(swsusp_resume_device, FMODE_READ);
hib_resume_bdev = blkdev_get_by_dev(swsusp_resume_device,
FMODE_READ, NULL);
if (!IS_ERR(hib_resume_bdev)) {
set_blocksize(hib_resume_bdev, PAGE_SIZE);
clear_page(swsusp_header);

View File

@ -758,53 +758,58 @@ static void blk_add_trace_rq_complete(void *ignore,
* @q: queue the io is for
* @bio: the source bio
* @what: the action
* @error: error, if any
*
* Description:
* Records an action against a bio. Will log the bio offset + size.
*
**/
static void blk_add_trace_bio(struct request_queue *q, struct bio *bio,
u32 what)
u32 what, int error)
{
struct blk_trace *bt = q->blk_trace;
if (likely(!bt))
return;
if (!error && !bio_flagged(bio, BIO_UPTODATE))
error = EIO;
__blk_add_trace(bt, bio->bi_sector, bio->bi_size, bio->bi_rw, what,
!bio_flagged(bio, BIO_UPTODATE), 0, NULL);
error, 0, NULL);
}
static void blk_add_trace_bio_bounce(void *ignore,
struct request_queue *q, struct bio *bio)
{
blk_add_trace_bio(q, bio, BLK_TA_BOUNCE);
blk_add_trace_bio(q, bio, BLK_TA_BOUNCE, 0);
}
static void blk_add_trace_bio_complete(void *ignore,
struct request_queue *q, struct bio *bio)
struct request_queue *q, struct bio *bio,
int error)
{
blk_add_trace_bio(q, bio, BLK_TA_COMPLETE);
blk_add_trace_bio(q, bio, BLK_TA_COMPLETE, error);
}
static void blk_add_trace_bio_backmerge(void *ignore,
struct request_queue *q,
struct bio *bio)
{
blk_add_trace_bio(q, bio, BLK_TA_BACKMERGE);
blk_add_trace_bio(q, bio, BLK_TA_BACKMERGE, 0);
}
static void blk_add_trace_bio_frontmerge(void *ignore,
struct request_queue *q,
struct bio *bio)
{
blk_add_trace_bio(q, bio, BLK_TA_FRONTMERGE);
blk_add_trace_bio(q, bio, BLK_TA_FRONTMERGE, 0);
}
static void blk_add_trace_bio_queue(void *ignore,
struct request_queue *q, struct bio *bio)
{
blk_add_trace_bio(q, bio, BLK_TA_QUEUE);
blk_add_trace_bio(q, bio, BLK_TA_QUEUE, 0);
}
static void blk_add_trace_getrq(void *ignore,
@ -812,7 +817,7 @@ static void blk_add_trace_getrq(void *ignore,
struct bio *bio, int rw)
{
if (bio)
blk_add_trace_bio(q, bio, BLK_TA_GETRQ);
blk_add_trace_bio(q, bio, BLK_TA_GETRQ, 0);
else {
struct blk_trace *bt = q->blk_trace;
@ -827,7 +832,7 @@ static void blk_add_trace_sleeprq(void *ignore,
struct bio *bio, int rw)
{
if (bio)
blk_add_trace_bio(q, bio, BLK_TA_SLEEPRQ);
blk_add_trace_bio(q, bio, BLK_TA_SLEEPRQ, 0);
else {
struct blk_trace *bt = q->blk_trace;
@ -887,7 +892,7 @@ static void blk_add_trace_split(void *ignore,
}
/**
* blk_add_trace_remap - Add a trace for a remap operation
* blk_add_trace_bio_remap - Add a trace for a bio-remap operation
* @ignore: trace callback data parameter (not used)
* @q: queue the io is for
* @bio: the source bio
@ -899,9 +904,9 @@ static void blk_add_trace_split(void *ignore,
* it spans a stripe (or similar). Add a trace for that action.
*
**/
static void blk_add_trace_remap(void *ignore,
struct request_queue *q, struct bio *bio,
dev_t dev, sector_t from)
static void blk_add_trace_bio_remap(void *ignore,
struct request_queue *q, struct bio *bio,
dev_t dev, sector_t from)
{
struct blk_trace *bt = q->blk_trace;
struct blk_io_trace_remap r;
@ -1016,7 +1021,7 @@ static void blk_register_tracepoints(void)
WARN_ON(ret);
ret = register_trace_block_split(blk_add_trace_split, NULL);
WARN_ON(ret);
ret = register_trace_block_remap(blk_add_trace_remap, NULL);
ret = register_trace_block_bio_remap(blk_add_trace_bio_remap, NULL);
WARN_ON(ret);
ret = register_trace_block_rq_remap(blk_add_trace_rq_remap, NULL);
WARN_ON(ret);
@ -1025,7 +1030,7 @@ static void blk_register_tracepoints(void)
static void blk_unregister_tracepoints(void)
{
unregister_trace_block_rq_remap(blk_add_trace_rq_remap, NULL);
unregister_trace_block_remap(blk_add_trace_remap, NULL);
unregister_trace_block_bio_remap(blk_add_trace_bio_remap, NULL);
unregister_trace_block_split(blk_add_trace_split, NULL);
unregister_trace_block_unplug_io(blk_add_trace_unplug_io, NULL);
unregister_trace_block_unplug_timer(blk_add_trace_unplug_timer, NULL);

View File

@ -1677,7 +1677,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
if (S_ISBLK(inode->i_mode)) {
struct block_device *bdev = I_BDEV(inode);
set_blocksize(bdev, p->old_block_size);
bd_release(bdev);
blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL);
} else {
mutex_lock(&inode->i_mutex);
inode->i_flags &= ~S_SWAPFILE;
@ -1939,7 +1939,8 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
error = -EINVAL;
if (S_ISBLK(inode->i_mode)) {
bdev = I_BDEV(inode);
error = bd_claim(bdev, sys_swapon);
error = blkdev_get(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL,
sys_swapon);
if (error < 0) {
bdev = NULL;
error = -EINVAL;
@ -2136,7 +2137,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
bad_swap:
if (bdev) {
set_blocksize(bdev, p->old_block_size);
bd_release(bdev);
blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL);
}
destroy_swap_extents(p);
swap_cgroup_swapoff(type);