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

ioctl.c (7658B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <linux/ceph/ceph_debug.h>
      3#include <linux/in.h>
      4
      5#include "super.h"
      6#include "mds_client.h"
      7#include "ioctl.h"
      8#include <linux/ceph/striper.h>
      9
     10/*
     11 * ioctls
     12 */
     13
     14/*
     15 * get and set the file layout
     16 */
     17static long ceph_ioctl_get_layout(struct file *file, void __user *arg)
     18{
     19	struct ceph_inode_info *ci = ceph_inode(file_inode(file));
     20	struct ceph_ioctl_layout l;
     21	int err;
     22
     23	err = ceph_do_getattr(file_inode(file), CEPH_STAT_CAP_LAYOUT, false);
     24	if (!err) {
     25		l.stripe_unit = ci->i_layout.stripe_unit;
     26		l.stripe_count = ci->i_layout.stripe_count;
     27		l.object_size = ci->i_layout.object_size;
     28		l.data_pool = ci->i_layout.pool_id;
     29		l.preferred_osd = -1;
     30		if (copy_to_user(arg, &l, sizeof(l)))
     31			return -EFAULT;
     32	}
     33
     34	return err;
     35}
     36
     37static long __validate_layout(struct ceph_mds_client *mdsc,
     38			      struct ceph_ioctl_layout *l)
     39{
     40	int i, err;
     41
     42	/* validate striping parameters */
     43	if ((l->object_size & ~PAGE_MASK) ||
     44	    (l->stripe_unit & ~PAGE_MASK) ||
     45	    ((unsigned)l->stripe_unit != 0 &&
     46	     ((unsigned)l->object_size % (unsigned)l->stripe_unit)))
     47		return -EINVAL;
     48
     49	/* make sure it's a valid data pool */
     50	mutex_lock(&mdsc->mutex);
     51	err = -EINVAL;
     52	for (i = 0; i < mdsc->mdsmap->m_num_data_pg_pools; i++)
     53		if (mdsc->mdsmap->m_data_pg_pools[i] == l->data_pool) {
     54			err = 0;
     55			break;
     56		}
     57	mutex_unlock(&mdsc->mutex);
     58	if (err)
     59		return err;
     60
     61	return 0;
     62}
     63
     64static long ceph_ioctl_set_layout(struct file *file, void __user *arg)
     65{
     66	struct inode *inode = file_inode(file);
     67	struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
     68	struct ceph_mds_request *req;
     69	struct ceph_ioctl_layout l;
     70	struct ceph_inode_info *ci = ceph_inode(file_inode(file));
     71	struct ceph_ioctl_layout nl;
     72	int err;
     73
     74	if (copy_from_user(&l, arg, sizeof(l)))
     75		return -EFAULT;
     76
     77	/* validate changed params against current layout */
     78	err = ceph_do_getattr(file_inode(file), CEPH_STAT_CAP_LAYOUT, false);
     79	if (err)
     80		return err;
     81
     82	memset(&nl, 0, sizeof(nl));
     83	if (l.stripe_count)
     84		nl.stripe_count = l.stripe_count;
     85	else
     86		nl.stripe_count = ci->i_layout.stripe_count;
     87	if (l.stripe_unit)
     88		nl.stripe_unit = l.stripe_unit;
     89	else
     90		nl.stripe_unit = ci->i_layout.stripe_unit;
     91	if (l.object_size)
     92		nl.object_size = l.object_size;
     93	else
     94		nl.object_size = ci->i_layout.object_size;
     95	if (l.data_pool)
     96		nl.data_pool = l.data_pool;
     97	else
     98		nl.data_pool = ci->i_layout.pool_id;
     99
    100	/* this is obsolete, and always -1 */
    101	nl.preferred_osd = -1;
    102
    103	err = __validate_layout(mdsc, &nl);
    104	if (err)
    105		return err;
    106
    107	req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETLAYOUT,
    108				       USE_AUTH_MDS);
    109	if (IS_ERR(req))
    110		return PTR_ERR(req);
    111	req->r_inode = inode;
    112	ihold(inode);
    113	req->r_num_caps = 1;
    114
    115	req->r_inode_drop = CEPH_CAP_FILE_SHARED | CEPH_CAP_FILE_EXCL;
    116
    117	req->r_args.setlayout.layout.fl_stripe_unit =
    118		cpu_to_le32(l.stripe_unit);
    119	req->r_args.setlayout.layout.fl_stripe_count =
    120		cpu_to_le32(l.stripe_count);
    121	req->r_args.setlayout.layout.fl_object_size =
    122		cpu_to_le32(l.object_size);
    123	req->r_args.setlayout.layout.fl_pg_pool = cpu_to_le32(l.data_pool);
    124
    125	err = ceph_mdsc_do_request(mdsc, NULL, req);
    126	ceph_mdsc_put_request(req);
    127	return err;
    128}
    129
    130/*
    131 * Set a layout policy on a directory inode. All items in the tree
    132 * rooted at this inode will inherit this layout on creation,
    133 * (It doesn't apply retroactively )
    134 * unless a subdirectory has its own layout policy.
    135 */
    136static long ceph_ioctl_set_layout_policy (struct file *file, void __user *arg)
    137{
    138	struct inode *inode = file_inode(file);
    139	struct ceph_mds_request *req;
    140	struct ceph_ioctl_layout l;
    141	int err;
    142	struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
    143
    144	/* copy and validate */
    145	if (copy_from_user(&l, arg, sizeof(l)))
    146		return -EFAULT;
    147
    148	err = __validate_layout(mdsc, &l);
    149	if (err)
    150		return err;
    151
    152	req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETDIRLAYOUT,
    153				       USE_AUTH_MDS);
    154
    155	if (IS_ERR(req))
    156		return PTR_ERR(req);
    157	req->r_inode = inode;
    158	ihold(inode);
    159	req->r_num_caps = 1;
    160
    161	req->r_args.setlayout.layout.fl_stripe_unit =
    162			cpu_to_le32(l.stripe_unit);
    163	req->r_args.setlayout.layout.fl_stripe_count =
    164			cpu_to_le32(l.stripe_count);
    165	req->r_args.setlayout.layout.fl_object_size =
    166			cpu_to_le32(l.object_size);
    167	req->r_args.setlayout.layout.fl_pg_pool =
    168			cpu_to_le32(l.data_pool);
    169
    170	err = ceph_mdsc_do_request(mdsc, inode, req);
    171	ceph_mdsc_put_request(req);
    172	return err;
    173}
    174
    175/*
    176 * Return object name, size/offset information, and location (OSD
    177 * number, network address) for a given file offset.
    178 */
    179static long ceph_ioctl_get_dataloc(struct file *file, void __user *arg)
    180{
    181	struct ceph_ioctl_dataloc dl;
    182	struct inode *inode = file_inode(file);
    183	struct ceph_inode_info *ci = ceph_inode(inode);
    184	struct ceph_osd_client *osdc =
    185		&ceph_sb_to_client(inode->i_sb)->client->osdc;
    186	struct ceph_object_locator oloc;
    187	CEPH_DEFINE_OID_ONSTACK(oid);
    188	u32 xlen;
    189	u64 tmp;
    190	struct ceph_pg pgid;
    191	int r;
    192
    193	/* copy and validate */
    194	if (copy_from_user(&dl, arg, sizeof(dl)))
    195		return -EFAULT;
    196
    197	down_read(&osdc->lock);
    198	ceph_calc_file_object_mapping(&ci->i_layout, dl.file_offset, 1,
    199				      &dl.object_no, &dl.object_offset, &xlen);
    200	dl.file_offset -= dl.object_offset;
    201	dl.object_size = ci->i_layout.object_size;
    202	dl.block_size = ci->i_layout.stripe_unit;
    203
    204	/* block_offset = object_offset % block_size */
    205	tmp = dl.object_offset;
    206	dl.block_offset = do_div(tmp, dl.block_size);
    207
    208	snprintf(dl.object_name, sizeof(dl.object_name), "%llx.%08llx",
    209		 ceph_ino(inode), dl.object_no);
    210
    211	oloc.pool = ci->i_layout.pool_id;
    212	oloc.pool_ns = ceph_try_get_string(ci->i_layout.pool_ns);
    213	ceph_oid_printf(&oid, "%s", dl.object_name);
    214
    215	r = ceph_object_locator_to_pg(osdc->osdmap, &oid, &oloc, &pgid);
    216
    217	ceph_oloc_destroy(&oloc);
    218	if (r < 0) {
    219		up_read(&osdc->lock);
    220		return r;
    221	}
    222
    223	dl.osd = ceph_pg_to_acting_primary(osdc->osdmap, &pgid);
    224	if (dl.osd >= 0) {
    225		struct ceph_entity_addr *a =
    226			ceph_osd_addr(osdc->osdmap, dl.osd);
    227		if (a)
    228			memcpy(&dl.osd_addr, &a->in_addr, sizeof(dl.osd_addr));
    229	} else {
    230		memset(&dl.osd_addr, 0, sizeof(dl.osd_addr));
    231	}
    232	up_read(&osdc->lock);
    233
    234	/* send result back to user */
    235	if (copy_to_user(arg, &dl, sizeof(dl)))
    236		return -EFAULT;
    237
    238	return 0;
    239}
    240
    241static long ceph_ioctl_lazyio(struct file *file)
    242{
    243	struct ceph_file_info *fi = file->private_data;
    244	struct inode *inode = file_inode(file);
    245	struct ceph_inode_info *ci = ceph_inode(inode);
    246	struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
    247
    248	if ((fi->fmode & CEPH_FILE_MODE_LAZY) == 0) {
    249		spin_lock(&ci->i_ceph_lock);
    250		fi->fmode |= CEPH_FILE_MODE_LAZY;
    251		ci->i_nr_by_mode[ffs(CEPH_FILE_MODE_LAZY)]++;
    252		__ceph_touch_fmode(ci, mdsc, fi->fmode);
    253		spin_unlock(&ci->i_ceph_lock);
    254		dout("ioctl_layzio: file %p marked lazy\n", file);
    255
    256		ceph_check_caps(ci, 0, NULL);
    257	} else {
    258		dout("ioctl_layzio: file %p already lazy\n", file);
    259	}
    260	return 0;
    261}
    262
    263static long ceph_ioctl_syncio(struct file *file)
    264{
    265	struct ceph_file_info *fi = file->private_data;
    266
    267	fi->flags |= CEPH_F_SYNC;
    268	return 0;
    269}
    270
    271long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    272{
    273	dout("ioctl file %p cmd %u arg %lu\n", file, cmd, arg);
    274	switch (cmd) {
    275	case CEPH_IOC_GET_LAYOUT:
    276		return ceph_ioctl_get_layout(file, (void __user *)arg);
    277
    278	case CEPH_IOC_SET_LAYOUT:
    279		return ceph_ioctl_set_layout(file, (void __user *)arg);
    280
    281	case CEPH_IOC_SET_LAYOUT_POLICY:
    282		return ceph_ioctl_set_layout_policy(file, (void __user *)arg);
    283
    284	case CEPH_IOC_GET_DATALOC:
    285		return ceph_ioctl_get_dataloc(file, (void __user *)arg);
    286
    287	case CEPH_IOC_LAZYIO:
    288		return ceph_ioctl_lazyio(file);
    289
    290	case CEPH_IOC_SYNCIO:
    291		return ceph_ioctl_syncio(file);
    292	}
    293
    294	return -ENOTTY;
    295}