summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-11-28 01:21:19 +0300
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-11-28 01:21:19 +0300
commit9c8ff4f4dac189e4111238d54c2b12e7837f4818 (patch)
tree70bd1b82721b56e17ebdbb11b618c47864146061
parent86e67a07d4dc8cd40454698f2abb972fced06910 (diff)
parent645a8d94629fd812a220d54876339a1ddafd9bc2 (diff)
downloadlinux-9c8ff4f4dac189e4111238d54c2b12e7837f4818.tar.xz
Merge branch 'for-linus' of git://git.kernel.dk/linux-2.6-block
* 'for-linus' of git://git.kernel.dk/linux-2.6-block: scatterlist: add more safeguards Revert "ll_rw_blk: temporarily enable max_segments tweaking" mmc: Add missing sg_init_table() call block: Fix memory leak in alloc_disk_node() alpha: fix sg_page breakage blktrace: Make sure BLKTRACETEARDOWN does the full cleanup.
-rw-r--r--arch/alpha/kernel/pci-noop.c14
-rw-r--r--block/blktrace.c9
-rw-r--r--block/genhd.c1
-rw-r--r--block/ll_rw_blk.c23
-rw-r--r--drivers/mmc/card/queue.c3
-rw-r--r--include/linux/scatterlist.h37
6 files changed, 44 insertions, 43 deletions
diff --git a/arch/alpha/kernel/pci-noop.c b/arch/alpha/kernel/pci-noop.c
index 174b729c504b..468b76ce66a1 100644
--- a/arch/alpha/kernel/pci-noop.c
+++ b/arch/alpha/kernel/pci-noop.c
@@ -12,6 +12,7 @@
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
#include "proto.h"
@@ -172,18 +173,19 @@ dma_alloc_coherent(struct device *dev, size_t size,
EXPORT_SYMBOL(dma_alloc_coherent);
int
-dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+dma_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
enum dma_data_direction direction)
{
int i;
+ struct scatterlist *sg;
- for (i = 0; i < nents; i++ ) {
+ for_each_sg(sgl, sg, nents, i) {
void *va;
- BUG_ON(!sg[i].page);
- va = page_address(sg[i].page) + sg[i].offset;
- sg_dma_address(sg + i) = (dma_addr_t)virt_to_bus(va);
- sg_dma_len(sg + i) = sg[i].length;
+ BUG_ON(!sg_page(sg));
+ va = sg_virt(sg);
+ sg_dma_address(sg) = (dma_addr_t)virt_to_bus(va);
+ sg_dma_len(sg) = sg->length;
}
return nents;
diff --git a/block/blktrace.c b/block/blktrace.c
index d00ac3993c18..498a0a54a6aa 100644
--- a/block/blktrace.c
+++ b/block/blktrace.c
@@ -202,6 +202,7 @@ static void blk_remove_tree(struct dentry *dir)
static struct dentry *blk_create_tree(const char *blk_name)
{
struct dentry *dir = NULL;
+ int created = 0;
mutex_lock(&blk_tree_mutex);
@@ -209,13 +210,17 @@ static struct dentry *blk_create_tree(const char *blk_name)
blk_tree_root = debugfs_create_dir("block", NULL);
if (!blk_tree_root)
goto err;
+ created = 1;
}
dir = debugfs_create_dir(blk_name, blk_tree_root);
if (dir)
root_users++;
- else
- blk_remove_root();
+ else {
+ /* Delete root only if we created it */
+ if (created)
+ blk_remove_root();
+ }
err:
mutex_unlock(&blk_tree_mutex);
diff --git a/block/genhd.c b/block/genhd.c
index e609996f2e76..f2ac914160d1 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -715,6 +715,7 @@ struct gendisk *alloc_disk_node(int minors, int node_id)
disk->part = kmalloc_node(size,
GFP_KERNEL | __GFP_ZERO, node_id);
if (!disk->part) {
+ free_disk_stats(disk);
kfree(disk);
return NULL;
}
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index 3b927be03850..8b919940b2ab 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -4080,23 +4080,7 @@ static ssize_t queue_max_hw_sectors_show(struct request_queue *q, char *page)
return queue_var_show(max_hw_sectors_kb, (page));
}
-static ssize_t queue_max_segments_show(struct request_queue *q, char *page)
-{
- return queue_var_show(q->max_phys_segments, page);
-}
-
-static ssize_t queue_max_segments_store(struct request_queue *q,
- const char *page, size_t count)
-{
- unsigned long segments;
- ssize_t ret = queue_var_store(&segments, page, count);
- spin_lock_irq(q->queue_lock);
- q->max_phys_segments = segments;
- spin_unlock_irq(q->queue_lock);
-
- return ret;
-}
static struct queue_sysfs_entry queue_requests_entry = {
.attr = {.name = "nr_requests", .mode = S_IRUGO | S_IWUSR },
.show = queue_requests_show,
@@ -4120,12 +4104,6 @@ static struct queue_sysfs_entry queue_max_hw_sectors_entry = {
.show = queue_max_hw_sectors_show,
};
-static struct queue_sysfs_entry queue_max_segments_entry = {
- .attr = {.name = "max_segments", .mode = S_IRUGO | S_IWUSR },
- .show = queue_max_segments_show,
- .store = queue_max_segments_store,
-};
-
static struct queue_sysfs_entry queue_iosched_entry = {
.attr = {.name = "scheduler", .mode = S_IRUGO | S_IWUSR },
.show = elv_iosched_show,
@@ -4137,7 +4115,6 @@ static struct attribute *default_attrs[] = {
&queue_ra_entry.attr,
&queue_max_hw_sectors_entry.attr,
&queue_max_sectors_entry.attr,
- &queue_max_segments_entry.attr,
&queue_iosched_entry.attr,
NULL,
};
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 1b9c9b6da5b7..30cd13b13ac3 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -180,12 +180,13 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
blk_queue_max_hw_segments(mq->queue, host->max_hw_segs);
blk_queue_max_segment_size(mq->queue, host->max_seg_size);
- mq->sg = kzalloc(sizeof(struct scatterlist) *
+ mq->sg = kmalloc(sizeof(struct scatterlist) *
host->max_phys_segs, GFP_KERNEL);
if (!mq->sg) {
ret = -ENOMEM;
goto cleanup_queue;
}
+ sg_init_table(mq->sg, host->max_phys_segs);
}
init_MUTEX(&mq->thread_sem);
diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h
index 259735044148..416e000dfe81 100644
--- a/include/linux/scatterlist.h
+++ b/include/linux/scatterlist.h
@@ -26,6 +26,16 @@
#define SG_MAGIC 0x87654321
+/*
+ * We overload the LSB of the page pointer to indicate whether it's
+ * a valid sg entry, or whether it points to the start of a new scatterlist.
+ * Those low bits are there for everyone! (thanks mason :-)
+ */
+#define sg_is_chain(sg) ((sg)->page_link & 0x01)
+#define sg_is_last(sg) ((sg)->page_link & 0x02)
+#define sg_chain_ptr(sg) \
+ ((struct scatterlist *) ((sg)->page_link & ~0x03))
+
/**
* sg_assign_page - Assign a given page to an SG entry
* @sg: SG entry
@@ -47,6 +57,7 @@ static inline void sg_assign_page(struct scatterlist *sg, struct page *page)
BUG_ON((unsigned long) page & 0x03);
#ifdef CONFIG_DEBUG_SG
BUG_ON(sg->sg_magic != SG_MAGIC);
+ BUG_ON(sg_is_chain(sg));
#endif
sg->page_link = page_link | (unsigned long) page;
}
@@ -73,7 +84,14 @@ static inline void sg_set_page(struct scatterlist *sg, struct page *page,
sg->length = len;
}
-#define sg_page(sg) ((struct page *) ((sg)->page_link & ~0x3))
+static inline struct page *sg_page(struct scatterlist *sg)
+{
+#ifdef CONFIG_DEBUG_SG
+ BUG_ON(sg->sg_magic != SG_MAGIC);
+ BUG_ON(sg_is_chain(sg));
+#endif
+ return (struct page *)((sg)->page_link & ~0x3);
+}
/**
* sg_set_buf - Set sg entry to point at given data
@@ -88,16 +106,6 @@ static inline void sg_set_buf(struct scatterlist *sg, const void *buf,
sg_set_page(sg, virt_to_page(buf), buflen, offset_in_page(buf));
}
-/*
- * We overload the LSB of the page pointer to indicate whether it's
- * a valid sg entry, or whether it points to the start of a new scatterlist.
- * Those low bits are there for everyone! (thanks mason :-)
- */
-#define sg_is_chain(sg) ((sg)->page_link & 0x01)
-#define sg_is_last(sg) ((sg)->page_link & 0x02)
-#define sg_chain_ptr(sg) \
- ((struct scatterlist *) ((sg)->page_link & ~0x03))
-
/**
* sg_next - return the next scatterlist entry in a list
* @sg: The current sg entry
@@ -179,6 +187,13 @@ static inline void sg_chain(struct scatterlist *prv, unsigned int prv_nents,
#ifndef ARCH_HAS_SG_CHAIN
BUG();
#endif
+
+ /*
+ * offset and length are unused for chain entry. Clear them.
+ */
+ prv->offset = 0;
+ prv->length = 0;
+
/*
* Set lowest bit to indicate a link pointer, and make sure to clear
* the termination bit if it happens to be set.