-/* If the next two routines are called while the gadget is registered,
- * the caller must own fsg->filesem for writing. */
-
-static int open_backing_file(struct lun *curlun, const char *filename)
-{
- int ro;
- struct file *filp = NULL;
- int rc = -EINVAL;
- struct inode *inode = NULL;
- loff_t size;
- loff_t num_sectors;
-
- /* R/W if we can, R/O if we must */
- ro = curlun->ro;
- if (!ro) {
- filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0);
- if (-EROFS == PTR_ERR(filp))
- ro = 1;
- }
- if (ro)
- filp = filp_open(filename, O_RDONLY | O_LARGEFILE, 0);
- if (IS_ERR(filp)) {
- LINFO(curlun, "unable to open backing file: %s\n", filename);
- return PTR_ERR(filp);
- }
-
- if (!(filp->f_mode & FMODE_WRITE))
- ro = 1;
-
- if (filp->f_path.dentry)
- inode = filp->f_path.dentry->d_inode;
- if (inode && S_ISBLK(inode->i_mode)) {
- if (bdev_read_only(inode->i_bdev))
- ro = 1;
- } else if (!inode || !S_ISREG(inode->i_mode)) {
- LINFO(curlun, "invalid file type: %s\n", filename);
- goto out;
- }
-
- /* If we can't read the file, it's no good.
- * If we can't write the file, use it read-only. */
- if (!filp->f_op || !(filp->f_op->read || filp->f_op->aio_read)) {
- LINFO(curlun, "file not readable: %s\n", filename);
- goto out;
- }
- if (!(filp->f_op->write || filp->f_op->aio_write))
- ro = 1;
-
- size = i_size_read(inode->i_mapping->host);
- if (size < 0) {
- LINFO(curlun, "unable to find file size: %s\n", filename);
- rc = (int) size;
- goto out;
- }
- num_sectors = size >> 9; // File size in 512-byte sectors
- if (num_sectors == 0) {
- LINFO(curlun, "file too small: %s\n", filename);
- rc = -ETOOSMALL;
- goto out;
- }
-
- get_file(filp);
- curlun->ro = ro;
- curlun->filp = filp;
- curlun->file_length = size;
- curlun->num_sectors = num_sectors;
- LDBG(curlun, "open backing file: %s\n", filename);
- rc = 0;
-
-out:
- filp_close(filp, current->files);
- return rc;
-}
-
-
-static void close_backing_file(struct lun *curlun)
-{
- if (curlun->filp) {
- LDBG(curlun, "close backing file\n");
- fput(curlun->filp);
- curlun->filp = NULL;
- }
-}
-
-static void close_all_backing_files(struct fsg_dev *fsg)
-{
- int i;
-
- for (i = 0; i < fsg->nluns; ++i)
- close_backing_file(&fsg->luns[i]);
-}
-
-
-static ssize_t show_ro(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct lun *curlun = dev_to_lun(dev);
-
- return sprintf(buf, "%d\n", curlun->ro);
-}
-
-static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct lun *curlun = dev_to_lun(dev);
- struct fsg_dev *fsg = dev_get_drvdata(dev);
- char *p;
- ssize_t rc;
-
- down_read(&fsg->filesem);
- if (backing_file_is_open(curlun)) { // Get the complete pathname
- p = d_path(curlun->filp->f_path.dentry, curlun->filp->f_path.mnt,
- buf, PAGE_SIZE - 1);
- if (IS_ERR(p))
- rc = PTR_ERR(p);
- else {
- rc = strlen(p);
- memmove(buf, p, rc);
- buf[rc] = '\n'; // Add a newline
- buf[++rc] = 0;
- }
- } else { // No file, return 0 bytes
- *buf = 0;
- rc = 0;
- }
- up_read(&fsg->filesem);
- return rc;
-}
-
-
-static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
- ssize_t rc = count;
- struct lun *curlun = dev_to_lun(dev);
- struct fsg_dev *fsg = dev_get_drvdata(dev);
- int i;
-
- if (sscanf(buf, "%d", &i) != 1)
- return -EINVAL;
-
- /* Allow the write-enable status to change only while the backing file
- * is closed. */
- down_read(&fsg->filesem);
- if (backing_file_is_open(curlun)) {
- LDBG(curlun, "read-only status change prevented\n");
- rc = -EBUSY;
- } else {
- curlun->ro = !!i;
- LDBG(curlun, "read-only status set to %d\n", curlun->ro);
- }
- up_read(&fsg->filesem);
- return rc;
-}
-
-static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
- struct lun *curlun = dev_to_lun(dev);
- struct fsg_dev *fsg = dev_get_drvdata(dev);
- int rc = 0;
-
- if (curlun->prevent_medium_removal && backing_file_is_open(curlun)) {
- LDBG(curlun, "eject attempt prevented\n");
- return -EBUSY; // "Door is locked"
- }
-
- /* Remove a trailing newline */
- if (count > 0 && buf[count-1] == '\n')
- ((char *) buf)[count-1] = 0; // Ugh!
-
- /* Eject current medium */
- down_write(&fsg->filesem);
- if (backing_file_is_open(curlun)) {
- close_backing_file(curlun);
- curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
- }
-
- /* Load new medium */
- if (count > 0 && buf[0]) {
- rc = open_backing_file(curlun, buf);
- if (rc == 0)
- curlun->unit_attention_data =
- SS_NOT_READY_TO_READY_TRANSITION;
- }
- up_write(&fsg->filesem);
- return (rc < 0 ? rc : count);
-}
-