Skip to content

Commit 88413a6

Browse files
jk-ozlabsAl Viro
authored andcommitted
powerpc/spufs: fix copy_to_user while atomic
Currently, we may perform a copy_to_user (through simple_read_from_buffer()) while holding a context's register_lock, while accessing the context save area. This change uses a temporary buffer for the context save area data, which we then pass to simple_read_from_buffer. Includes changes from Christoph Hellwig <[email protected]>. Fixes: bf1ab97 ("[POWERPC] coredump: Add SPU elf notes to coredump.") Signed-off-by: Jeremy Kerr <[email protected]> Reviewed-by: Arnd Bergmann <[email protected]> [hch: renamed to function to avoid ___-prefixes] Signed-off-by: Christoph Hellwig <[email protected]> Signed-off-by: Al Viro <[email protected]>
1 parent 8f3d9f3 commit 88413a6

File tree

1 file changed

+75
-38
lines changed
  • arch/powerpc/platforms/cell/spufs

1 file changed

+75
-38
lines changed

arch/powerpc/platforms/cell/spufs/file.c

Lines changed: 75 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1978,8 +1978,9 @@ static ssize_t __spufs_mbox_info_read(struct spu_context *ctx,
19781978
static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf,
19791979
size_t len, loff_t *pos)
19801980
{
1981-
int ret;
19821981
struct spu_context *ctx = file->private_data;
1982+
u32 stat, data;
1983+
int ret;
19831984

19841985
if (!access_ok(buf, len))
19851986
return -EFAULT;
@@ -1988,11 +1989,16 @@ static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf,
19881989
if (ret)
19891990
return ret;
19901991
spin_lock(&ctx->csa.register_lock);
1991-
ret = __spufs_mbox_info_read(ctx, buf, len, pos);
1992+
stat = ctx->csa.prob.mb_stat_R;
1993+
data = ctx->csa.prob.pu_mb_R;
19921994
spin_unlock(&ctx->csa.register_lock);
19931995
spu_release_saved(ctx);
19941996

1995-
return ret;
1997+
/* EOF if there's no entry in the mbox */
1998+
if (!(stat & 0x0000ff))
1999+
return 0;
2000+
2001+
return simple_read_from_buffer(buf, len, pos, &data, sizeof(data));
19962002
}
19972003

19982004
static const struct file_operations spufs_mbox_info_fops = {
@@ -2019,6 +2025,7 @@ static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf,
20192025
size_t len, loff_t *pos)
20202026
{
20212027
struct spu_context *ctx = file->private_data;
2028+
u32 stat, data;
20222029
int ret;
20232030

20242031
if (!access_ok(buf, len))
@@ -2028,11 +2035,16 @@ static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf,
20282035
if (ret)
20292036
return ret;
20302037
spin_lock(&ctx->csa.register_lock);
2031-
ret = __spufs_ibox_info_read(ctx, buf, len, pos);
2038+
stat = ctx->csa.prob.mb_stat_R;
2039+
data = ctx->csa.priv2.puint_mb_R;
20322040
spin_unlock(&ctx->csa.register_lock);
20332041
spu_release_saved(ctx);
20342042

2035-
return ret;
2043+
/* EOF if there's no entry in the ibox */
2044+
if (!(stat & 0xff0000))
2045+
return 0;
2046+
2047+
return simple_read_from_buffer(buf, len, pos, &data, sizeof(data));
20362048
}
20372049

20382050
static const struct file_operations spufs_ibox_info_fops = {
@@ -2041,6 +2053,11 @@ static const struct file_operations spufs_ibox_info_fops = {
20412053
.llseek = generic_file_llseek,
20422054
};
20432055

2056+
static size_t spufs_wbox_info_cnt(struct spu_context *ctx)
2057+
{
2058+
return (4 - ((ctx->csa.prob.mb_stat_R & 0x00ff00) >> 8)) * sizeof(u32);
2059+
}
2060+
20442061
static ssize_t __spufs_wbox_info_read(struct spu_context *ctx,
20452062
char __user *buf, size_t len, loff_t *pos)
20462063
{
@@ -2049,7 +2066,7 @@ static ssize_t __spufs_wbox_info_read(struct spu_context *ctx,
20492066
u32 wbox_stat;
20502067

20512068
wbox_stat = ctx->csa.prob.mb_stat_R;
2052-
cnt = 4 - ((wbox_stat & 0x00ff00) >> 8);
2069+
cnt = spufs_wbox_info_cnt(ctx);
20532070
for (i = 0; i < cnt; i++) {
20542071
data[i] = ctx->csa.spu_mailbox_data[i];
20552072
}
@@ -2062,7 +2079,8 @@ static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf,
20622079
size_t len, loff_t *pos)
20632080
{
20642081
struct spu_context *ctx = file->private_data;
2065-
int ret;
2082+
u32 data[ARRAY_SIZE(ctx->csa.spu_mailbox_data)];
2083+
int ret, count;
20662084

20672085
if (!access_ok(buf, len))
20682086
return -EFAULT;
@@ -2071,11 +2089,13 @@ static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf,
20712089
if (ret)
20722090
return ret;
20732091
spin_lock(&ctx->csa.register_lock);
2074-
ret = __spufs_wbox_info_read(ctx, buf, len, pos);
2092+
count = spufs_wbox_info_cnt(ctx);
2093+
memcpy(&data, &ctx->csa.spu_mailbox_data, sizeof(data));
20752094
spin_unlock(&ctx->csa.register_lock);
20762095
spu_release_saved(ctx);
20772096

2078-
return ret;
2097+
return simple_read_from_buffer(buf, len, pos, &data,
2098+
count * sizeof(u32));
20792099
}
20802100

20812101
static const struct file_operations spufs_wbox_info_fops = {
@@ -2084,27 +2104,33 @@ static const struct file_operations spufs_wbox_info_fops = {
20842104
.llseek = generic_file_llseek,
20852105
};
20862106

2087-
static ssize_t __spufs_dma_info_read(struct spu_context *ctx,
2088-
char __user *buf, size_t len, loff_t *pos)
2107+
static void spufs_get_dma_info(struct spu_context *ctx,
2108+
struct spu_dma_info *info)
20892109
{
2090-
struct spu_dma_info info;
2091-
struct mfc_cq_sr *qp, *spuqp;
20922110
int i;
20932111

2094-
info.dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW;
2095-
info.dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0];
2096-
info.dma_info_status = ctx->csa.spu_chnldata_RW[24];
2097-
info.dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25];
2098-
info.dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27];
2112+
info->dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW;
2113+
info->dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0];
2114+
info->dma_info_status = ctx->csa.spu_chnldata_RW[24];
2115+
info->dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25];
2116+
info->dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27];
20992117
for (i = 0; i < 16; i++) {
2100-
qp = &info.dma_info_command_data[i];
2101-
spuqp = &ctx->csa.priv2.spuq[i];
2118+
struct mfc_cq_sr *qp = &info->dma_info_command_data[i];
2119+
struct mfc_cq_sr *spuqp = &ctx->csa.priv2.spuq[i];
21022120

21032121
qp->mfc_cq_data0_RW = spuqp->mfc_cq_data0_RW;
21042122
qp->mfc_cq_data1_RW = spuqp->mfc_cq_data1_RW;
21052123
qp->mfc_cq_data2_RW = spuqp->mfc_cq_data2_RW;
21062124
qp->mfc_cq_data3_RW = spuqp->mfc_cq_data3_RW;
21072125
}
2126+
}
2127+
2128+
static ssize_t __spufs_dma_info_read(struct spu_context *ctx,
2129+
char __user *buf, size_t len, loff_t *pos)
2130+
{
2131+
struct spu_dma_info info;
2132+
2133+
spufs_get_dma_info(ctx, &info);
21082134

21092135
return simple_read_from_buffer(buf, len, pos, &info,
21102136
sizeof info);
@@ -2114,6 +2140,7 @@ static ssize_t spufs_dma_info_read(struct file *file, char __user *buf,
21142140
size_t len, loff_t *pos)
21152141
{
21162142
struct spu_context *ctx = file->private_data;
2143+
struct spu_dma_info info;
21172144
int ret;
21182145

21192146
if (!access_ok(buf, len))
@@ -2123,11 +2150,12 @@ static ssize_t spufs_dma_info_read(struct file *file, char __user *buf,
21232150
if (ret)
21242151
return ret;
21252152
spin_lock(&ctx->csa.register_lock);
2126-
ret = __spufs_dma_info_read(ctx, buf, len, pos);
2153+
spufs_get_dma_info(ctx, &info);
21272154
spin_unlock(&ctx->csa.register_lock);
21282155
spu_release_saved(ctx);
21292156

2130-
return ret;
2157+
return simple_read_from_buffer(buf, len, pos, &info,
2158+
sizeof(info));
21312159
}
21322160

21332161
static const struct file_operations spufs_dma_info_fops = {
@@ -2136,32 +2164,39 @@ static const struct file_operations spufs_dma_info_fops = {
21362164
.llseek = no_llseek,
21372165
};
21382166

2167+
static void spufs_get_proxydma_info(struct spu_context *ctx,
2168+
struct spu_proxydma_info *info)
2169+
{
2170+
int i;
2171+
2172+
info->proxydma_info_type = ctx->csa.prob.dma_querytype_RW;
2173+
info->proxydma_info_mask = ctx->csa.prob.dma_querymask_RW;
2174+
info->proxydma_info_status = ctx->csa.prob.dma_tagstatus_R;
2175+
2176+
for (i = 0; i < 8; i++) {
2177+
struct mfc_cq_sr *qp = &info->proxydma_info_command_data[i];
2178+
struct mfc_cq_sr *puqp = &ctx->csa.priv2.puq[i];
2179+
2180+
qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW;
2181+
qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW;
2182+
qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW;
2183+
qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW;
2184+
}
2185+
}
2186+
21392187
static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx,
21402188
char __user *buf, size_t len, loff_t *pos)
21412189
{
21422190
struct spu_proxydma_info info;
2143-
struct mfc_cq_sr *qp, *puqp;
21442191
int ret = sizeof info;
2145-
int i;
21462192

21472193
if (len < ret)
21482194
return -EINVAL;
21492195

21502196
if (!access_ok(buf, len))
21512197
return -EFAULT;
21522198

2153-
info.proxydma_info_type = ctx->csa.prob.dma_querytype_RW;
2154-
info.proxydma_info_mask = ctx->csa.prob.dma_querymask_RW;
2155-
info.proxydma_info_status = ctx->csa.prob.dma_tagstatus_R;
2156-
for (i = 0; i < 8; i++) {
2157-
qp = &info.proxydma_info_command_data[i];
2158-
puqp = &ctx->csa.priv2.puq[i];
2159-
2160-
qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW;
2161-
qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW;
2162-
qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW;
2163-
qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW;
2164-
}
2199+
spufs_get_proxydma_info(ctx, &info);
21652200

21662201
return simple_read_from_buffer(buf, len, pos, &info,
21672202
sizeof info);
@@ -2171,17 +2206,19 @@ static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf,
21712206
size_t len, loff_t *pos)
21722207
{
21732208
struct spu_context *ctx = file->private_data;
2209+
struct spu_proxydma_info info;
21742210
int ret;
21752211

21762212
ret = spu_acquire_saved(ctx);
21772213
if (ret)
21782214
return ret;
21792215
spin_lock(&ctx->csa.register_lock);
2180-
ret = __spufs_proxydma_info_read(ctx, buf, len, pos);
2216+
spufs_get_proxydma_info(ctx, &info);
21812217
spin_unlock(&ctx->csa.register_lock);
21822218
spu_release_saved(ctx);
21832219

2184-
return ret;
2220+
return simple_read_from_buffer(buf, len, pos, &info,
2221+
sizeof(info));
21852222
}
21862223

21872224
static const struct file_operations spufs_proxydma_info_fops = {

0 commit comments

Comments
 (0)