cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

storage_common.c (13112B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * storage_common.c -- Common definitions for mass storage functionality
      4 *
      5 * Copyright (C) 2003-2008 Alan Stern
      6 * Copyeight (C) 2009 Samsung Electronics
      7 * Author: Michal Nazarewicz (mina86@mina86.com)
      8 */
      9
     10/*
     11 * This file requires the following identifiers used in USB strings to
     12 * be defined (each of type pointer to char):
     13 *  - fsg_string_interface    -- name of the interface
     14 */
     15
     16/*
     17 * When USB_GADGET_DEBUG_FILES is defined the module param num_buffers
     18 * sets the number of pipeline buffers (length of the fsg_buffhd array).
     19 * The valid range of num_buffers is: num >= 2 && num <= 4.
     20 */
     21
     22#include <linux/module.h>
     23#include <linux/blkdev.h>
     24#include <linux/file.h>
     25#include <linux/fs.h>
     26#include <linux/usb/composite.h>
     27
     28#include "storage_common.h"
     29
     30/* There is only one interface. */
     31
     32struct usb_interface_descriptor fsg_intf_desc = {
     33	.bLength =		sizeof fsg_intf_desc,
     34	.bDescriptorType =	USB_DT_INTERFACE,
     35
     36	.bNumEndpoints =	2,		/* Adjusted during fsg_bind() */
     37	.bInterfaceClass =	USB_CLASS_MASS_STORAGE,
     38	.bInterfaceSubClass =	USB_SC_SCSI,	/* Adjusted during fsg_bind() */
     39	.bInterfaceProtocol =	USB_PR_BULK,	/* Adjusted during fsg_bind() */
     40	.iInterface =		FSG_STRING_INTERFACE,
     41};
     42EXPORT_SYMBOL_GPL(fsg_intf_desc);
     43
     44/*
     45 * Three full-speed endpoint descriptors: bulk-in, bulk-out, and
     46 * interrupt-in.
     47 */
     48
     49struct usb_endpoint_descriptor fsg_fs_bulk_in_desc = {
     50	.bLength =		USB_DT_ENDPOINT_SIZE,
     51	.bDescriptorType =	USB_DT_ENDPOINT,
     52
     53	.bEndpointAddress =	USB_DIR_IN,
     54	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
     55	/* wMaxPacketSize set by autoconfiguration */
     56};
     57EXPORT_SYMBOL_GPL(fsg_fs_bulk_in_desc);
     58
     59struct usb_endpoint_descriptor fsg_fs_bulk_out_desc = {
     60	.bLength =		USB_DT_ENDPOINT_SIZE,
     61	.bDescriptorType =	USB_DT_ENDPOINT,
     62
     63	.bEndpointAddress =	USB_DIR_OUT,
     64	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
     65	/* wMaxPacketSize set by autoconfiguration */
     66};
     67EXPORT_SYMBOL_GPL(fsg_fs_bulk_out_desc);
     68
     69struct usb_descriptor_header *fsg_fs_function[] = {
     70	(struct usb_descriptor_header *) &fsg_intf_desc,
     71	(struct usb_descriptor_header *) &fsg_fs_bulk_in_desc,
     72	(struct usb_descriptor_header *) &fsg_fs_bulk_out_desc,
     73	NULL,
     74};
     75EXPORT_SYMBOL_GPL(fsg_fs_function);
     76
     77
     78/*
     79 * USB 2.0 devices need to expose both high speed and full speed
     80 * descriptors, unless they only run at full speed.
     81 *
     82 * That means alternate endpoint descriptors (bigger packets).
     83 */
     84struct usb_endpoint_descriptor fsg_hs_bulk_in_desc = {
     85	.bLength =		USB_DT_ENDPOINT_SIZE,
     86	.bDescriptorType =	USB_DT_ENDPOINT,
     87
     88	/* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
     89	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
     90	.wMaxPacketSize =	cpu_to_le16(512),
     91};
     92EXPORT_SYMBOL_GPL(fsg_hs_bulk_in_desc);
     93
     94struct usb_endpoint_descriptor fsg_hs_bulk_out_desc = {
     95	.bLength =		USB_DT_ENDPOINT_SIZE,
     96	.bDescriptorType =	USB_DT_ENDPOINT,
     97
     98	/* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
     99	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
    100	.wMaxPacketSize =	cpu_to_le16(512),
    101	.bInterval =		1,	/* NAK every 1 uframe */
    102};
    103EXPORT_SYMBOL_GPL(fsg_hs_bulk_out_desc);
    104
    105
    106struct usb_descriptor_header *fsg_hs_function[] = {
    107	(struct usb_descriptor_header *) &fsg_intf_desc,
    108	(struct usb_descriptor_header *) &fsg_hs_bulk_in_desc,
    109	(struct usb_descriptor_header *) &fsg_hs_bulk_out_desc,
    110	NULL,
    111};
    112EXPORT_SYMBOL_GPL(fsg_hs_function);
    113
    114struct usb_endpoint_descriptor fsg_ss_bulk_in_desc = {
    115	.bLength =		USB_DT_ENDPOINT_SIZE,
    116	.bDescriptorType =	USB_DT_ENDPOINT,
    117
    118	/* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
    119	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
    120	.wMaxPacketSize =	cpu_to_le16(1024),
    121};
    122EXPORT_SYMBOL_GPL(fsg_ss_bulk_in_desc);
    123
    124struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = {
    125	.bLength =		sizeof(fsg_ss_bulk_in_comp_desc),
    126	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
    127
    128	/*.bMaxBurst =		DYNAMIC, */
    129};
    130EXPORT_SYMBOL_GPL(fsg_ss_bulk_in_comp_desc);
    131
    132struct usb_endpoint_descriptor fsg_ss_bulk_out_desc = {
    133	.bLength =		USB_DT_ENDPOINT_SIZE,
    134	.bDescriptorType =	USB_DT_ENDPOINT,
    135
    136	/* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
    137	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
    138	.wMaxPacketSize =	cpu_to_le16(1024),
    139};
    140EXPORT_SYMBOL_GPL(fsg_ss_bulk_out_desc);
    141
    142struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = {
    143	.bLength =		sizeof(fsg_ss_bulk_in_comp_desc),
    144	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
    145
    146	/*.bMaxBurst =		DYNAMIC, */
    147};
    148EXPORT_SYMBOL_GPL(fsg_ss_bulk_out_comp_desc);
    149
    150struct usb_descriptor_header *fsg_ss_function[] = {
    151	(struct usb_descriptor_header *) &fsg_intf_desc,
    152	(struct usb_descriptor_header *) &fsg_ss_bulk_in_desc,
    153	(struct usb_descriptor_header *) &fsg_ss_bulk_in_comp_desc,
    154	(struct usb_descriptor_header *) &fsg_ss_bulk_out_desc,
    155	(struct usb_descriptor_header *) &fsg_ss_bulk_out_comp_desc,
    156	NULL,
    157};
    158EXPORT_SYMBOL_GPL(fsg_ss_function);
    159
    160
    161 /*-------------------------------------------------------------------------*/
    162
    163/*
    164 * If the next two routines are called while the gadget is registered,
    165 * the caller must own fsg->filesem for writing.
    166 */
    167
    168void fsg_lun_close(struct fsg_lun *curlun)
    169{
    170	if (curlun->filp) {
    171		LDBG(curlun, "close backing file\n");
    172		fput(curlun->filp);
    173		curlun->filp = NULL;
    174	}
    175}
    176EXPORT_SYMBOL_GPL(fsg_lun_close);
    177
    178int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
    179{
    180	int				ro;
    181	struct file			*filp = NULL;
    182	int				rc = -EINVAL;
    183	struct inode			*inode = NULL;
    184	loff_t				size;
    185	loff_t				num_sectors;
    186	loff_t				min_sectors;
    187	unsigned int			blkbits;
    188	unsigned int			blksize;
    189
    190	/* R/W if we can, R/O if we must */
    191	ro = curlun->initially_ro;
    192	if (!ro) {
    193		filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0);
    194		if (PTR_ERR(filp) == -EROFS || PTR_ERR(filp) == -EACCES)
    195			ro = 1;
    196	}
    197	if (ro)
    198		filp = filp_open(filename, O_RDONLY | O_LARGEFILE, 0);
    199	if (IS_ERR(filp)) {
    200		LINFO(curlun, "unable to open backing file: %s\n", filename);
    201		return PTR_ERR(filp);
    202	}
    203
    204	if (!(filp->f_mode & FMODE_WRITE))
    205		ro = 1;
    206
    207	inode = filp->f_mapping->host;
    208	if ((!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))) {
    209		LINFO(curlun, "invalid file type: %s\n", filename);
    210		goto out;
    211	}
    212
    213	/*
    214	 * If we can't read the file, it's no good.
    215	 * If we can't write the file, use it read-only.
    216	 */
    217	if (!(filp->f_mode & FMODE_CAN_READ)) {
    218		LINFO(curlun, "file not readable: %s\n", filename);
    219		goto out;
    220	}
    221	if (!(filp->f_mode & FMODE_CAN_WRITE))
    222		ro = 1;
    223
    224	size = i_size_read(inode);
    225	if (size < 0) {
    226		LINFO(curlun, "unable to find file size: %s\n", filename);
    227		rc = (int) size;
    228		goto out;
    229	}
    230
    231	if (curlun->cdrom) {
    232		blksize = 2048;
    233		blkbits = 11;
    234	} else if (S_ISBLK(inode->i_mode)) {
    235		blksize = bdev_logical_block_size(I_BDEV(inode));
    236		blkbits = blksize_bits(blksize);
    237	} else {
    238		blksize = 512;
    239		blkbits = 9;
    240	}
    241
    242	num_sectors = size >> blkbits; /* File size in logic-block-size blocks */
    243	min_sectors = 1;
    244	if (curlun->cdrom) {
    245		min_sectors = 300;	/* Smallest track is 300 frames */
    246		if (num_sectors >= 256*60*75) {
    247			num_sectors = 256*60*75 - 1;
    248			LINFO(curlun, "file too big: %s\n", filename);
    249			LINFO(curlun, "using only first %d blocks\n",
    250					(int) num_sectors);
    251		}
    252	}
    253	if (num_sectors < min_sectors) {
    254		LINFO(curlun, "file too small: %s\n", filename);
    255		rc = -ETOOSMALL;
    256		goto out;
    257	}
    258
    259	if (fsg_lun_is_open(curlun))
    260		fsg_lun_close(curlun);
    261
    262	curlun->blksize = blksize;
    263	curlun->blkbits = blkbits;
    264	curlun->ro = ro;
    265	curlun->filp = filp;
    266	curlun->file_length = size;
    267	curlun->num_sectors = num_sectors;
    268	LDBG(curlun, "open backing file: %s\n", filename);
    269	return 0;
    270
    271out:
    272	fput(filp);
    273	return rc;
    274}
    275EXPORT_SYMBOL_GPL(fsg_lun_open);
    276
    277
    278/*-------------------------------------------------------------------------*/
    279
    280/*
    281 * Sync the file data, don't bother with the metadata.
    282 * This code was copied from fs/buffer.c:sys_fdatasync().
    283 */
    284int fsg_lun_fsync_sub(struct fsg_lun *curlun)
    285{
    286	struct file	*filp = curlun->filp;
    287
    288	if (curlun->ro || !filp)
    289		return 0;
    290	return vfs_fsync(filp, 1);
    291}
    292EXPORT_SYMBOL_GPL(fsg_lun_fsync_sub);
    293
    294void store_cdrom_address(u8 *dest, int msf, u32 addr)
    295{
    296	if (msf) {
    297		/* Convert to Minutes-Seconds-Frames */
    298		addr >>= 2;		/* Convert to 2048-byte frames */
    299		addr += 2*75;		/* Lead-in occupies 2 seconds */
    300		dest[3] = addr % 75;	/* Frames */
    301		addr /= 75;
    302		dest[2] = addr % 60;	/* Seconds */
    303		addr /= 60;
    304		dest[1] = addr;		/* Minutes */
    305		dest[0] = 0;		/* Reserved */
    306	} else {
    307		/* Absolute sector */
    308		put_unaligned_be32(addr, dest);
    309	}
    310}
    311EXPORT_SYMBOL_GPL(store_cdrom_address);
    312
    313/*-------------------------------------------------------------------------*/
    314
    315
    316ssize_t fsg_show_ro(struct fsg_lun *curlun, char *buf)
    317{
    318	return sprintf(buf, "%d\n", fsg_lun_is_open(curlun)
    319				  ? curlun->ro
    320				  : curlun->initially_ro);
    321}
    322EXPORT_SYMBOL_GPL(fsg_show_ro);
    323
    324ssize_t fsg_show_nofua(struct fsg_lun *curlun, char *buf)
    325{
    326	return sprintf(buf, "%u\n", curlun->nofua);
    327}
    328EXPORT_SYMBOL_GPL(fsg_show_nofua);
    329
    330ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem,
    331		      char *buf)
    332{
    333	char		*p;
    334	ssize_t		rc;
    335
    336	down_read(filesem);
    337	if (fsg_lun_is_open(curlun)) {	/* Get the complete pathname */
    338		p = file_path(curlun->filp, buf, PAGE_SIZE - 1);
    339		if (IS_ERR(p))
    340			rc = PTR_ERR(p);
    341		else {
    342			rc = strlen(p);
    343			memmove(buf, p, rc);
    344			buf[rc] = '\n';		/* Add a newline */
    345			buf[++rc] = 0;
    346		}
    347	} else {				/* No file, return 0 bytes */
    348		*buf = 0;
    349		rc = 0;
    350	}
    351	up_read(filesem);
    352	return rc;
    353}
    354EXPORT_SYMBOL_GPL(fsg_show_file);
    355
    356ssize_t fsg_show_cdrom(struct fsg_lun *curlun, char *buf)
    357{
    358	return sprintf(buf, "%u\n", curlun->cdrom);
    359}
    360EXPORT_SYMBOL_GPL(fsg_show_cdrom);
    361
    362ssize_t fsg_show_removable(struct fsg_lun *curlun, char *buf)
    363{
    364	return sprintf(buf, "%u\n", curlun->removable);
    365}
    366EXPORT_SYMBOL_GPL(fsg_show_removable);
    367
    368ssize_t fsg_show_inquiry_string(struct fsg_lun *curlun, char *buf)
    369{
    370	return sprintf(buf, "%s\n", curlun->inquiry_string);
    371}
    372EXPORT_SYMBOL_GPL(fsg_show_inquiry_string);
    373
    374/*
    375 * The caller must hold fsg->filesem for reading when calling this function.
    376 */
    377static ssize_t _fsg_store_ro(struct fsg_lun *curlun, bool ro)
    378{
    379	if (fsg_lun_is_open(curlun)) {
    380		LDBG(curlun, "read-only status change prevented\n");
    381		return -EBUSY;
    382	}
    383
    384	curlun->ro = ro;
    385	curlun->initially_ro = ro;
    386	LDBG(curlun, "read-only status set to %d\n", curlun->ro);
    387
    388	return 0;
    389}
    390
    391ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem,
    392		     const char *buf, size_t count)
    393{
    394	ssize_t		rc;
    395	bool		ro;
    396
    397	rc = strtobool(buf, &ro);
    398	if (rc)
    399		return rc;
    400
    401	/*
    402	 * Allow the write-enable status to change only while the
    403	 * backing file is closed.
    404	 */
    405	down_read(filesem);
    406	rc = _fsg_store_ro(curlun, ro);
    407	if (!rc)
    408		rc = count;
    409	up_read(filesem);
    410
    411	return rc;
    412}
    413EXPORT_SYMBOL_GPL(fsg_store_ro);
    414
    415ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count)
    416{
    417	bool		nofua;
    418	int		ret;
    419
    420	ret = strtobool(buf, &nofua);
    421	if (ret)
    422		return ret;
    423
    424	/* Sync data when switching from async mode to sync */
    425	if (!nofua && curlun->nofua)
    426		fsg_lun_fsync_sub(curlun);
    427
    428	curlun->nofua = nofua;
    429
    430	return count;
    431}
    432EXPORT_SYMBOL_GPL(fsg_store_nofua);
    433
    434ssize_t fsg_store_file(struct fsg_lun *curlun, struct rw_semaphore *filesem,
    435		       const char *buf, size_t count)
    436{
    437	int		rc = 0;
    438
    439	if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) {
    440		LDBG(curlun, "eject attempt prevented\n");
    441		return -EBUSY;				/* "Door is locked" */
    442	}
    443
    444	/* Remove a trailing newline */
    445	if (count > 0 && buf[count-1] == '\n')
    446		((char *) buf)[count-1] = 0;		/* Ugh! */
    447
    448	/* Load new medium */
    449	down_write(filesem);
    450	if (count > 0 && buf[0]) {
    451		/* fsg_lun_open() will close existing file if any. */
    452		rc = fsg_lun_open(curlun, buf);
    453		if (rc == 0)
    454			curlun->unit_attention_data =
    455					SS_NOT_READY_TO_READY_TRANSITION;
    456	} else if (fsg_lun_is_open(curlun)) {
    457		fsg_lun_close(curlun);
    458		curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
    459	}
    460	up_write(filesem);
    461	return (rc < 0 ? rc : count);
    462}
    463EXPORT_SYMBOL_GPL(fsg_store_file);
    464
    465ssize_t fsg_store_cdrom(struct fsg_lun *curlun, struct rw_semaphore *filesem,
    466			const char *buf, size_t count)
    467{
    468	bool		cdrom;
    469	int		ret;
    470
    471	ret = strtobool(buf, &cdrom);
    472	if (ret)
    473		return ret;
    474
    475	down_read(filesem);
    476	ret = cdrom ? _fsg_store_ro(curlun, true) : 0;
    477
    478	if (!ret) {
    479		curlun->cdrom = cdrom;
    480		ret = count;
    481	}
    482	up_read(filesem);
    483
    484	return ret;
    485}
    486EXPORT_SYMBOL_GPL(fsg_store_cdrom);
    487
    488ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf,
    489			    size_t count)
    490{
    491	bool		removable;
    492	int		ret;
    493
    494	ret = strtobool(buf, &removable);
    495	if (ret)
    496		return ret;
    497
    498	curlun->removable = removable;
    499
    500	return count;
    501}
    502EXPORT_SYMBOL_GPL(fsg_store_removable);
    503
    504ssize_t fsg_store_inquiry_string(struct fsg_lun *curlun, const char *buf,
    505				 size_t count)
    506{
    507	const size_t len = min(count, sizeof(curlun->inquiry_string));
    508
    509	if (len == 0 || buf[0] == '\n') {
    510		curlun->inquiry_string[0] = 0;
    511	} else {
    512		snprintf(curlun->inquiry_string,
    513			 sizeof(curlun->inquiry_string), "%-28s", buf);
    514		if (curlun->inquiry_string[len-1] == '\n')
    515			curlun->inquiry_string[len-1] = ' ';
    516	}
    517
    518	return count;
    519}
    520EXPORT_SYMBOL_GPL(fsg_store_inquiry_string);
    521
    522MODULE_LICENSE("GPL");