usb: gadget: mass_storage: fail fsg_store_file() early if colud not open file
authorMichal Nazarewicz <mina86@mina86.com>
Mon, 18 Jun 2012 12:37:20 +0000 (14:37 +0200)
committerFelipe Balbi <balbi@ti.com>
Fri, 22 Jun 2012 10:19:37 +0000 (13:19 +0300)
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>
drivers/usb/gadget/storage_common.c

index 8a8157f..e576678 100644 (file)
@@ -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);