diff options
Diffstat (limited to 'block')
-rw-r--r-- | block/Makefile | 2 | ||||
-rw-r--r-- | block/blk-core.c | 14 | ||||
-rw-r--r-- | block/bsg.c | 5 | ||||
-rw-r--r-- | block/cfq-iosched.c | 176 | ||||
-rw-r--r-- | block/cmd-filter.c | 233 | ||||
-rw-r--r-- | block/scsi_ioctl.c | 43 |
6 files changed, 139 insertions, 334 deletions
diff --git a/block/Makefile b/block/Makefile index e9fa4dd690f2..6c54ed0ff755 100644 --- a/block/Makefile +++ b/block/Makefile | |||
@@ -5,7 +5,7 @@ | |||
5 | obj-$(CONFIG_BLOCK) := elevator.o blk-core.o blk-tag.o blk-sysfs.o \ | 5 | obj-$(CONFIG_BLOCK) := elevator.o blk-core.o blk-tag.o blk-sysfs.o \ |
6 | blk-barrier.o blk-settings.o blk-ioc.o blk-map.o \ | 6 | blk-barrier.o blk-settings.o blk-ioc.o blk-map.o \ |
7 | blk-exec.o blk-merge.o blk-softirq.o blk-timeout.o \ | 7 | blk-exec.o blk-merge.o blk-softirq.o blk-timeout.o \ |
8 | ioctl.o genhd.o scsi_ioctl.o cmd-filter.o | 8 | ioctl.o genhd.o scsi_ioctl.o |
9 | 9 | ||
10 | obj-$(CONFIG_BLK_DEV_BSG) += bsg.o | 10 | obj-$(CONFIG_BLK_DEV_BSG) += bsg.o |
11 | obj-$(CONFIG_IOSCHED_NOOP) += noop-iosched.o | 11 | obj-$(CONFIG_IOSCHED_NOOP) += noop-iosched.o |
diff --git a/block/blk-core.c b/block/blk-core.c index b06cf5c2a829..4b45435c6eaf 100644 --- a/block/blk-core.c +++ b/block/blk-core.c | |||
@@ -595,8 +595,6 @@ blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id) | |||
595 | 595 | ||
596 | q->sg_reserved_size = INT_MAX; | 596 | q->sg_reserved_size = INT_MAX; |
597 | 597 | ||
598 | blk_set_cmd_filter_defaults(&q->cmd_filter); | ||
599 | |||
600 | /* | 598 | /* |
601 | * all done | 599 | * all done |
602 | */ | 600 | */ |
@@ -1172,6 +1170,11 @@ static int __make_request(struct request_queue *q, struct bio *bio) | |||
1172 | const int unplug = bio_unplug(bio); | 1170 | const int unplug = bio_unplug(bio); |
1173 | int rw_flags; | 1171 | int rw_flags; |
1174 | 1172 | ||
1173 | if (bio_barrier(bio) && bio_has_data(bio) && | ||
1174 | (q->next_ordered == QUEUE_ORDERED_NONE)) { | ||
1175 | bio_endio(bio, -EOPNOTSUPP); | ||
1176 | return 0; | ||
1177 | } | ||
1175 | /* | 1178 | /* |
1176 | * low level driver can indicate that it wants pages above a | 1179 | * low level driver can indicate that it wants pages above a |
1177 | * certain limit bounced to low memory (ie for highmem, or even | 1180 | * certain limit bounced to low memory (ie for highmem, or even |
@@ -1472,11 +1475,6 @@ static inline void __generic_make_request(struct bio *bio) | |||
1472 | err = -EOPNOTSUPP; | 1475 | err = -EOPNOTSUPP; |
1473 | goto end_io; | 1476 | goto end_io; |
1474 | } | 1477 | } |
1475 | if (bio_barrier(bio) && bio_has_data(bio) && | ||
1476 | (q->next_ordered == QUEUE_ORDERED_NONE)) { | ||
1477 | err = -EOPNOTSUPP; | ||
1478 | goto end_io; | ||
1479 | } | ||
1480 | 1478 | ||
1481 | ret = q->make_request_fn(q, bio); | 1479 | ret = q->make_request_fn(q, bio); |
1482 | } while (ret); | 1480 | } while (ret); |
@@ -2365,7 +2363,7 @@ int blk_rq_prep_clone(struct request *rq, struct request *rq_src, | |||
2365 | __bio_clone(bio, bio_src); | 2363 | __bio_clone(bio, bio_src); |
2366 | 2364 | ||
2367 | if (bio_integrity(bio_src) && | 2365 | if (bio_integrity(bio_src) && |
2368 | bio_integrity_clone(bio, bio_src, gfp_mask)) | 2366 | bio_integrity_clone(bio, bio_src, gfp_mask, bs)) |
2369 | goto free_and_out; | 2367 | goto free_and_out; |
2370 | 2368 | ||
2371 | if (bio_ctr && bio_ctr(bio, bio_src, data)) | 2369 | if (bio_ctr && bio_ctr(bio, bio_src, data)) |
diff --git a/block/bsg.c b/block/bsg.c index 54106f052f70..5f184bb3ff9e 100644 --- a/block/bsg.c +++ b/block/bsg.c | |||
@@ -186,7 +186,7 @@ static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq, | |||
186 | return -EFAULT; | 186 | return -EFAULT; |
187 | 187 | ||
188 | if (hdr->subprotocol == BSG_SUB_PROTOCOL_SCSI_CMD) { | 188 | if (hdr->subprotocol == BSG_SUB_PROTOCOL_SCSI_CMD) { |
189 | if (blk_verify_command(&q->cmd_filter, rq->cmd, has_write_perm)) | 189 | if (blk_verify_command(rq->cmd, has_write_perm)) |
190 | return -EPERM; | 190 | return -EPERM; |
191 | } else if (!capable(CAP_SYS_RAWIO)) | 191 | } else if (!capable(CAP_SYS_RAWIO)) |
192 | return -EPERM; | 192 | return -EPERM; |
@@ -315,7 +315,6 @@ out: | |||
315 | blk_put_request(rq); | 315 | blk_put_request(rq); |
316 | if (next_rq) { | 316 | if (next_rq) { |
317 | blk_rq_unmap_user(next_rq->bio); | 317 | blk_rq_unmap_user(next_rq->bio); |
318 | next_rq->bio = NULL; | ||
319 | blk_put_request(next_rq); | 318 | blk_put_request(next_rq); |
320 | } | 319 | } |
321 | return ERR_PTR(ret); | 320 | return ERR_PTR(ret); |
@@ -449,7 +448,6 @@ static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr, | |||
449 | hdr->dout_resid = rq->resid_len; | 448 | hdr->dout_resid = rq->resid_len; |
450 | hdr->din_resid = rq->next_rq->resid_len; | 449 | hdr->din_resid = rq->next_rq->resid_len; |
451 | blk_rq_unmap_user(bidi_bio); | 450 | blk_rq_unmap_user(bidi_bio); |
452 | rq->next_rq->bio = NULL; | ||
453 | blk_put_request(rq->next_rq); | 451 | blk_put_request(rq->next_rq); |
454 | } else if (rq_data_dir(rq) == READ) | 452 | } else if (rq_data_dir(rq) == READ) |
455 | hdr->din_resid = rq->resid_len; | 453 | hdr->din_resid = rq->resid_len; |
@@ -468,7 +466,6 @@ static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr, | |||
468 | blk_rq_unmap_user(bio); | 466 | blk_rq_unmap_user(bio); |
469 | if (rq->cmd != rq->__cmd) | 467 | if (rq->cmd != rq->__cmd) |
470 | kfree(rq->cmd); | 468 | kfree(rq->cmd); |
471 | rq->bio = NULL; | ||
472 | blk_put_request(rq); | 469 | blk_put_request(rq); |
473 | 470 | ||
474 | return ret; | 471 | return ret; |
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 0f1cc7d3855e..85208dd1d05b 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c | |||
@@ -71,6 +71,51 @@ struct cfq_rb_root { | |||
71 | #define CFQ_RB_ROOT (struct cfq_rb_root) { RB_ROOT, NULL, } | 71 | #define CFQ_RB_ROOT (struct cfq_rb_root) { RB_ROOT, NULL, } |
72 | 72 | ||
73 | /* | 73 | /* |
74 | * Per process-grouping structure | ||
75 | */ | ||
76 | struct cfq_queue { | ||
77 | /* reference count */ | ||
78 | atomic_t ref; | ||
79 | /* various state flags, see below */ | ||
80 | unsigned int flags; | ||
81 | /* parent cfq_data */ | ||
82 | struct cfq_data *cfqd; | ||
83 | /* service_tree member */ | ||
84 | struct rb_node rb_node; | ||
85 | /* service_tree key */ | ||
86 | unsigned long rb_key; | ||
87 | /* prio tree member */ | ||
88 | struct rb_node p_node; | ||
89 | /* prio tree root we belong to, if any */ | ||
90 | struct rb_root *p_root; | ||
91 | /* sorted list of pending requests */ | ||
92 | struct rb_root sort_list; | ||
93 | /* if fifo isn't expired, next request to serve */ | ||
94 | struct request *next_rq; | ||
95 | /* requests queued in sort_list */ | ||
96 | int queued[2]; | ||
97 | /* currently allocated requests */ | ||
98 | int allocated[2]; | ||
99 | /* fifo list of requests in sort_list */ | ||
100 | struct list_head fifo; | ||
101 | |||
102 | unsigned long slice_end; | ||
103 | long slice_resid; | ||
104 | unsigned int slice_dispatch; | ||
105 | |||
106 | /* pending metadata requests */ | ||
107 | int meta_pending; | ||
108 | /* number of requests that are on the dispatch list or inside driver */ | ||
109 | int dispatched; | ||
110 | |||
111 | /* io prio of this group */ | ||
112 | unsigned short ioprio, org_ioprio; | ||
113 | unsigned short ioprio_class, org_ioprio_class; | ||
114 | |||
115 | pid_t pid; | ||
116 | }; | ||
117 | |||
118 | /* | ||
74 | * Per block device queue structure | 119 | * Per block device queue structure |
75 | */ | 120 | */ |
76 | struct cfq_data { | 121 | struct cfq_data { |
@@ -135,51 +180,11 @@ struct cfq_data { | |||
135 | unsigned int cfq_slice_idle; | 180 | unsigned int cfq_slice_idle; |
136 | 181 | ||
137 | struct list_head cic_list; | 182 | struct list_head cic_list; |
138 | }; | ||
139 | |||
140 | /* | ||
141 | * Per process-grouping structure | ||
142 | */ | ||
143 | struct cfq_queue { | ||
144 | /* reference count */ | ||
145 | atomic_t ref; | ||
146 | /* various state flags, see below */ | ||
147 | unsigned int flags; | ||
148 | /* parent cfq_data */ | ||
149 | struct cfq_data *cfqd; | ||
150 | /* service_tree member */ | ||
151 | struct rb_node rb_node; | ||
152 | /* service_tree key */ | ||
153 | unsigned long rb_key; | ||
154 | /* prio tree member */ | ||
155 | struct rb_node p_node; | ||
156 | /* prio tree root we belong to, if any */ | ||
157 | struct rb_root *p_root; | ||
158 | /* sorted list of pending requests */ | ||
159 | struct rb_root sort_list; | ||
160 | /* if fifo isn't expired, next request to serve */ | ||
161 | struct request *next_rq; | ||
162 | /* requests queued in sort_list */ | ||
163 | int queued[2]; | ||
164 | /* currently allocated requests */ | ||
165 | int allocated[2]; | ||
166 | /* fifo list of requests in sort_list */ | ||
167 | struct list_head fifo; | ||
168 | 183 | ||
169 | unsigned long slice_end; | 184 | /* |
170 | long slice_resid; | 185 | * Fallback dummy cfqq for extreme OOM conditions |
171 | unsigned int slice_dispatch; | 186 | */ |
172 | 187 | struct cfq_queue oom_cfqq; | |
173 | /* pending metadata requests */ | ||
174 | int meta_pending; | ||
175 | /* number of requests that are on the dispatch list or inside driver */ | ||
176 | int dispatched; | ||
177 | |||
178 | /* io prio of this group */ | ||
179 | unsigned short ioprio, org_ioprio; | ||
180 | unsigned short ioprio_class, org_ioprio_class; | ||
181 | |||
182 | pid_t pid; | ||
183 | }; | 188 | }; |
184 | 189 | ||
185 | enum cfqq_state_flags { | 190 | enum cfqq_state_flags { |
@@ -1641,6 +1646,26 @@ static void cfq_ioc_set_ioprio(struct io_context *ioc) | |||
1641 | ioc->ioprio_changed = 0; | 1646 | ioc->ioprio_changed = 0; |
1642 | } | 1647 | } |
1643 | 1648 | ||
1649 | static void cfq_init_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq, | ||
1650 | pid_t pid, int is_sync) | ||
1651 | { | ||
1652 | RB_CLEAR_NODE(&cfqq->rb_node); | ||
1653 | RB_CLEAR_NODE(&cfqq->p_node); | ||
1654 | INIT_LIST_HEAD(&cfqq->fifo); | ||
1655 | |||
1656 | atomic_set(&cfqq->ref, 0); | ||
1657 | cfqq->cfqd = cfqd; | ||
1658 | |||
1659 | cfq_mark_cfqq_prio_changed(cfqq); | ||
1660 | |||
1661 | if (is_sync) { | ||
1662 | if (!cfq_class_idle(cfqq)) | ||
1663 | cfq_mark_cfqq_idle_window(cfqq); | ||
1664 | cfq_mark_cfqq_sync(cfqq); | ||
1665 | } | ||
1666 | cfqq->pid = pid; | ||
1667 | } | ||
1668 | |||
1644 | static struct cfq_queue * | 1669 | static struct cfq_queue * |
1645 | cfq_find_alloc_queue(struct cfq_data *cfqd, int is_sync, | 1670 | cfq_find_alloc_queue(struct cfq_data *cfqd, int is_sync, |
1646 | struct io_context *ioc, gfp_t gfp_mask) | 1671 | struct io_context *ioc, gfp_t gfp_mask) |
@@ -1653,56 +1678,40 @@ retry: | |||
1653 | /* cic always exists here */ | 1678 | /* cic always exists here */ |
1654 | cfqq = cic_to_cfqq(cic, is_sync); | 1679 | cfqq = cic_to_cfqq(cic, is_sync); |
1655 | 1680 | ||
1656 | if (!cfqq) { | 1681 | /* |
1682 | * Always try a new alloc if we fell back to the OOM cfqq | ||
1683 | * originally, since it should just be a temporary situation. | ||
1684 | */ | ||
1685 | if (!cfqq || cfqq == &cfqd->oom_cfqq) { | ||
1686 | cfqq = NULL; | ||
1657 | if (new_cfqq) { | 1687 | if (new_cfqq) { |
1658 | cfqq = new_cfqq; | 1688 | cfqq = new_cfqq; |
1659 | new_cfqq = NULL; | 1689 | new_cfqq = NULL; |
1660 | } else if (gfp_mask & __GFP_WAIT) { | 1690 | } else if (gfp_mask & __GFP_WAIT) { |
1661 | /* | ||
1662 | * Inform the allocator of the fact that we will | ||
1663 | * just repeat this allocation if it fails, to allow | ||
1664 | * the allocator to do whatever it needs to attempt to | ||
1665 | * free memory. | ||
1666 | */ | ||
1667 | spin_unlock_irq(cfqd->queue->queue_lock); | 1691 | spin_unlock_irq(cfqd->queue->queue_lock); |
1668 | new_cfqq = kmem_cache_alloc_node(cfq_pool, | 1692 | new_cfqq = kmem_cache_alloc_node(cfq_pool, |
1669 | gfp_mask | __GFP_NOFAIL | __GFP_ZERO, | 1693 | gfp_mask | __GFP_ZERO, |
1670 | cfqd->queue->node); | 1694 | cfqd->queue->node); |
1671 | spin_lock_irq(cfqd->queue->queue_lock); | 1695 | spin_lock_irq(cfqd->queue->queue_lock); |
1672 | goto retry; | 1696 | if (new_cfqq) |
1697 | goto retry; | ||
1673 | } else { | 1698 | } else { |
1674 | cfqq = kmem_cache_alloc_node(cfq_pool, | 1699 | cfqq = kmem_cache_alloc_node(cfq_pool, |
1675 | gfp_mask | __GFP_ZERO, | 1700 | gfp_mask | __GFP_ZERO, |
1676 | cfqd->queue->node); | 1701 | cfqd->queue->node); |
1677 | if (!cfqq) | ||
1678 | goto out; | ||
1679 | } | 1702 | } |
1680 | 1703 | ||
1681 | RB_CLEAR_NODE(&cfqq->rb_node); | 1704 | if (cfqq) { |
1682 | RB_CLEAR_NODE(&cfqq->p_node); | 1705 | cfq_init_cfqq(cfqd, cfqq, current->pid, is_sync); |
1683 | INIT_LIST_HEAD(&cfqq->fifo); | 1706 | cfq_init_prio_data(cfqq, ioc); |
1684 | 1707 | cfq_log_cfqq(cfqd, cfqq, "alloced"); | |
1685 | atomic_set(&cfqq->ref, 0); | 1708 | } else |
1686 | cfqq->cfqd = cfqd; | 1709 | cfqq = &cfqd->oom_cfqq; |
1687 | |||
1688 | cfq_mark_cfqq_prio_changed(cfqq); | ||
1689 | |||
1690 | cfq_init_prio_data(cfqq, ioc); | ||
1691 | |||
1692 | if (is_sync) { | ||
1693 | if (!cfq_class_idle(cfqq)) | ||
1694 | cfq_mark_cfqq_idle_window(cfqq); | ||
1695 | cfq_mark_cfqq_sync(cfqq); | ||
1696 | } | ||
1697 | cfqq->pid = current->pid; | ||
1698 | cfq_log_cfqq(cfqd, cfqq, "alloced"); | ||
1699 | } | 1710 | } |
1700 | 1711 | ||
1701 | if (new_cfqq) | 1712 | if (new_cfqq) |
1702 | kmem_cache_free(cfq_pool, new_cfqq); | 1713 | kmem_cache_free(cfq_pool, new_cfqq); |
1703 | 1714 | ||
1704 | out: | ||
1705 | WARN_ON((gfp_mask & __GFP_WAIT) && !cfqq); | ||
1706 | return cfqq; | 1715 | return cfqq; |
1707 | } | 1716 | } |
1708 | 1717 | ||
@@ -1735,11 +1744,8 @@ cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct io_context *ioc, | |||
1735 | cfqq = *async_cfqq; | 1744 | cfqq = *async_cfqq; |
1736 | } | 1745 | } |
1737 | 1746 | ||
1738 | if (!cfqq) { | 1747 | if (!cfqq) |
1739 | cfqq = cfq_find_alloc_queue(cfqd, is_sync, ioc, gfp_mask); | 1748 | cfqq = cfq_find_alloc_queue(cfqd, is_sync, ioc, gfp_mask); |
1740 | if (!cfqq) | ||
1741 | return NULL; | ||
1742 | } | ||
1743 | 1749 | ||
1744 | /* | 1750 | /* |
1745 | * pin the queue now that it's allocated, scheduler exit will prune it | 1751 | * pin the queue now that it's allocated, scheduler exit will prune it |
@@ -2307,10 +2313,6 @@ cfq_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask) | |||
2307 | cfqq = cic_to_cfqq(cic, is_sync); | 2313 | cfqq = cic_to_cfqq(cic, is_sync); |
2308 | if (!cfqq) { | 2314 | if (!cfqq) { |
2309 | cfqq = cfq_get_queue(cfqd, is_sync, cic->ioc, gfp_mask); | 2315 | cfqq = cfq_get_queue(cfqd, is_sync, cic->ioc, gfp_mask); |
2310 | |||
2311 | if (!cfqq) | ||
2312 | goto queue_fail; | ||
2313 | |||
2314 | cic_set_cfqq(cic, cfqq, is_sync); | 2316 | cic_set_cfqq(cic, cfqq, is_sync); |
2315 | } | 2317 | } |
2316 | 2318 | ||
@@ -2465,6 +2467,14 @@ static void *cfq_init_queue(struct request_queue *q) | |||
2465 | for (i = 0; i < CFQ_PRIO_LISTS; i++) | 2467 | for (i = 0; i < CFQ_PRIO_LISTS; i++) |
2466 | cfqd->prio_trees[i] = RB_ROOT; | 2468 | cfqd->prio_trees[i] = RB_ROOT; |
2467 | 2469 | ||
2470 | /* | ||
2471 | * Our fallback cfqq if cfq_find_alloc_queue() runs into OOM issues. | ||
2472 | * Grab a permanent reference to it, so that the normal code flow | ||
2473 | * will not attempt to free it. | ||
2474 | */ | ||
2475 | cfq_init_cfqq(cfqd, &cfqd->oom_cfqq, 1, 0); | ||
2476 | atomic_inc(&cfqd->oom_cfqq.ref); | ||
2477 | |||
2468 | INIT_LIST_HEAD(&cfqd->cic_list); | 2478 | INIT_LIST_HEAD(&cfqd->cic_list); |
2469 | 2479 | ||
2470 | cfqd->queue = q; | 2480 | cfqd->queue = q; |
diff --git a/block/cmd-filter.c b/block/cmd-filter.c deleted file mode 100644 index 572bbc2f900d..000000000000 --- a/block/cmd-filter.c +++ /dev/null | |||
@@ -1,233 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 2004 Peter M. Jones <pjones@redhat.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public Licens | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111- | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #include <linux/list.h> | ||
21 | #include <linux/genhd.h> | ||
22 | #include <linux/spinlock.h> | ||
23 | #include <linux/capability.h> | ||
24 | #include <linux/bitops.h> | ||
25 | #include <linux/blkdev.h> | ||
26 | |||
27 | #include <scsi/scsi.h> | ||
28 | #include <linux/cdrom.h> | ||
29 | |||
30 | int blk_verify_command(struct blk_cmd_filter *filter, | ||
31 | unsigned char *cmd, fmode_t has_write_perm) | ||
32 | { | ||
33 | /* root can do any command. */ | ||
34 | if (capable(CAP_SYS_RAWIO)) | ||
35 | return 0; | ||
36 | |||
37 | /* if there's no filter set, assume we're filtering everything out */ | ||
38 | if (!filter) | ||
39 | return -EPERM; | ||
40 | |||
41 | /* Anybody who can open the device can do a read-safe command */ | ||
42 | if (test_bit(cmd[0], filter->read_ok)) | ||
43 | return 0; | ||
44 | |||
45 | /* Write-safe commands require a writable open */ | ||
46 | if (test_bit(cmd[0], filter->write_ok) && has_write_perm) | ||
47 | return 0; | ||
48 | |||
49 | return -EPERM; | ||
50 | } | ||
51 | EXPORT_SYMBOL(blk_verify_command); | ||
52 | |||
53 | #if 0 | ||
54 | /* and now, the sysfs stuff */ | ||
55 | static ssize_t rcf_cmds_show(struct blk_cmd_filter *filter, char *page, | ||
56 | int rw) | ||
57 | { | ||
58 | char *npage = page; | ||
59 | unsigned long *okbits; | ||
60 | int i; | ||
61 | |||
62 | if (rw == READ) | ||
63 | okbits = filter->read_ok; | ||
64 | else | ||
65 | okbits = filter->write_ok; | ||
66 | |||
67 | for (i = 0; i < BLK_SCSI_MAX_CMDS; i++) { | ||
68 | if (test_bit(i, okbits)) { | ||
69 | npage += sprintf(npage, "0x%02x", i); | ||
70 | if (i < BLK_SCSI_MAX_CMDS - 1) | ||
71 | sprintf(npage++, " "); | ||
72 | } | ||
73 | } | ||
74 | |||
75 | if (npage != page) | ||
76 | npage += sprintf(npage, "\n"); | ||
77 | |||
78 | return npage - page; | ||
79 | } | ||
80 | |||
81 | static ssize_t rcf_readcmds_show(struct blk_cmd_filter *filter, char *page) | ||
82 | { | ||
83 | return rcf_cmds_show(filter, page, READ); | ||
84 | } | ||
85 | |||
86 | static ssize_t rcf_writecmds_show(struct blk_cmd_filter *filter, | ||
87 | char *page) | ||
88 | { | ||
89 | return rcf_cmds_show(filter, page, WRITE); | ||
90 | } | ||
91 | |||
92 | static ssize_t rcf_cmds_store(struct blk_cmd_filter *filter, | ||
93 | const char *page, size_t count, int rw) | ||
94 | { | ||
95 | unsigned long okbits[BLK_SCSI_CMD_PER_LONG], *target_okbits; | ||
96 | int cmd, set; | ||
97 | char *p, *status; | ||
98 | |||
99 | if (rw == READ) { | ||
100 | memcpy(&okbits, filter->read_ok, sizeof(okbits)); | ||
101 | target_okbits = filter->read_ok; | ||
102 | } else { | ||
103 | memcpy(&okbits, filter->write_ok, sizeof(okbits)); | ||
104 | target_okbits = filter->write_ok; | ||
105 | } | ||
106 | |||
107 | while ((p = strsep((char **)&page, " ")) != NULL) { | ||
108 | set = 1; | ||
109 | |||
110 | if (p[0] == '+') { | ||
111 | p++; | ||
112 | } else if (p[0] == '-') { | ||
113 | set = 0; | ||
114 | p++; | ||
115 | } | ||
116 | |||
117 | cmd = simple_strtol(p, &status, 16); | ||
118 | |||
119 | /* either of these cases means invalid input, so do nothing. */ | ||
120 | if ((status == p) || cmd >= BLK_SCSI_MAX_CMDS) | ||
121 | return -EINVAL; | ||
122 | |||
123 | if (set) | ||
124 | __set_bit(cmd, okbits); | ||
125 | else | ||
126 | __clear_bit(cmd, okbits); | ||
127 | } | ||
128 | |||
129 | memcpy(target_okbits, okbits, sizeof(okbits)); | ||
130 | return count; | ||
131 | } | ||
132 | |||
133 | static ssize_t rcf_readcmds_store(struct blk_cmd_filter *filter, | ||
134 | const char *page, size_t count) | ||
135 | { | ||
136 | return rcf_cmds_store(filter, page, count, READ); | ||
137 | } | ||
138 | |||
139 | static ssize_t rcf_writecmds_store(struct blk_cmd_filter *filter, | ||
140 | const char *page, size_t count) | ||
141 | { | ||
142 | return rcf_cmds_store(filter, page, count, WRITE); | ||
143 | } | ||
144 | |||
145 | struct rcf_sysfs_entry { | ||
146 | struct attribute attr; | ||
147 | ssize_t (*show)(struct blk_cmd_filter *, char *); | ||
148 | ssize_t (*store)(struct blk_cmd_filter *, const char *, size_t); | ||
149 | }; | ||
150 | |||
151 | static struct rcf_sysfs_entry rcf_readcmds_entry = { | ||
152 | .attr = { .name = "read_table", .mode = S_IRUGO | S_IWUSR }, | ||
153 | .show = rcf_readcmds_show, | ||
154 | .store = rcf_readcmds_store, | ||
155 | }; | ||
156 | |||
157 | static struct rcf_sysfs_entry rcf_writecmds_entry = { | ||
158 | .attr = {.name = "write_table", .mode = S_IRUGO | S_IWUSR }, | ||
159 | .show = rcf_writecmds_show, | ||
160 | .store = rcf_writecmds_store, | ||
161 | }; | ||
162 | |||
163 | static struct attribute *default_attrs[] = { | ||
164 | &rcf_readcmds_entry.attr, | ||
165 | &rcf_writecmds_entry.attr, | ||
166 | NULL, | ||
167 | }; | ||
168 | |||
169 | #define to_rcf(atr) container_of((atr), struct rcf_sysfs_entry, attr) | ||
170 | |||
171 | static ssize_t | ||
172 | rcf_attr_show(struct kobject *kobj, struct attribute *attr, char *page) | ||
173 | { | ||
174 | struct rcf_sysfs_entry *entry = to_rcf(attr); | ||
175 | struct blk_cmd_filter *filter; | ||
176 | |||
177 | filter = container_of(kobj, struct blk_cmd_filter, kobj); | ||
178 | if (entry->show) | ||
179 | return entry->show(filter, page); | ||
180 | |||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | static ssize_t | ||
185 | rcf_attr_store(struct kobject *kobj, struct attribute *attr, | ||
186 | const char *page, size_t length) | ||
187 | { | ||
188 | struct rcf_sysfs_entry *entry = to_rcf(attr); | ||
189 | struct blk_cmd_filter *filter; | ||
190 | |||
191 | if (!capable(CAP_SYS_RAWIO)) | ||
192 | return -EPERM; | ||
193 | |||
194 | if (!entry->store) | ||
195 | return -EINVAL; | ||
196 | |||
197 | filter = container_of(kobj, struct blk_cmd_filter, kobj); | ||
198 | return entry->store(filter, page, length); | ||
199 | } | ||
200 | |||
201 | static struct sysfs_ops rcf_sysfs_ops = { | ||
202 | .show = rcf_attr_show, | ||
203 | .store = rcf_attr_store, | ||
204 | }; | ||
205 | |||
206 | static struct kobj_type rcf_ktype = { | ||
207 | .sysfs_ops = &rcf_sysfs_ops, | ||
208 | .default_attrs = default_attrs, | ||
209 | }; | ||
210 | |||
211 | int blk_register_filter(struct gendisk *disk) | ||
212 | { | ||
213 | int ret; | ||
214 | struct blk_cmd_filter *filter = &disk->queue->cmd_filter; | ||
215 | |||
216 | ret = kobject_init_and_add(&filter->kobj, &rcf_ktype, | ||
217 | &disk_to_dev(disk)->kobj, | ||
218 | "%s", "cmd_filter"); | ||
219 | if (ret < 0) | ||
220 | return ret; | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | EXPORT_SYMBOL(blk_register_filter); | ||
225 | |||
226 | void blk_unregister_filter(struct gendisk *disk) | ||
227 | { | ||
228 | struct blk_cmd_filter *filter = &disk->queue->cmd_filter; | ||
229 | |||
230 | kobject_put(&filter->kobj); | ||
231 | } | ||
232 | EXPORT_SYMBOL(blk_unregister_filter); | ||
233 | #endif | ||
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index 5f8e798ede4e..f0e0ce0a607d 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c | |||
@@ -32,6 +32,11 @@ | |||
32 | #include <scsi/scsi_ioctl.h> | 32 | #include <scsi/scsi_ioctl.h> |
33 | #include <scsi/scsi_cmnd.h> | 33 | #include <scsi/scsi_cmnd.h> |
34 | 34 | ||
35 | struct blk_cmd_filter { | ||
36 | unsigned long read_ok[BLK_SCSI_CMD_PER_LONG]; | ||
37 | unsigned long write_ok[BLK_SCSI_CMD_PER_LONG]; | ||
38 | } blk_default_cmd_filter; | ||
39 | |||
35 | /* Command group 3 is reserved and should never be used. */ | 40 | /* Command group 3 is reserved and should never be used. */ |
36 | const unsigned char scsi_command_size_tbl[8] = | 41 | const unsigned char scsi_command_size_tbl[8] = |
37 | { | 42 | { |
@@ -105,7 +110,7 @@ static int sg_emulated_host(struct request_queue *q, int __user *p) | |||
105 | return put_user(1, p); | 110 | return put_user(1, p); |
106 | } | 111 | } |
107 | 112 | ||
108 | void blk_set_cmd_filter_defaults(struct blk_cmd_filter *filter) | 113 | static void blk_set_cmd_filter_defaults(struct blk_cmd_filter *filter) |
109 | { | 114 | { |
110 | /* Basic read-only commands */ | 115 | /* Basic read-only commands */ |
111 | __set_bit(TEST_UNIT_READY, filter->read_ok); | 116 | __set_bit(TEST_UNIT_READY, filter->read_ok); |
@@ -187,14 +192,37 @@ void blk_set_cmd_filter_defaults(struct blk_cmd_filter *filter) | |||
187 | __set_bit(GPCMD_SET_STREAMING, filter->write_ok); | 192 | __set_bit(GPCMD_SET_STREAMING, filter->write_ok); |
188 | __set_bit(GPCMD_SET_READ_AHEAD, filter->write_ok); | 193 | __set_bit(GPCMD_SET_READ_AHEAD, filter->write_ok); |
189 | } | 194 | } |
190 | EXPORT_SYMBOL_GPL(blk_set_cmd_filter_defaults); | 195 | |
196 | int blk_verify_command(unsigned char *cmd, fmode_t has_write_perm) | ||
197 | { | ||
198 | struct blk_cmd_filter *filter = &blk_default_cmd_filter; | ||
199 | |||
200 | /* root can do any command. */ | ||
201 | if (capable(CAP_SYS_RAWIO)) | ||
202 | return 0; | ||
203 | |||
204 | /* if there's no filter set, assume we're filtering everything out */ | ||
205 | if (!filter) | ||
206 | return -EPERM; | ||
207 | |||
208 | /* Anybody who can open the device can do a read-safe command */ | ||
209 | if (test_bit(cmd[0], filter->read_ok)) | ||
210 | return 0; | ||
211 | |||
212 | /* Write-safe commands require a writable open */ | ||
213 | if (test_bit(cmd[0], filter->write_ok) && has_write_perm) | ||
214 | return 0; | ||
215 | |||
216 | return -EPERM; | ||
217 | } | ||
218 | EXPORT_SYMBOL(blk_verify_command); | ||
191 | 219 | ||
192 | static int blk_fill_sghdr_rq(struct request_queue *q, struct request *rq, | 220 | static int blk_fill_sghdr_rq(struct request_queue *q, struct request *rq, |
193 | struct sg_io_hdr *hdr, fmode_t mode) | 221 | struct sg_io_hdr *hdr, fmode_t mode) |
194 | { | 222 | { |
195 | if (copy_from_user(rq->cmd, hdr->cmdp, hdr->cmd_len)) | 223 | if (copy_from_user(rq->cmd, hdr->cmdp, hdr->cmd_len)) |
196 | return -EFAULT; | 224 | return -EFAULT; |
197 | if (blk_verify_command(&q->cmd_filter, rq->cmd, mode & FMODE_WRITE)) | 225 | if (blk_verify_command(rq->cmd, mode & FMODE_WRITE)) |
198 | return -EPERM; | 226 | return -EPERM; |
199 | 227 | ||
200 | /* | 228 | /* |
@@ -427,7 +455,7 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode, | |||
427 | if (in_len && copy_from_user(buffer, sic->data + cmdlen, in_len)) | 455 | if (in_len && copy_from_user(buffer, sic->data + cmdlen, in_len)) |
428 | goto error; | 456 | goto error; |
429 | 457 | ||
430 | err = blk_verify_command(&q->cmd_filter, rq->cmd, mode & FMODE_WRITE); | 458 | err = blk_verify_command(rq->cmd, mode & FMODE_WRITE); |
431 | if (err) | 459 | if (err) |
432 | goto error; | 460 | goto error; |
433 | 461 | ||
@@ -645,5 +673,10 @@ int scsi_cmd_ioctl(struct request_queue *q, struct gendisk *bd_disk, fmode_t mod | |||
645 | blk_put_queue(q); | 673 | blk_put_queue(q); |
646 | return err; | 674 | return err; |
647 | } | 675 | } |
648 | |||
649 | EXPORT_SYMBOL(scsi_cmd_ioctl); | 676 | EXPORT_SYMBOL(scsi_cmd_ioctl); |
677 | |||
678 | int __init blk_scsi_ioctl_init(void) | ||
679 | { | ||
680 | blk_set_cmd_filter_defaults(&blk_default_cmd_filter); | ||
681 | return 0; | ||
682 | } | ||