ioctl.c 7.6 KB
Newer Older
S
Sage Weil 已提交
1 2 3
#include <linux/in.h>

#include "super.h"
4 5 6 7
#include "mds_client.h"
#include <linux/ceph/ceph_debug.h>

#include "ioctl.h"
S
Sage Weil 已提交
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28


/*
 * ioctls
 */

/*
 * get and set the file layout
 */
static long ceph_ioctl_get_layout(struct file *file, void __user *arg)
{
	struct ceph_inode_info *ci = ceph_inode(file->f_dentry->d_inode);
	struct ceph_ioctl_layout l;
	int err;

	err = ceph_do_getattr(file->f_dentry->d_inode, CEPH_STAT_CAP_LAYOUT);
	if (!err) {
		l.stripe_unit = ceph_file_layout_su(ci->i_layout);
		l.stripe_count = ceph_file_layout_stripe_count(ci->i_layout);
		l.object_size = ceph_file_layout_object_size(ci->i_layout);
		l.data_pool = le32_to_cpu(ci->i_layout.fl_pg_pool);
29
		l.preferred_osd = (s32)-1;
S
Sage Weil 已提交
30 31 32 33 34 35 36 37 38 39
		if (copy_to_user(arg, &l, sizeof(l)))
			return -EFAULT;
	}

	return err;
}

static long ceph_ioctl_set_layout(struct file *file, void __user *arg)
{
	struct inode *inode = file->f_dentry->d_inode;
S
Sage Weil 已提交
40
	struct inode *parent_inode;
41
	struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
S
Sage Weil 已提交
42 43
	struct ceph_mds_request *req;
	struct ceph_ioctl_layout l;
44 45
	struct ceph_inode_info *ci = ceph_inode(file->f_dentry->d_inode);
	struct ceph_ioctl_layout nl;
S
Sage Weil 已提交
46 47 48 49 50
	int err, i;

	if (copy_from_user(&l, arg, sizeof(l)))
		return -EFAULT;

51 52 53 54
	/* preferred_osd is no longer supported */
	if (l.preferred_osd != -1)
		return -EINVAL;

55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
	/* validate changed params against current layout */
	err = ceph_do_getattr(file->f_dentry->d_inode, CEPH_STAT_CAP_LAYOUT);
	if (!err) {
		nl.stripe_unit = ceph_file_layout_su(ci->i_layout);
		nl.stripe_count = ceph_file_layout_stripe_count(ci->i_layout);
		nl.object_size = ceph_file_layout_object_size(ci->i_layout);
		nl.data_pool = le32_to_cpu(ci->i_layout.fl_pg_pool);
	} else
		return err;

	if (l.stripe_count)
		nl.stripe_count = l.stripe_count;
	if (l.stripe_unit)
		nl.stripe_unit = l.stripe_unit;
	if (l.object_size)
		nl.object_size = l.object_size;
	if (l.data_pool)
		nl.data_pool = l.data_pool;

	if ((nl.object_size & ~PAGE_MASK) ||
	    (nl.stripe_unit & ~PAGE_MASK) ||
	    ((unsigned)nl.object_size % (unsigned)nl.stripe_unit))
S
Sage Weil 已提交
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
		return -EINVAL;

	/* make sure it's a valid data pool */
	if (l.data_pool > 0) {
		mutex_lock(&mdsc->mutex);
		err = -EINVAL;
		for (i = 0; i < mdsc->mdsmap->m_num_data_pg_pools; i++)
			if (mdsc->mdsmap->m_data_pg_pools[i] == l.data_pool) {
				err = 0;
				break;
			}
		mutex_unlock(&mdsc->mutex);
		if (err)
			return err;
	}

	req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETLAYOUT,
				       USE_AUTH_MDS);
	if (IS_ERR(req))
		return PTR_ERR(req);
97 98
	req->r_inode = inode;
	ihold(inode);
S
Sage Weil 已提交
99 100 101 102 103 104 105 106 107 108
	req->r_inode_drop = CEPH_CAP_FILE_SHARED | CEPH_CAP_FILE_EXCL;

	req->r_args.setlayout.layout.fl_stripe_unit =
		cpu_to_le32(l.stripe_unit);
	req->r_args.setlayout.layout.fl_stripe_count =
		cpu_to_le32(l.stripe_count);
	req->r_args.setlayout.layout.fl_object_size =
		cpu_to_le32(l.object_size);
	req->r_args.setlayout.layout.fl_pg_pool = cpu_to_le32(l.data_pool);

S
Sage Weil 已提交
109
	parent_inode = ceph_get_dentry_parent_inode(file->f_dentry);
S
Sage Weil 已提交
110
	err = ceph_mdsc_do_request(mdsc, parent_inode, req);
S
Sage Weil 已提交
111
	iput(parent_inode);
S
Sage Weil 已提交
112 113 114 115
	ceph_mdsc_put_request(req);
	return err;
}

116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
/*
 * Set a layout policy on a directory inode. All items in the tree
 * rooted at this inode will inherit this layout on creation,
 * (It doesn't apply retroactively )
 * unless a subdirectory has its own layout policy.
 */
static long ceph_ioctl_set_layout_policy (struct file *file, void __user *arg)
{
	struct inode *inode = file->f_dentry->d_inode;
	struct ceph_mds_request *req;
	struct ceph_ioctl_layout l;
	int err, i;
	struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;

	/* copy and validate */
	if (copy_from_user(&l, arg, sizeof(l)))
		return -EFAULT;

	if ((l.object_size & ~PAGE_MASK) ||
	    (l.stripe_unit & ~PAGE_MASK) ||
	    !l.stripe_unit ||
	    (l.object_size &&
	        (unsigned)l.object_size % (unsigned)l.stripe_unit))
		return -EINVAL;

	/* make sure it's a valid data pool */
	if (l.data_pool > 0) {
		mutex_lock(&mdsc->mutex);
		err = -EINVAL;
		for (i = 0; i < mdsc->mdsmap->m_num_data_pg_pools; i++)
			if (mdsc->mdsmap->m_data_pg_pools[i] == l.data_pool) {
				err = 0;
				break;
			}
		mutex_unlock(&mdsc->mutex);
		if (err)
			return err;
	}

	req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETDIRLAYOUT,
				       USE_AUTH_MDS);

	if (IS_ERR(req))
		return PTR_ERR(req);
160 161
	req->r_inode = inode;
	ihold(inode);
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176

	req->r_args.setlayout.layout.fl_stripe_unit =
			cpu_to_le32(l.stripe_unit);
	req->r_args.setlayout.layout.fl_stripe_count =
			cpu_to_le32(l.stripe_count);
	req->r_args.setlayout.layout.fl_object_size =
			cpu_to_le32(l.object_size);
	req->r_args.setlayout.layout.fl_pg_pool =
			cpu_to_le32(l.data_pool);

	err = ceph_mdsc_do_request(mdsc, inode, req);
	ceph_mdsc_put_request(req);
	return err;
}

S
Sage Weil 已提交
177 178 179 180 181 182 183 184 185
/*
 * Return object name, size/offset information, and location (OSD
 * number, network address) for a given file offset.
 */
static long ceph_ioctl_get_dataloc(struct file *file, void __user *arg)
{
	struct ceph_ioctl_dataloc dl;
	struct inode *inode = file->f_dentry->d_inode;
	struct ceph_inode_info *ci = ceph_inode(inode);
186 187
	struct ceph_osd_client *osdc =
		&ceph_sb_to_client(inode->i_sb)->client->osdc;
S
Sage Weil 已提交
188 189 190
	u64 len = 1, olen;
	u64 tmp;
	struct ceph_object_layout ol;
191
	struct ceph_pg pgid;
S
Sage Weil 已提交
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212

	/* copy and validate */
	if (copy_from_user(&dl, arg, sizeof(dl)))
		return -EFAULT;

	down_read(&osdc->map_sem);
	ceph_calc_file_object_mapping(&ci->i_layout, dl.file_offset, &len,
				      &dl.object_no, &dl.object_offset, &olen);
	dl.file_offset -= dl.object_offset;
	dl.object_size = ceph_file_layout_object_size(ci->i_layout);
	dl.block_size = ceph_file_layout_su(ci->i_layout);

	/* block_offset = object_offset % block_size */
	tmp = dl.object_offset;
	dl.block_offset = do_div(tmp, dl.block_size);

	snprintf(dl.object_name, sizeof(dl.object_name), "%llx.%08llx",
		 ceph_ino(inode), dl.object_no);
	ceph_calc_object_layout(&ol, dl.object_name, &ci->i_layout,
				osdc->osdmap);

213
	pgid = ol.ol_pgid;
S
Sage Weil 已提交
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
	dl.osd = ceph_calc_pg_primary(osdc->osdmap, pgid);
	if (dl.osd >= 0) {
		struct ceph_entity_addr *a =
			ceph_osd_addr(osdc->osdmap, dl.osd);
		if (a)
			memcpy(&dl.osd_addr, &a->in_addr, sizeof(dl.osd_addr));
	} else {
		memset(&dl.osd_addr, 0, sizeof(dl.osd_addr));
	}
	up_read(&osdc->map_sem);

	/* send result back to user */
	if (copy_to_user(arg, &dl, sizeof(dl)))
		return -EFAULT;

	return 0;
}

232 233 234 235 236 237 238
static long ceph_ioctl_lazyio(struct file *file)
{
	struct ceph_file_info *fi = file->private_data;
	struct inode *inode = file->f_dentry->d_inode;
	struct ceph_inode_info *ci = ceph_inode(inode);

	if ((fi->fmode & CEPH_FILE_MODE_LAZY) == 0) {
239
		spin_lock(&ci->i_ceph_lock);
240 241 242
		ci->i_nr_by_mode[fi->fmode]--;
		fi->fmode |= CEPH_FILE_MODE_LAZY;
		ci->i_nr_by_mode[fi->fmode]++;
243
		spin_unlock(&ci->i_ceph_lock);
244 245 246 247 248 249 250 251 252
		dout("ioctl_layzio: file %p marked lazy\n", file);

		ceph_check_caps(ci, 0, NULL);
	} else {
		dout("ioctl_layzio: file %p already lazy\n", file);
	}
	return 0;
}

253 254 255 256 257 258 259 260
static long ceph_ioctl_syncio(struct file *file)
{
	struct ceph_file_info *fi = file->private_data;

	fi->flags |= CEPH_F_SYNC;
	return 0;
}

S
Sage Weil 已提交
261 262 263 264 265 266 267 268 269 270
long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	dout("ioctl file %p cmd %u arg %lu\n", file, cmd, arg);
	switch (cmd) {
	case CEPH_IOC_GET_LAYOUT:
		return ceph_ioctl_get_layout(file, (void __user *)arg);

	case CEPH_IOC_SET_LAYOUT:
		return ceph_ioctl_set_layout(file, (void __user *)arg);

271 272 273
	case CEPH_IOC_SET_LAYOUT_POLICY:
		return ceph_ioctl_set_layout_policy(file, (void __user *)arg);

S
Sage Weil 已提交
274 275
	case CEPH_IOC_GET_DATALOC:
		return ceph_ioctl_get_dataloc(file, (void __user *)arg);
276 277 278

	case CEPH_IOC_LAZYIO:
		return ceph_ioctl_lazyio(file);
279 280 281

	case CEPH_IOC_SYNCIO:
		return ceph_ioctl_syncio(file);
S
Sage Weil 已提交
282
	}
283

S
Sage Weil 已提交
284 285
	return -ENOTTY;
}