summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget/storage_common.c
diff options
context:
space:
mode:
authorMichal Nazarewicz <mina86@mina86.com>2012-06-18 14:37:20 +0200
committerFelipe Balbi <balbi@ti.com>2012-06-22 13:19:37 +0300
commitd6e16a89578fcc8834be634c85c5c5ddc2d13229 (patch)
tree0013611c5f58bf8b466ec32a315d7aef292a72a3 /drivers/usb/gadget/storage_common.c
parentf87cabf4d56e1fc5d08434df9d54ef3450a756f0 (diff)
usb: gadget: mass_storage: fail fsg_store_file() early if colud not open file
Currently, when a new value is stored to the “file” sysfs entry, fsg_store_file() will release existing backing file and only then attempt to open a new one. If that fails, no new backing file is open. This commit changes the fsg_lun_open() so that it closes existing backing file only after the new backing file has been successfully opened. With that change, fsg_store_file() may use it to perform an atomic open operation with guarantee that logical unit will either point to the new backing file or still to the old one. Signed-off-by: Michal Nazarewicz <mina86@mina86.com> Acked-by: Alan Stern <stern@rowland.harvard.edu Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/gadget/storage_common.c')
-rw-r--r--drivers/usb/gadget/storage_common.c52
1 files changed, 29 insertions, 23 deletions
diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c
index 8a8157f96a2d..e576678fb621 100644
--- a/drivers/usb/gadget/storage_common.c
+++ b/drivers/usb/gadget/storage_common.c
@@ -617,6 +617,16 @@ static struct usb_gadget_strings fsg_stringtab = {
* the caller must own fsg->filesem for writing.
*/
+static void fsg_lun_close(struct fsg_lun *curlun)
+{
+ if (curlun->filp) {
+ LDBG(curlun, "close backing file\n");
+ fput(curlun->filp);
+ curlun->filp = NULL;
+ }
+}
+
+
static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
{
int ro;
@@ -626,6 +636,8 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
loff_t size;
loff_t num_sectors;
loff_t min_sectors;
+ unsigned int blkbits;
+ unsigned int blksize;
/* R/W if we can, R/O if we must */
ro = curlun->initially_ro;
@@ -670,17 +682,17 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
}
if (curlun->cdrom) {
- curlun->blksize = 2048;
- curlun->blkbits = 11;
+ blksize = 2048;
+ blkbits = 11;
} else if (inode->i_bdev) {
- curlun->blksize = bdev_logical_block_size(inode->i_bdev);
- curlun->blkbits = blksize_bits(curlun->blksize);
+ blksize = bdev_logical_block_size(inode->i_bdev);
+ blkbits = blksize_bits(blksize);
} else {
- curlun->blksize = 512;
- curlun->blkbits = 9;
+ blksize = 512;
+ blkbits = 9;
}
- num_sectors = size >> curlun->blkbits; /* File size in logic-block-size blocks */
+ num_sectors = size >> blkbits; /* File size in logic-block-size blocks */
min_sectors = 1;
if (curlun->cdrom) {
min_sectors = 300; /* Smallest track is 300 frames */
@@ -697,7 +709,12 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
goto out;
}
+ if (fsg_lun_is_open(curlun))
+ fsg_lun_close(curlun);
+
get_file(filp);
+ curlun->blksize = blksize;
+ curlun->blkbits = blkbits;
curlun->ro = ro;
curlun->filp = filp;
curlun->file_length = size;
@@ -711,16 +728,6 @@ out:
}
-static void fsg_lun_close(struct fsg_lun *curlun)
-{
- if (curlun->filp) {
- LDBG(curlun, "close backing file\n");
- fput(curlun->filp);
- curlun->filp = NULL;
- }
-}
-
-
/*-------------------------------------------------------------------------*/
/*
@@ -871,19 +878,18 @@ static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr,
if (count > 0 && buf[count-1] == '\n')
((char *) buf)[count-1] = 0; /* Ugh! */
- /* Eject current medium */
- down_write(filesem);
- if (fsg_lun_is_open(curlun)) {
- fsg_lun_close(curlun);
- curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
- }
/* Load new medium */
+ down_write(filesem);
if (count > 0 && buf[0]) {
+ /* fsg_lun_open() will close existing file if any. */
rc = fsg_lun_open(curlun, buf);
if (rc == 0)
curlun->unit_attention_data =
SS_NOT_READY_TO_READY_TRANSITION;
+ } else if (fsg_lun_is_open(curlun)) {
+ fsg_lun_close(curlun);
+ curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
}
up_write(filesem);
return (rc < 0 ? rc : count);