Commit d6e16a89 authored by Michal Nazarewicz's avatar Michal Nazarewicz Committed by Felipe Balbi

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: default avatarMichal Nazarewicz <mina86@mina86.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent f87cabf4
...@@ -617,6 +617,16 @@ static struct usb_gadget_strings fsg_stringtab = { ...@@ -617,6 +617,16 @@ static struct usb_gadget_strings fsg_stringtab = {
* the caller must own fsg->filesem for writing. * 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) static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
{ {
int ro; int ro;
...@@ -626,6 +636,8 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename) ...@@ -626,6 +636,8 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
loff_t size; loff_t size;
loff_t num_sectors; loff_t num_sectors;
loff_t min_sectors; loff_t min_sectors;
unsigned int blkbits;
unsigned int blksize;
/* R/W if we can, R/O if we must */ /* R/W if we can, R/O if we must */
ro = curlun->initially_ro; ro = curlun->initially_ro;
...@@ -670,17 +682,17 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename) ...@@ -670,17 +682,17 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
} }
if (curlun->cdrom) { if (curlun->cdrom) {
curlun->blksize = 2048; blksize = 2048;
curlun->blkbits = 11; blkbits = 11;
} else if (inode->i_bdev) { } else if (inode->i_bdev) {
curlun->blksize = bdev_logical_block_size(inode->i_bdev); blksize = bdev_logical_block_size(inode->i_bdev);
curlun->blkbits = blksize_bits(curlun->blksize); blkbits = blksize_bits(blksize);
} else { } else {
curlun->blksize = 512; blksize = 512;
curlun->blkbits = 9; 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; min_sectors = 1;
if (curlun->cdrom) { if (curlun->cdrom) {
min_sectors = 300; /* Smallest track is 300 frames */ min_sectors = 300; /* Smallest track is 300 frames */
...@@ -697,7 +709,12 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename) ...@@ -697,7 +709,12 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
goto out; goto out;
} }
if (fsg_lun_is_open(curlun))
fsg_lun_close(curlun);
get_file(filp); get_file(filp);
curlun->blksize = blksize;
curlun->blkbits = blkbits;
curlun->ro = ro; curlun->ro = ro;
curlun->filp = filp; curlun->filp = filp;
curlun->file_length = size; curlun->file_length = size;
...@@ -711,16 +728,6 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename) ...@@ -711,16 +728,6 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
} }
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, ...@@ -871,19 +878,18 @@ static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr,
if (count > 0 && buf[count-1] == '\n') if (count > 0 && buf[count-1] == '\n')
((char *) buf)[count-1] = 0; /* Ugh! */ ((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 */ /* Load new medium */
down_write(filesem);
if (count > 0 && buf[0]) { if (count > 0 && buf[0]) {
/* fsg_lun_open() will close existing file if any. */
rc = fsg_lun_open(curlun, buf); rc = fsg_lun_open(curlun, buf);
if (rc == 0) if (rc == 0)
curlun->unit_attention_data = curlun->unit_attention_data =
SS_NOT_READY_TO_READY_TRANSITION; 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); up_write(filesem);
return (rc < 0 ? rc : count); return (rc < 0 ? rc : count);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment