diff options
author | Tejun Heo <htejun@gmail.com> | 2007-11-27 03:30:39 -0500 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2007-11-27 03:30:39 -0500 |
commit | 645a8d94629fd812a220d54876339a1ddafd9bc2 (patch) | |
tree | ea333b0ae1dd478e8a902a3bab780a1c6d673304 | |
parent | 7c9f29b128aab5ac95af553e8d8e0e372647f1d5 (diff) |
scatterlist: add more safeguards
Add more safeguards to protect against misinterpreting a chain entry
as a normal scatterlist and vice-versa.
* Make sure the entry isn't a chain when assigning and reading a
normal sg.
* Clear offset and length when chaining.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
-rw-r--r-- | include/linux/scatterlist.h | 37 |
1 files changed, 26 insertions, 11 deletions
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 @@ | |||
26 | 26 | ||
27 | #define SG_MAGIC 0x87654321 | 27 | #define SG_MAGIC 0x87654321 |
28 | 28 | ||
29 | /* | ||
30 | * We overload the LSB of the page pointer to indicate whether it's | ||
31 | * a valid sg entry, or whether it points to the start of a new scatterlist. | ||
32 | * Those low bits are there for everyone! (thanks mason :-) | ||
33 | */ | ||
34 | #define sg_is_chain(sg) ((sg)->page_link & 0x01) | ||
35 | #define sg_is_last(sg) ((sg)->page_link & 0x02) | ||
36 | #define sg_chain_ptr(sg) \ | ||
37 | ((struct scatterlist *) ((sg)->page_link & ~0x03)) | ||
38 | |||
29 | /** | 39 | /** |
30 | * sg_assign_page - Assign a given page to an SG entry | 40 | * sg_assign_page - Assign a given page to an SG entry |
31 | * @sg: SG entry | 41 | * @sg: SG entry |
@@ -47,6 +57,7 @@ static inline void sg_assign_page(struct scatterlist *sg, struct page *page) | |||
47 | BUG_ON((unsigned long) page & 0x03); | 57 | BUG_ON((unsigned long) page & 0x03); |
48 | #ifdef CONFIG_DEBUG_SG | 58 | #ifdef CONFIG_DEBUG_SG |
49 | BUG_ON(sg->sg_magic != SG_MAGIC); | 59 | BUG_ON(sg->sg_magic != SG_MAGIC); |
60 | BUG_ON(sg_is_chain(sg)); | ||
50 | #endif | 61 | #endif |
51 | sg->page_link = page_link | (unsigned long) page; | 62 | sg->page_link = page_link | (unsigned long) page; |
52 | } | 63 | } |
@@ -73,7 +84,14 @@ static inline void sg_set_page(struct scatterlist *sg, struct page *page, | |||
73 | sg->length = len; | 84 | sg->length = len; |
74 | } | 85 | } |
75 | 86 | ||
76 | #define sg_page(sg) ((struct page *) ((sg)->page_link & ~0x3)) | 87 | static inline struct page *sg_page(struct scatterlist *sg) |
88 | { | ||
89 | #ifdef CONFIG_DEBUG_SG | ||
90 | BUG_ON(sg->sg_magic != SG_MAGIC); | ||
91 | BUG_ON(sg_is_chain(sg)); | ||
92 | #endif | ||
93 | return (struct page *)((sg)->page_link & ~0x3); | ||
94 | } | ||
77 | 95 | ||
78 | /** | 96 | /** |
79 | * sg_set_buf - Set sg entry to point at given data | 97 | * 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, | |||
88 | sg_set_page(sg, virt_to_page(buf), buflen, offset_in_page(buf)); | 106 | sg_set_page(sg, virt_to_page(buf), buflen, offset_in_page(buf)); |
89 | } | 107 | } |
90 | 108 | ||
91 | /* | ||
92 | * We overload the LSB of the page pointer to indicate whether it's | ||
93 | * a valid sg entry, or whether it points to the start of a new scatterlist. | ||
94 | * Those low bits are there for everyone! (thanks mason :-) | ||
95 | */ | ||
96 | #define sg_is_chain(sg) ((sg)->page_link & 0x01) | ||
97 | #define sg_is_last(sg) ((sg)->page_link & 0x02) | ||
98 | #define sg_chain_ptr(sg) \ | ||
99 | ((struct scatterlist *) ((sg)->page_link & ~0x03)) | ||
100 | |||
101 | /** | 109 | /** |
102 | * sg_next - return the next scatterlist entry in a list | 110 | * sg_next - return the next scatterlist entry in a list |
103 | * @sg: The current sg entry | 111 | * @sg: The current sg entry |
@@ -179,6 +187,13 @@ static inline void sg_chain(struct scatterlist *prv, unsigned int prv_nents, | |||
179 | #ifndef ARCH_HAS_SG_CHAIN | 187 | #ifndef ARCH_HAS_SG_CHAIN |
180 | BUG(); | 188 | BUG(); |
181 | #endif | 189 | #endif |
190 | |||
191 | /* | ||
192 | * offset and length are unused for chain entry. Clear them. | ||
193 | */ | ||
194 | prv->offset = 0; | ||
195 | prv->length = 0; | ||
196 | |||
182 | /* | 197 | /* |
183 | * Set lowest bit to indicate a link pointer, and make sure to clear | 198 | * Set lowest bit to indicate a link pointer, and make sure to clear |
184 | * the termination bit if it happens to be set. | 199 | * the termination bit if it happens to be set. |