brintos

brintos / linux-shallow public Read only

0
0
Text · 10.9 KiB · e861de3 Raw
426 lines · c
1// SPDX-License-Identifier: GPL-2.02#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#include <linux/fscrypt.h>10 11/*12 * ioctls13 */14 15/*16 * get and set the file layout17 */18static long ceph_ioctl_get_layout(struct file *file, void __user *arg)19{20	struct ceph_inode_info *ci = ceph_inode(file_inode(file));21	struct ceph_ioctl_layout l;22	int err;23 24	err = ceph_do_getattr(file_inode(file), CEPH_STAT_CAP_LAYOUT, false);25	if (!err) {26		l.stripe_unit = ci->i_layout.stripe_unit;27		l.stripe_count = ci->i_layout.stripe_count;28		l.object_size = ci->i_layout.object_size;29		l.data_pool = ci->i_layout.pool_id;30		l.preferred_osd = -1;31		if (copy_to_user(arg, &l, sizeof(l)))32			return -EFAULT;33	}34 35	return err;36}37 38static long __validate_layout(struct ceph_mds_client *mdsc,39			      struct ceph_ioctl_layout *l)40{41	int i, err;42 43	/* validate striping parameters */44	if ((l->object_size & ~PAGE_MASK) ||45	    (l->stripe_unit & ~PAGE_MASK) ||46	    ((unsigned)l->stripe_unit != 0 &&47	     ((unsigned)l->object_size % (unsigned)l->stripe_unit)))48		return -EINVAL;49 50	/* make sure it's a valid data pool */51	mutex_lock(&mdsc->mutex);52	err = -EINVAL;53	for (i = 0; i < mdsc->mdsmap->m_num_data_pg_pools; i++)54		if (mdsc->mdsmap->m_data_pg_pools[i] == l->data_pool) {55			err = 0;56			break;57		}58	mutex_unlock(&mdsc->mutex);59	if (err)60		return err;61 62	return 0;63}64 65static long ceph_ioctl_set_layout(struct file *file, void __user *arg)66{67	struct inode *inode = file_inode(file);68	struct ceph_mds_client *mdsc = ceph_sb_to_fs_client(inode->i_sb)->mdsc;69	struct ceph_mds_request *req;70	struct ceph_ioctl_layout l;71	struct ceph_inode_info *ci = ceph_inode(file_inode(file));72	struct ceph_ioctl_layout nl;73	int err;74 75	if (copy_from_user(&l, arg, sizeof(l)))76		return -EFAULT;77 78	/* validate changed params against current layout */79	err = ceph_do_getattr(file_inode(file), CEPH_STAT_CAP_LAYOUT, false);80	if (err)81		return err;82 83	memset(&nl, 0, sizeof(nl));84	if (l.stripe_count)85		nl.stripe_count = l.stripe_count;86	else87		nl.stripe_count = ci->i_layout.stripe_count;88	if (l.stripe_unit)89		nl.stripe_unit = l.stripe_unit;90	else91		nl.stripe_unit = ci->i_layout.stripe_unit;92	if (l.object_size)93		nl.object_size = l.object_size;94	else95		nl.object_size = ci->i_layout.object_size;96	if (l.data_pool)97		nl.data_pool = l.data_pool;98	else99		nl.data_pool = ci->i_layout.pool_id;100 101	/* this is obsolete, and always -1 */102	nl.preferred_osd = -1;103 104	err = __validate_layout(mdsc, &nl);105	if (err)106		return err;107 108	req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETLAYOUT,109				       USE_AUTH_MDS);110	if (IS_ERR(req))111		return PTR_ERR(req);112	req->r_inode = inode;113	ihold(inode);114	req->r_num_caps = 1;115 116	req->r_inode_drop = CEPH_CAP_FILE_SHARED | CEPH_CAP_FILE_EXCL;117 118	req->r_args.setlayout.layout.fl_stripe_unit =119		cpu_to_le32(l.stripe_unit);120	req->r_args.setlayout.layout.fl_stripe_count =121		cpu_to_le32(l.stripe_count);122	req->r_args.setlayout.layout.fl_object_size =123		cpu_to_le32(l.object_size);124	req->r_args.setlayout.layout.fl_pg_pool = cpu_to_le32(l.data_pool);125 126	err = ceph_mdsc_do_request(mdsc, NULL, req);127	ceph_mdsc_put_request(req);128	return err;129}130 131/*132 * Set a layout policy on a directory inode. All items in the tree133 * rooted at this inode will inherit this layout on creation,134 * (It doesn't apply retroactively )135 * unless a subdirectory has its own layout policy.136 */137static long ceph_ioctl_set_layout_policy (struct file *file, void __user *arg)138{139	struct inode *inode = file_inode(file);140	struct ceph_mds_request *req;141	struct ceph_ioctl_layout l;142	int err;143	struct ceph_mds_client *mdsc = ceph_sb_to_fs_client(inode->i_sb)->mdsc;144 145	/* copy and validate */146	if (copy_from_user(&l, arg, sizeof(l)))147		return -EFAULT;148 149	err = __validate_layout(mdsc, &l);150	if (err)151		return err;152 153	req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETDIRLAYOUT,154				       USE_AUTH_MDS);155 156	if (IS_ERR(req))157		return PTR_ERR(req);158	req->r_inode = inode;159	ihold(inode);160	req->r_num_caps = 1;161 162	req->r_args.setlayout.layout.fl_stripe_unit =163			cpu_to_le32(l.stripe_unit);164	req->r_args.setlayout.layout.fl_stripe_count =165			cpu_to_le32(l.stripe_count);166	req->r_args.setlayout.layout.fl_object_size =167			cpu_to_le32(l.object_size);168	req->r_args.setlayout.layout.fl_pg_pool =169			cpu_to_le32(l.data_pool);170 171	err = ceph_mdsc_do_request(mdsc, inode, req);172	ceph_mdsc_put_request(req);173	return err;174}175 176/*177 * Return object name, size/offset information, and location (OSD178 * number, network address) for a given file offset.179 */180static long ceph_ioctl_get_dataloc(struct file *file, void __user *arg)181{182	struct ceph_ioctl_dataloc dl;183	struct inode *inode = file_inode(file);184	struct ceph_inode_info *ci = ceph_inode(inode);185	struct ceph_osd_client *osdc =186		&ceph_sb_to_fs_client(inode->i_sb)->client->osdc;187	struct ceph_object_locator oloc;188	CEPH_DEFINE_OID_ONSTACK(oid);189	u32 xlen;190	u64 tmp;191	struct ceph_pg pgid;192	int r;193 194	/* copy and validate */195	if (copy_from_user(&dl, arg, sizeof(dl)))196		return -EFAULT;197 198	down_read(&osdc->lock);199	ceph_calc_file_object_mapping(&ci->i_layout, dl.file_offset, 1,200				      &dl.object_no, &dl.object_offset, &xlen);201	dl.file_offset -= dl.object_offset;202	dl.object_size = ci->i_layout.object_size;203	dl.block_size = ci->i_layout.stripe_unit;204 205	/* block_offset = object_offset % block_size */206	tmp = dl.object_offset;207	dl.block_offset = do_div(tmp, dl.block_size);208 209	snprintf(dl.object_name, sizeof(dl.object_name), "%llx.%08llx",210		 ceph_ino(inode), dl.object_no);211 212	oloc.pool = ci->i_layout.pool_id;213	oloc.pool_ns = ceph_try_get_string(ci->i_layout.pool_ns);214	ceph_oid_printf(&oid, "%s", dl.object_name);215 216	r = ceph_object_locator_to_pg(osdc->osdmap, &oid, &oloc, &pgid);217 218	ceph_oloc_destroy(&oloc);219	if (r < 0) {220		up_read(&osdc->lock);221		return r;222	}223 224	dl.osd = ceph_pg_to_acting_primary(osdc->osdmap, &pgid);225	if (dl.osd >= 0) {226		struct ceph_entity_addr *a =227			ceph_osd_addr(osdc->osdmap, dl.osd);228		if (a)229			memcpy(&dl.osd_addr, &a->in_addr, sizeof(dl.osd_addr));230	} else {231		memset(&dl.osd_addr, 0, sizeof(dl.osd_addr));232	}233	up_read(&osdc->lock);234 235	/* send result back to user */236	if (copy_to_user(arg, &dl, sizeof(dl)))237		return -EFAULT;238 239	return 0;240}241 242static long ceph_ioctl_lazyio(struct file *file)243{244	struct ceph_file_info *fi = file->private_data;245	struct inode *inode = file_inode(file);246	struct ceph_inode_info *ci = ceph_inode(inode);247	struct ceph_mds_client *mdsc = ceph_inode_to_fs_client(inode)->mdsc;248	struct ceph_client *cl = mdsc->fsc->client;249 250	if ((fi->fmode & CEPH_FILE_MODE_LAZY) == 0) {251		spin_lock(&ci->i_ceph_lock);252		fi->fmode |= CEPH_FILE_MODE_LAZY;253		ci->i_nr_by_mode[ffs(CEPH_FILE_MODE_LAZY)]++;254		__ceph_touch_fmode(ci, mdsc, fi->fmode);255		spin_unlock(&ci->i_ceph_lock);256		doutc(cl, "file %p %p %llx.%llx marked lazy\n", file, inode,257		      ceph_vinop(inode));258 259		ceph_check_caps(ci, 0);260	} else {261		doutc(cl, "file %p %p %llx.%llx already lazy\n", file, inode,262		      ceph_vinop(inode));263	}264	return 0;265}266 267static long ceph_ioctl_syncio(struct file *file)268{269	struct ceph_file_info *fi = file->private_data;270 271	fi->flags |= CEPH_F_SYNC;272	return 0;273}274 275static int vet_mds_for_fscrypt(struct file *file)276{277	int i, ret = -EOPNOTSUPP;278	struct ceph_mds_client	*mdsc = ceph_sb_to_mdsc(file_inode(file)->i_sb);279 280	mutex_lock(&mdsc->mutex);281	for (i = 0; i < mdsc->max_sessions; i++) {282		struct ceph_mds_session *s = mdsc->sessions[i];283 284		if (!s)285			continue;286		if (test_bit(CEPHFS_FEATURE_ALTERNATE_NAME, &s->s_features))287			ret = 0;288		break;289	}290	mutex_unlock(&mdsc->mutex);291	return ret;292}293 294static long ceph_set_encryption_policy(struct file *file, unsigned long arg)295{296	int ret, got = 0;297	struct inode *inode = file_inode(file);298	struct ceph_inode_info *ci = ceph_inode(inode);299 300	/* encrypted directories can't have striped layout */301	if (ci->i_layout.stripe_count > 1)302		return -EINVAL;303 304	ret = vet_mds_for_fscrypt(file);305	if (ret)306		return ret;307 308	/*309	 * Ensure we hold these caps so that we _know_ that the rstats check310	 * in the empty_dir check is reliable.311	 */312	ret = ceph_get_caps(file, CEPH_CAP_FILE_SHARED, 0, -1, &got);313	if (ret)314		return ret;315 316	ret = fscrypt_ioctl_set_policy(file, (const void __user *)arg);317	if (got)318		ceph_put_cap_refs(ci, got);319 320	return ret;321}322 323static const char *ceph_ioctl_cmd_name(const unsigned int cmd)324{325	switch (cmd) {326	case CEPH_IOC_GET_LAYOUT:327		return "get_layout";328	case CEPH_IOC_SET_LAYOUT:329		return "set_layout";330	case CEPH_IOC_SET_LAYOUT_POLICY:331		return "set_layout_policy";332	case CEPH_IOC_GET_DATALOC:333		return "get_dataloc";334	case CEPH_IOC_LAZYIO:335		return "lazyio";336	case CEPH_IOC_SYNCIO:337		return "syncio";338	case FS_IOC_SET_ENCRYPTION_POLICY:339		return "set_encryption_policy";340	case FS_IOC_GET_ENCRYPTION_POLICY:341		return "get_encryption_policy";342	case FS_IOC_GET_ENCRYPTION_POLICY_EX:343		return "get_encryption_policy_ex";344	case FS_IOC_ADD_ENCRYPTION_KEY:345		return "add_encryption_key";346	case FS_IOC_REMOVE_ENCRYPTION_KEY:347		return "remove_encryption_key";348	case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS:349		return "remove_encryption_key_all_users";350	case FS_IOC_GET_ENCRYPTION_KEY_STATUS:351		return "get_encryption_key_status";352	case FS_IOC_GET_ENCRYPTION_NONCE:353		return "get_encryption_nonce";354	default:355		return "unknown";356	}357}358 359long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg)360{361	struct inode *inode = file_inode(file);362	struct ceph_fs_client *fsc = ceph_inode_to_fs_client(inode);363	int ret;364 365	doutc(fsc->client, "file %p %p %llx.%llx cmd %s arg %lu\n", file,366	      inode, ceph_vinop(inode), ceph_ioctl_cmd_name(cmd), arg);367	switch (cmd) {368	case CEPH_IOC_GET_LAYOUT:369		return ceph_ioctl_get_layout(file, (void __user *)arg);370 371	case CEPH_IOC_SET_LAYOUT:372		return ceph_ioctl_set_layout(file, (void __user *)arg);373 374	case CEPH_IOC_SET_LAYOUT_POLICY:375		return ceph_ioctl_set_layout_policy(file, (void __user *)arg);376 377	case CEPH_IOC_GET_DATALOC:378		return ceph_ioctl_get_dataloc(file, (void __user *)arg);379 380	case CEPH_IOC_LAZYIO:381		return ceph_ioctl_lazyio(file);382 383	case CEPH_IOC_SYNCIO:384		return ceph_ioctl_syncio(file);385 386	case FS_IOC_SET_ENCRYPTION_POLICY:387		return ceph_set_encryption_policy(file, arg);388 389	case FS_IOC_GET_ENCRYPTION_POLICY:390		ret = vet_mds_for_fscrypt(file);391		if (ret)392			return ret;393		return fscrypt_ioctl_get_policy(file, (void __user *)arg);394 395	case FS_IOC_GET_ENCRYPTION_POLICY_EX:396		ret = vet_mds_for_fscrypt(file);397		if (ret)398			return ret;399		return fscrypt_ioctl_get_policy_ex(file, (void __user *)arg);400 401	case FS_IOC_ADD_ENCRYPTION_KEY:402		ret = vet_mds_for_fscrypt(file);403		if (ret)404			return ret;405		return fscrypt_ioctl_add_key(file, (void __user *)arg);406 407	case FS_IOC_REMOVE_ENCRYPTION_KEY:408		return fscrypt_ioctl_remove_key(file, (void __user *)arg);409 410	case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS:411		return fscrypt_ioctl_remove_key_all_users(file,412							  (void __user *)arg);413 414	case FS_IOC_GET_ENCRYPTION_KEY_STATUS:415		return fscrypt_ioctl_get_key_status(file, (void __user *)arg);416 417	case FS_IOC_GET_ENCRYPTION_NONCE:418		ret = vet_mds_for_fscrypt(file);419		if (ret)420			return ret;421		return fscrypt_ioctl_get_nonce(file, (void __user *)arg);422	}423 424	return -ENOTTY;425}426