History

ps3: Replace direct file operations by callback

Currently the FLASH database is updated by the kernel using file operations, meant for userspace only. While this works for us because copy_{from,to}_user() on powerpc can handle kernel pointers, this is unportable and a bad example. Replace the file operations by callbacks, registered by the ps3flash driver.

Geert Uytterhoeven committed 17 years ago

Commit a4e623f1 parent 47cb9963 files · +152 −87Browse files

Unified · Split

3 files
  1. arch/powerpc/include/asm/ps3.h +7 −0
  2. arch/powerpc/platforms/ps3/os-area.c +75 −63
  3. drivers/char/ps3flash.c +70 −24
arch/powerpc/include/asm/ps3.h+7−0
@@ -53,6 +53,13 @@ enum ps3_param_av_multi_out ps3_os_area_get_av_multi_out(void); · 52 unmodified lines
53extern u64 ps3_os_area_get_rtc_diff(void);53extern u64 ps3_os_area_get_rtc_diff(void);
54extern void ps3_os_area_set_rtc_diff(u64 rtc_diff);54extern void ps3_os_area_set_rtc_diff(u64 rtc_diff);
55 55
56struct ps3_os_area_flash_ops {
57 ssize_t (*read)(void *buf, size_t count, loff_t pos);
58 ssize_t (*write)(const void *buf, size_t count, loff_t pos);
59};
60
61extern void ps3_os_area_flash_register(const struct ps3_os_area_flash_ops *ops);
62
56/* dma routines */63/* dma routines */
57 64
58enum ps3_dma_page_size {65enum ps3_dma_page_size {
arch/powerpc/platforms/ps3/os-area.c+75−63
@@ -226,6 +226,44 @@ static struct property property_av_multi_out = { · 225 unmodified lines
226 .value = &saved_params.av_multi_out,226 .value = &saved_params.av_multi_out,
227};227};
228 228
229
230static DEFINE_MUTEX(os_area_flash_mutex);
231
232static const struct ps3_os_area_flash_ops *os_area_flash_ops;
233
234void ps3_os_area_flash_register(const struct ps3_os_area_flash_ops *ops)
235{
236 mutex_lock(&os_area_flash_mutex);
237 os_area_flash_ops = ops;
238 mutex_unlock(&os_area_flash_mutex);
239}
240EXPORT_SYMBOL_GPL(ps3_os_area_flash_register);
241
242static ssize_t os_area_flash_read(void *buf, size_t count, loff_t pos)
243{
244 ssize_t res = -ENODEV;
245
246 mutex_lock(&os_area_flash_mutex);
247 if (os_area_flash_ops)
248 res = os_area_flash_ops->read(buf, count, pos);
249 mutex_unlock(&os_area_flash_mutex);
250
251 return res;
252}
253
254static ssize_t os_area_flash_write(const void *buf, size_t count, loff_t pos)
255{
256 ssize_t res = -ENODEV;
257
258 mutex_lock(&os_area_flash_mutex);
259 if (os_area_flash_ops)
260 res = os_area_flash_ops->write(buf, count, pos);
261 mutex_unlock(&os_area_flash_mutex);
262
263 return res;
264}
265
266
229/**267/**
230 * os_area_set_property - Add or overwrite a saved_params value to the device tree.268 * os_area_set_property - Add or overwrite a saved_params value to the device tree.
231 *269 *
@@ -352,12 +390,12 @@ static int db_verify(const struct os_area_db *db) · 120 unmodified lines
352 if (memcmp(db->magic_num, OS_AREA_DB_MAGIC_NUM,390 if (memcmp(db->magic_num, OS_AREA_DB_MAGIC_NUM,
353 sizeof(db->magic_num))) {391 sizeof(db->magic_num))) {
354 pr_debug("%s:%d magic_num failed\n", __func__, __LINE__);392 pr_debug("%s:%d magic_num failed\n", __func__, __LINE__);
355 return -1;393 return -EINVAL;
356 }394 }
357 395
358 if (db->version != 1) {396 if (db->version != 1) {
359 pr_debug("%s:%d version failed\n", __func__, __LINE__);397 pr_debug("%s:%d version failed\n", __func__, __LINE__);
360 return -1;398 return -EINVAL;
361 }399 }
362 400
363 return 0;401 return 0;
@@ -578,59 +616,48 @@ static void os_area_db_init(struct os_area_db *db) · 214 unmodified lines
578 *616 *
579 */617 */
580 618
581static void __maybe_unused update_flash_db(void)619static int update_flash_db(void)
582{620{
583 int result;621 const unsigned int buf_len = 8 * OS_AREA_SEGMENT_SIZE;
584 int file;622 struct os_area_header *header;
585 off_t offset;
586 ssize_t count;623 ssize_t count;
587 static const unsigned int buf_len = 8 * OS_AREA_SEGMENT_SIZE;624 int error;
588 const struct os_area_header *header;625 loff_t pos;
589 struct os_area_db* db;626 struct os_area_db* db;
590 627
591 /* Read in header and db from flash. */628 /* Read in header and db from flash. */
592 629
593 file = sys_open("/dev/ps3flash", O_RDWR, 0);
594
595 if (file < 0) {
596 pr_debug("%s:%d sys_open failed\n", __func__, __LINE__);
597 goto fail_open;
598 }
599
600 header = kmalloc(buf_len, GFP_KERNEL);630 header = kmalloc(buf_len, GFP_KERNEL);
601
602 if (!header) {631 if (!header) {
603 pr_debug("%s:%d kmalloc failed\n", __func__, __LINE__);632 pr_debug("%s: kmalloc failed\n", __func__);
604 goto fail_malloc;633 return -ENOMEM;
605 }634 }
606 635
607 offset = sys_lseek(file, 0, SEEK_SET);636 count = os_area_flash_read(header, buf_len, 0);
608 637 if (count < 0) {
609 if (offset != 0) {638 pr_debug("%s: os_area_flash_read failed %zd\n", __func__,
610 pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__);639 count);
611 goto fail_header_seek;640 error = count;
641 goto fail;
612 }642 }
613 643
614 count = sys_read(file, (char __user *)header, buf_len);644 pos = header->db_area_offset * OS_AREA_SEGMENT_SIZE;
615 645 if (count < OS_AREA_SEGMENT_SIZE || verify_header(header) ||
616 result = count < OS_AREA_SEGMENT_SIZE || verify_header(header)646 count < pos) {
617 || count < header->db_area_offset * OS_AREA_SEGMENT_SIZE;647 pr_debug("%s: verify_header failed\n", __func__);
618
619 if (result) {
620 pr_debug("%s:%d verify_header failed\n", __func__, __LINE__);
621 dump_header(header);648 dump_header(header);
622 goto fail_header;649 error = -EINVAL;
650 goto fail;
623 }651 }
624 652
625 /* Now got a good db offset and some maybe good db data. */653 /* Now got a good db offset and some maybe good db data. */
626 654
627 db = (void*)header + header->db_area_offset * OS_AREA_SEGMENT_SIZE;655 db = (void *)header + pos;
628 656
629 result = db_verify(db);657 error = db_verify(db);
630 658 if (error) {
631 if (result) {659 pr_notice("%s: Verify of flash database failed, formatting.\n",
632 printk(KERN_NOTICE "%s:%d: Verify of flash database failed, "660 __func__);
633 "formatting.\n", __func__, __LINE__);
634 dump_db(db);661 dump_db(db);
635 os_area_db_init(db);662 os_area_db_init(db);
636 }663 }
@@ -639,29 +666,16 @@ static void __maybe_unused update_flash_db(void) · 2 unmodified lines
639 666
640 db_set_64(db, &os_area_db_id_rtc_diff, saved_params.rtc_diff);667 db_set_64(db, &os_area_db_id_rtc_diff, saved_params.rtc_diff);
641 668
642 offset = sys_lseek(file, header->db_area_offset * OS_AREA_SEGMENT_SIZE,669 count = os_area_flash_write(db, sizeof(struct os_area_db), pos);
643 SEEK_SET);
644
645 if (offset != header->db_area_offset * OS_AREA_SEGMENT_SIZE) {
646 pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__);
647 goto fail_db_seek;
648 }
649
650 count = sys_write(file, (const char __user *)db,
651 sizeof(struct os_area_db));
652
653 if (count < sizeof(struct os_area_db)) {670 if (count < sizeof(struct os_area_db)) {
654 pr_debug("%s:%d sys_write failed\n", __func__, __LINE__);671 pr_debug("%s: os_area_flash_write failed %zd\n", __func__,
672 count);
673 error = count < 0 ? count : -EIO;
655 }674 }
656 675
657fail_db_seek:676fail:
658fail_header:
659fail_header_seek:
660 kfree(header);677 kfree(header);
661fail_malloc:678 return error;
662 sys_close(file);
663fail_open:
664 return;
665}679}
666 680
667/**681/**
@@ -674,11 +688,11 @@ fail_open: · 6 unmodified lines
674static void os_area_queue_work_handler(struct work_struct *work)688static void os_area_queue_work_handler(struct work_struct *work)
675{689{
676 struct device_node *node;690 struct device_node *node;
691 int error;
677 692
678 pr_debug(" -> %s:%d\n", __func__, __LINE__);693 pr_debug(" -> %s:%d\n", __func__, __LINE__);
679 694
680 node = of_find_node_by_path("/");695 node = of_find_node_by_path("/");
681
682 if (node) {696 if (node) {
683 os_area_set_property(node, &property_rtc_diff);697 os_area_set_property(node, &property_rtc_diff);
684 of_node_put(node);698 of_node_put(node);
@@ -686,12 +700,10 @@ static void os_area_queue_work_handler(struct work_struct *work) · 1 unmodified line
686 pr_debug("%s:%d of_find_node_by_path failed\n",700 pr_debug("%s:%d of_find_node_by_path failed\n",
687 __func__, __LINE__);701 __func__, __LINE__);
688 702
689#if defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE)703 error = update_flash_db();
690 update_flash_db();704 if (error)
691#else705 pr_warning("%s: Could not update FLASH ROM\n", __func__);
692 printk(KERN_WARNING "%s:%d: No flash rom driver configured.\n",706
693 __func__, __LINE__);
694#endif
695 pr_debug(" <- %s:%d\n", __func__, __LINE__);707 pr_debug(" <- %s:%d\n", __func__, __LINE__);
696}708}
697 709
drivers/char/ps3flash.c+70−24
@@ -104,18 +104,19 @@ out: · 103 unmodified lines
104 return res;104 return res;
105}105}
106 106
107static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count,107static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf,
108 loff_t *pos)108 size_t count, loff_t *pos)
109{109{
110 struct ps3_storage_device *dev = ps3flash_dev;110 struct ps3_storage_device *dev = ps3flash_dev;
111 struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);111 struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
112 u64 size, start_sector, end_sector, offset;112 u64 size, start_sector, end_sector, offset;
113 ssize_t sectors_read;113 ssize_t sectors_read;
114 size_t remaining, n;114 size_t remaining, n;
115 const void *src;
115 116
116 dev_dbg(&dev->sbd.core,117 dev_dbg(&dev->sbd.core,
117 "%s:%u: Reading %zu bytes at position %lld to user 0x%p\n",118 "%s:%u: Reading %zu bytes at position %lld to U0x%p/K0x%p\n",
118 __func__, __LINE__, count, *pos, buf);119 __func__, __LINE__, count, *pos, userbuf, kernelbuf);
119 120
120 size = dev->regions[dev->region_idx].size*dev->blk_size;121 size = dev->regions[dev->region_idx].size*dev->blk_size;
121 if (*pos >= size || !count)122 if (*pos >= size || !count)
@@ -145,19 +146,26 @@ static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count, · 23 unmodified lines
145 }146 }
146 147
147 n = min_t(u64, remaining, sectors_read*dev->blk_size-offset);148 n = min_t(u64, remaining, sectors_read*dev->blk_size-offset);
149 src = dev->bounce_buf+offset;
148 dev_dbg(&dev->sbd.core,150 dev_dbg(&dev->sbd.core,
149 "%s:%u: copy %lu bytes from 0x%p to user 0x%p\n",151 "%s:%u: copy %lu bytes from 0x%p to U0x%p/K0x%p\n",
150 __func__, __LINE__, n, dev->bounce_buf+offset, buf);152 __func__, __LINE__, n, src, userbuf, kernelbuf);
151 if (copy_to_user(buf, dev->bounce_buf+offset, n)) {153 if (userbuf) {
152 mutex_unlock(&priv->mutex);154 if (copy_to_user(userbuf, src, n)) {
153 sectors_read = -EFAULT;155 mutex_unlock(&priv->mutex);
154 goto fail;156 sectors_read = -EFAULT;
157 goto fail;
158 }
159 userbuf += n;
160 }
161 if (kernelbuf) {
162 memcpy(kernelbuf, src, n);
163 kernelbuf += n;
155 }164 }
156 165
157 mutex_unlock(&priv->mutex);166 mutex_unlock(&priv->mutex);
158 167
159 *pos += n;168 *pos += n;
160 buf += n;
161 remaining -= n;169 remaining -= n;
162 start_sector += sectors_read;170 start_sector += sectors_read;
163 offset = 0;171 offset = 0;
@@ -169,8 +177,8 @@ fail: · 5 unmodified lines
169 return sectors_read;177 return sectors_read;
170}178}
171 179
172static ssize_t ps3flash_write(struct file *file, const char __user *buf,180static ssize_t ps3flash_write(const char __user *userbuf,
173 size_t count, loff_t *pos)181 const void *kernelbuf, size_t count, loff_t *pos)
174{182{
175 struct ps3_storage_device *dev = ps3flash_dev;183 struct ps3_storage_device *dev = ps3flash_dev;
176 struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);184 struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
@@ -179,10 +187,11 @@ static ssize_t ps3flash_write(struct file *file, const char __user *buf, · 2 unmodified lines
179 ssize_t res;187 ssize_t res;
180 size_t remaining, n;188 size_t remaining, n;
181 unsigned int sec_off;189 unsigned int sec_off;
190 void *dst;
182 191
183 dev_dbg(&dev->sbd.core,192 dev_dbg(&dev->sbd.core,
184 "%s:%u: Writing %zu bytes at position %lld from user 0x%p\n",193 "%s:%u: Writing %zu bytes at position %lld from U0x%p/K0x%p\n",
185 __func__, __LINE__, count, *pos, buf);194 __func__, __LINE__, count, *pos, userbuf, kernelbuf);
186 195
187 size = dev->regions[dev->region_idx].size*dev->blk_size;196 size = dev->regions[dev->region_idx].size*dev->blk_size;
188 if (*pos >= size || !count)197 if (*pos >= size || !count)
@@ -259,12 +268,20 @@ static ssize_t ps3flash_write(struct file *file, const char __user *buf, · 70 unmodified lines
259 }268 }
260 269
261 n = min_t(u64, remaining, dev->bounce_size-offset);270 n = min_t(u64, remaining, dev->bounce_size-offset);
271 dst = dev->bounce_buf+offset;
262 dev_dbg(&dev->sbd.core,272 dev_dbg(&dev->sbd.core,
263 "%s:%u: copy %lu bytes from user 0x%p to 0x%p\n",273 "%s:%u: copy %lu bytes from U0x%p/K0x%p to 0x%p\n",
264 __func__, __LINE__, n, buf, dev->bounce_buf+offset);274 __func__, __LINE__, n, userbuf, kernelbuf, dst);
265 if (copy_from_user(dev->bounce_buf+offset, buf, n)) {275 if (userbuf) {
266 res = -EFAULT;276 if (copy_from_user(dst, userbuf, n)) {
267 goto fail;277 res = -EFAULT;
278 goto fail;
279 }
280 userbuf += n;
281 }
282 if (kernelbuf) {
283 memcpy(dst, kernelbuf, n);
284 kernelbuf += n;
268 }285 }
269 286
270 res = ps3flash_write_chunk(dev, start_write_sector);287 res = ps3flash_write_chunk(dev, start_write_sector);
@@ -274,7 +291,6 @@ static ssize_t ps3flash_write(struct file *file, const char __user *buf, · 3 unmodified lines
274 mutex_unlock(&priv->mutex);291 mutex_unlock(&priv->mutex);
275 292
276 *pos += n;293 *pos += n;
277 buf += n;
278 remaining -= n;294 remaining -= n;
279 start_write_sector += chunk_sectors;295 start_write_sector += chunk_sectors;
280 head = 0;296 head = 0;
@@ -288,6 +304,29 @@ fail: · 7 unmodified lines
288 return res;304 return res;
289}305}
290 306
307static ssize_t ps3flash_user_read(struct file *file, char __user *buf,
308 size_t count, loff_t *pos)
309{
310 return ps3flash_read(buf, NULL, count, pos);
311}
312
313static ssize_t ps3flash_user_write(struct file *file, const char __user *buf,
314 size_t count, loff_t *pos)
315{
316 return ps3flash_write(buf, NULL, count, pos);
317}
318
319static ssize_t ps3flash_kernel_read(void *buf, size_t count, loff_t pos)
320{
321 return ps3flash_read(NULL, buf, count, &pos);
322}
323
324static ssize_t ps3flash_kernel_write(const void *buf, size_t count,
325 loff_t pos)
326{
327 return ps3flash_write(NULL, buf, count, &pos);
328}
329
291 330
292static irqreturn_t ps3flash_interrupt(int irq, void *data)331static irqreturn_t ps3flash_interrupt(int irq, void *data)
293{332{
@@ -312,12 +351,16 @@ static irqreturn_t ps3flash_interrupt(int irq, void *data) · 18 unmodified lines
312 return IRQ_HANDLED;351 return IRQ_HANDLED;
313}352}
314 353
315
316static const struct file_operations ps3flash_fops = {354static const struct file_operations ps3flash_fops = {
317 .owner = THIS_MODULE,355 .owner = THIS_MODULE,
318 .llseek = ps3flash_llseek,356 .llseek = ps3flash_llseek,
319 .read = ps3flash_read,357 .read = ps3flash_user_read,
320 .write = ps3flash_write,358 .write = ps3flash_user_write,
359};
360
361static const struct ps3_os_area_flash_ops ps3flash_kernel_ops = {
362 .read = ps3flash_kernel_read,
363 .write = ps3flash_kernel_write,
321};364};
322 365
323static struct miscdevice ps3flash_misc = {366static struct miscdevice ps3flash_misc = {
@@ -386,6 +429,8 @@ static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev) · 62 unmodified lines
386 429
387 dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n",430 dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n",
388 __func__, __LINE__, ps3flash_misc.minor);431 __func__, __LINE__, ps3flash_misc.minor);
432
433 ps3_os_area_flash_register(&ps3flash_kernel_ops);
389 return 0;434 return 0;
390 435
391fail_teardown:436fail_teardown:
@@ -402,6 +447,7 @@ static int ps3flash_remove(struct ps3_system_bus_device *_dev) · 10 unmodified lines
402{447{
403 struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);448 struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
404 449
450 ps3_os_area_flash_register(NULL);
405 misc_deregister(&ps3flash_misc);451 misc_deregister(&ps3flash_misc);
406 ps3stor_teardown(dev);452 ps3stor_teardown(dev);
407 kfree(ps3_system_bus_get_drvdata(&dev->sbd));453 kfree(ps3_system_bus_get_drvdata(&dev->sbd));