Re: [patch 3/3] ps3: FLASH ROM Storage Driver
From: Geert Uytterhoeven
Date: Thu Jul 19 2007 - 07:26:18 EST
Hi Andrew,
On Wed, 18 Jul 2007, Andrew Morton wrote:
> > +struct ps3flash_private {
> > + struct mutex mutex; /* Bounce buffer mutex */
> > +};
> > +#define ps3flash_priv(dev) ((dev)->sbd.core.driver_data)
>
> bzzzt!
Same defense as ps3rom ;-)
> > +static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin)
> > +{
> > + struct ps3_storage_device *dev = ps3flash_dev;
> > + u64 size = dev->regions[dev->region_idx].size*dev->blk_size;
> > +
> > + switch (origin) {
> > + case 1:
> > + offset += file->f_pos;
> > + break;
> > + case 2:
> > + offset += size;
> > + break;
> > + }
> > + if (offset < 0)
> > + return -EINVAL;
> > +
> > + file->f_pos = offset;
> > + return file->f_pos;
> > +}
>
> lseek implementations usually need locking. file->f_mapping->host->i_mutex
> would be typical.
>
> That locking mostly protects 64-bit f_pos on 32-bit architectures so you
> can perahps kinda get away with it here. However the code is a bit racy
> even on 64-bit, for silly userspace.
>
> That being said, I'd have thought that you could use one of our many
> generic lseek library fucntions here, or even an newly-exported
> block_llseek(). That assumes that i_size is correct, which I trust is the
> case.
You mean generic_file_llseek()?
Who is responsible for setting i_size in that case? This is not a file, but a
character device, so currently i_size is always zero.
So I'll just add the missing locks.
> > +static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count,
> > + loff_t *pos)
> > +{
> > + struct ps3_storage_device *dev = ps3flash_dev;
> > + struct ps3flash_private *priv = ps3flash_priv(dev);
> > + u64 size, start_sector, end_sector, offset;
> > + ssize_t sectors_read;
> > + size_t remaining, n;
> > +
> > + dev_dbg(&dev->sbd.core,
> > + "%s:%u: Reading %zu bytes at position %lld to user 0x%p\n",
> > + __func__, __LINE__, count, *pos, buf);
> > +
> > + size = dev->regions[dev->region_idx].size*dev->blk_size;
> > + if (*pos >= size || !count)
> > + return 0;
> > +
> > + if (*pos+count > size) {
> > + dev_dbg(&dev->sbd.core,
> > + "%s:%u Truncating count from %zu to %llu\n", __func__,
> > + __LINE__, count, size - *pos);
> > + count = size - *pos;
> > + }
> > +
> > + start_sector = do_div_llr(*pos, dev->blk_size, &offset);
> > + end_sector = DIV_ROUND_UP(*pos+count, dev->blk_size);
> > +
> > + remaining = count;
> > + do {
> > + mutex_lock(&priv->mutex);
> > +
> > + sectors_read = ps3flash_read_sectors(dev, start_sector,
> > + end_sector-start_sector,
> > + 0);
> > + if (sectors_read < 0) {
> > + mutex_unlock(&priv->mutex);
> > + return sectors_read;
> > + }
> > +
> > + n = min(remaining, sectors_read*dev->blk_size-offset);
> > + dev_dbg(&dev->sbd.core,
> > + "%s:%u: copy %lu bytes from 0x%p to user 0x%p\n",
> > + __func__, __LINE__, n, dev->bounce_buf+offset, buf);
> > + if (copy_to_user(buf, dev->bounce_buf+offset, n)) {
> > + mutex_unlock(&priv->mutex);
> > + return -EFAULT;
> > + }
> > +
> > + mutex_unlock(&priv->mutex);
> > +
> > + *pos += n;
> > + buf += n;
> > + remaining -= n;
> > + start_sector += sectors_read;
> > + offset = 0;
> > + } while (remaining > 0);
> > +
> > + return count;
> > +}
>
> There are several nasty deeply-embedded return points in this function.
Will change to `goto fail' and common error return.
> > + if (*pos+count > size) {
>
> checkpatch missed stuff here.
Checkpatch is silent...
> > + dev_dbg(&dev->sbd.core,
> > + "%s:%u Truncating count from %zu to %llu\n", __func__,
> > + __LINE__, count, size - *pos);
> > + count = size - *pos;
> > + }
> > +
> > + chunk_sectors = dev->bounce_size / dev->blk_size;
> > +
> > + start_write_sector = do_div_llr(*pos, dev->bounce_size, &offset) *
> > + chunk_sectors;
>
> It's strange to see a do_div_llr() in the middle of all this 64-bit-only
> code. Could use / and %?
Sure.
Note that in theory do_div_llr() could do the division and modulo in one
instruction on architectures that support that (hmm, that's div_long_long_rem).
With kind regards,
Geert Uytterhoeven
Software Architect
Sony Network and Software Technology Center Europe
The Corporate Village  Da Vincilaan 7-D1  B-1935 Zaventem  Belgium
Phone: +32 (0)2 700 8453
Fax: +32 (0)2 700 8622
E-mail: Geert.Uytterhoeven@xxxxxxxxxxx
Internet: http://www.sony-europe.com/
Sony Network and Software Technology Center Europe
A division of Sony Service Centre (Europe) N.V.
Registered office: Technologielaan 7  B-1840 Londerzeel  Belgium
VAT BE 0413.825.160 Â RPR Brussels
Fortis Bank Zaventem  Swift GEBABEBB08A  IBAN BE39001382358619