18f4e91deSSage Weil #include <linux/in.h> 28f4e91deSSage Weil 38f4e91deSSage Weil #include "super.h" 43d14c5d2SYehuda Sadeh #include "mds_client.h" 53d14c5d2SYehuda Sadeh #include <linux/ceph/ceph_debug.h> 63d14c5d2SYehuda Sadeh 73d14c5d2SYehuda Sadeh #include "ioctl.h" 88f4e91deSSage Weil 98f4e91deSSage Weil 108f4e91deSSage Weil /* 118f4e91deSSage Weil * ioctls 128f4e91deSSage Weil */ 138f4e91deSSage Weil 148f4e91deSSage Weil /* 158f4e91deSSage Weil * get and set the file layout 168f4e91deSSage Weil */ 178f4e91deSSage Weil static long ceph_ioctl_get_layout(struct file *file, void __user *arg) 188f4e91deSSage Weil { 198f4e91deSSage Weil struct ceph_inode_info *ci = ceph_inode(file->f_dentry->d_inode); 208f4e91deSSage Weil struct ceph_ioctl_layout l; 218f4e91deSSage Weil int err; 228f4e91deSSage Weil 238f4e91deSSage Weil err = ceph_do_getattr(file->f_dentry->d_inode, CEPH_STAT_CAP_LAYOUT); 248f4e91deSSage Weil if (!err) { 258f4e91deSSage Weil l.stripe_unit = ceph_file_layout_su(ci->i_layout); 268f4e91deSSage Weil l.stripe_count = ceph_file_layout_stripe_count(ci->i_layout); 278f4e91deSSage Weil l.object_size = ceph_file_layout_object_size(ci->i_layout); 288f4e91deSSage Weil l.data_pool = le32_to_cpu(ci->i_layout.fl_pg_pool); 2933d4909cSSage Weil l.preferred_osd = 3033d4909cSSage Weil (s32)le32_to_cpu(ci->i_layout.fl_pg_preferred); 318f4e91deSSage Weil if (copy_to_user(arg, &l, sizeof(l))) 328f4e91deSSage Weil return -EFAULT; 338f4e91deSSage Weil } 348f4e91deSSage Weil 358f4e91deSSage Weil return err; 368f4e91deSSage Weil } 378f4e91deSSage Weil 388f4e91deSSage Weil static long ceph_ioctl_set_layout(struct file *file, void __user *arg) 398f4e91deSSage Weil { 408f4e91deSSage Weil struct inode *inode = file->f_dentry->d_inode; 418f4e91deSSage Weil struct inode *parent_inode = file->f_dentry->d_parent->d_inode; 423d14c5d2SYehuda Sadeh struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc; 438f4e91deSSage Weil struct ceph_mds_request *req; 448f4e91deSSage Weil struct ceph_ioctl_layout l; 458f4e91deSSage Weil int err, i; 468f4e91deSSage Weil 478f4e91deSSage Weil /* copy and validate */ 488f4e91deSSage Weil if (copy_from_user(&l, arg, sizeof(l))) 498f4e91deSSage Weil return -EFAULT; 508f4e91deSSage Weil 518f4e91deSSage Weil if ((l.object_size & ~PAGE_MASK) || 528f4e91deSSage Weil (l.stripe_unit & ~PAGE_MASK) || 538f4e91deSSage Weil !l.stripe_unit || 548f4e91deSSage Weil (l.object_size && 558f4e91deSSage Weil (unsigned)l.object_size % (unsigned)l.stripe_unit)) 568f4e91deSSage Weil return -EINVAL; 578f4e91deSSage Weil 588f4e91deSSage Weil /* make sure it's a valid data pool */ 598f4e91deSSage Weil if (l.data_pool > 0) { 608f4e91deSSage Weil mutex_lock(&mdsc->mutex); 618f4e91deSSage Weil err = -EINVAL; 628f4e91deSSage Weil for (i = 0; i < mdsc->mdsmap->m_num_data_pg_pools; i++) 638f4e91deSSage Weil if (mdsc->mdsmap->m_data_pg_pools[i] == l.data_pool) { 648f4e91deSSage Weil err = 0; 658f4e91deSSage Weil break; 668f4e91deSSage Weil } 678f4e91deSSage Weil mutex_unlock(&mdsc->mutex); 688f4e91deSSage Weil if (err) 698f4e91deSSage Weil return err; 708f4e91deSSage Weil } 718f4e91deSSage Weil 728f4e91deSSage Weil req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETLAYOUT, 738f4e91deSSage Weil USE_AUTH_MDS); 748f4e91deSSage Weil if (IS_ERR(req)) 758f4e91deSSage Weil return PTR_ERR(req); 76*70b666c3SSage Weil req->r_inode = inode; 77*70b666c3SSage Weil ihold(inode); 788f4e91deSSage Weil req->r_inode_drop = CEPH_CAP_FILE_SHARED | CEPH_CAP_FILE_EXCL; 798f4e91deSSage Weil 808f4e91deSSage Weil req->r_args.setlayout.layout.fl_stripe_unit = 818f4e91deSSage Weil cpu_to_le32(l.stripe_unit); 828f4e91deSSage Weil req->r_args.setlayout.layout.fl_stripe_count = 838f4e91deSSage Weil cpu_to_le32(l.stripe_count); 848f4e91deSSage Weil req->r_args.setlayout.layout.fl_object_size = 858f4e91deSSage Weil cpu_to_le32(l.object_size); 868f4e91deSSage Weil req->r_args.setlayout.layout.fl_pg_pool = cpu_to_le32(l.data_pool); 8733d4909cSSage Weil req->r_args.setlayout.layout.fl_pg_preferred = 8833d4909cSSage Weil cpu_to_le32(l.preferred_osd); 898f4e91deSSage Weil 908f4e91deSSage Weil err = ceph_mdsc_do_request(mdsc, parent_inode, req); 918f4e91deSSage Weil ceph_mdsc_put_request(req); 928f4e91deSSage Weil return err; 938f4e91deSSage Weil } 948f4e91deSSage Weil 958f4e91deSSage Weil /* 96571dba52SGreg Farnum * Set a layout policy on a directory inode. All items in the tree 97571dba52SGreg Farnum * rooted at this inode will inherit this layout on creation, 98571dba52SGreg Farnum * (It doesn't apply retroactively ) 99571dba52SGreg Farnum * unless a subdirectory has its own layout policy. 100571dba52SGreg Farnum */ 101571dba52SGreg Farnum static long ceph_ioctl_set_layout_policy (struct file *file, void __user *arg) 102571dba52SGreg Farnum { 103571dba52SGreg Farnum struct inode *inode = file->f_dentry->d_inode; 104571dba52SGreg Farnum struct ceph_mds_request *req; 105571dba52SGreg Farnum struct ceph_ioctl_layout l; 106571dba52SGreg Farnum int err, i; 107571dba52SGreg Farnum struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc; 108571dba52SGreg Farnum 109571dba52SGreg Farnum /* copy and validate */ 110571dba52SGreg Farnum if (copy_from_user(&l, arg, sizeof(l))) 111571dba52SGreg Farnum return -EFAULT; 112571dba52SGreg Farnum 113571dba52SGreg Farnum if ((l.object_size & ~PAGE_MASK) || 114571dba52SGreg Farnum (l.stripe_unit & ~PAGE_MASK) || 115571dba52SGreg Farnum !l.stripe_unit || 116571dba52SGreg Farnum (l.object_size && 117571dba52SGreg Farnum (unsigned)l.object_size % (unsigned)l.stripe_unit)) 118571dba52SGreg Farnum return -EINVAL; 119571dba52SGreg Farnum 120571dba52SGreg Farnum /* make sure it's a valid data pool */ 121571dba52SGreg Farnum if (l.data_pool > 0) { 122571dba52SGreg Farnum mutex_lock(&mdsc->mutex); 123571dba52SGreg Farnum err = -EINVAL; 124571dba52SGreg Farnum for (i = 0; i < mdsc->mdsmap->m_num_data_pg_pools; i++) 125571dba52SGreg Farnum if (mdsc->mdsmap->m_data_pg_pools[i] == l.data_pool) { 126571dba52SGreg Farnum err = 0; 127571dba52SGreg Farnum break; 128571dba52SGreg Farnum } 129571dba52SGreg Farnum mutex_unlock(&mdsc->mutex); 130571dba52SGreg Farnum if (err) 131571dba52SGreg Farnum return err; 132571dba52SGreg Farnum } 133571dba52SGreg Farnum 134571dba52SGreg Farnum req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETDIRLAYOUT, 135571dba52SGreg Farnum USE_AUTH_MDS); 136571dba52SGreg Farnum 137571dba52SGreg Farnum if (IS_ERR(req)) 138571dba52SGreg Farnum return PTR_ERR(req); 139*70b666c3SSage Weil req->r_inode = inode; 140*70b666c3SSage Weil ihold(inode); 141571dba52SGreg Farnum 142571dba52SGreg Farnum req->r_args.setlayout.layout.fl_stripe_unit = 143571dba52SGreg Farnum cpu_to_le32(l.stripe_unit); 144571dba52SGreg Farnum req->r_args.setlayout.layout.fl_stripe_count = 145571dba52SGreg Farnum cpu_to_le32(l.stripe_count); 146571dba52SGreg Farnum req->r_args.setlayout.layout.fl_object_size = 147571dba52SGreg Farnum cpu_to_le32(l.object_size); 148571dba52SGreg Farnum req->r_args.setlayout.layout.fl_pg_pool = 149571dba52SGreg Farnum cpu_to_le32(l.data_pool); 150571dba52SGreg Farnum req->r_args.setlayout.layout.fl_pg_preferred = 151571dba52SGreg Farnum cpu_to_le32(l.preferred_osd); 152571dba52SGreg Farnum 153571dba52SGreg Farnum err = ceph_mdsc_do_request(mdsc, inode, req); 154571dba52SGreg Farnum ceph_mdsc_put_request(req); 155571dba52SGreg Farnum return err; 156571dba52SGreg Farnum } 157571dba52SGreg Farnum 158571dba52SGreg Farnum /* 1598f4e91deSSage Weil * Return object name, size/offset information, and location (OSD 1608f4e91deSSage Weil * number, network address) for a given file offset. 1618f4e91deSSage Weil */ 1628f4e91deSSage Weil static long ceph_ioctl_get_dataloc(struct file *file, void __user *arg) 1638f4e91deSSage Weil { 1648f4e91deSSage Weil struct ceph_ioctl_dataloc dl; 1658f4e91deSSage Weil struct inode *inode = file->f_dentry->d_inode; 1668f4e91deSSage Weil struct ceph_inode_info *ci = ceph_inode(inode); 1673d14c5d2SYehuda Sadeh struct ceph_osd_client *osdc = 1683d14c5d2SYehuda Sadeh &ceph_sb_to_client(inode->i_sb)->client->osdc; 1698f4e91deSSage Weil u64 len = 1, olen; 1708f4e91deSSage Weil u64 tmp; 1718f4e91deSSage Weil struct ceph_object_layout ol; 17251042122SSage Weil struct ceph_pg pgid; 1738f4e91deSSage Weil 1748f4e91deSSage Weil /* copy and validate */ 1758f4e91deSSage Weil if (copy_from_user(&dl, arg, sizeof(dl))) 1768f4e91deSSage Weil return -EFAULT; 1778f4e91deSSage Weil 1788f4e91deSSage Weil down_read(&osdc->map_sem); 1798f4e91deSSage Weil ceph_calc_file_object_mapping(&ci->i_layout, dl.file_offset, &len, 1808f4e91deSSage Weil &dl.object_no, &dl.object_offset, &olen); 1818f4e91deSSage Weil dl.file_offset -= dl.object_offset; 1828f4e91deSSage Weil dl.object_size = ceph_file_layout_object_size(ci->i_layout); 1838f4e91deSSage Weil dl.block_size = ceph_file_layout_su(ci->i_layout); 1848f4e91deSSage Weil 1858f4e91deSSage Weil /* block_offset = object_offset % block_size */ 1868f4e91deSSage Weil tmp = dl.object_offset; 1878f4e91deSSage Weil dl.block_offset = do_div(tmp, dl.block_size); 1888f4e91deSSage Weil 1898f4e91deSSage Weil snprintf(dl.object_name, sizeof(dl.object_name), "%llx.%08llx", 1908f4e91deSSage Weil ceph_ino(inode), dl.object_no); 1918f4e91deSSage Weil ceph_calc_object_layout(&ol, dl.object_name, &ci->i_layout, 1928f4e91deSSage Weil osdc->osdmap); 1938f4e91deSSage Weil 19451042122SSage Weil pgid = ol.ol_pgid; 1958f4e91deSSage Weil dl.osd = ceph_calc_pg_primary(osdc->osdmap, pgid); 1968f4e91deSSage Weil if (dl.osd >= 0) { 1978f4e91deSSage Weil struct ceph_entity_addr *a = 1988f4e91deSSage Weil ceph_osd_addr(osdc->osdmap, dl.osd); 1998f4e91deSSage Weil if (a) 2008f4e91deSSage Weil memcpy(&dl.osd_addr, &a->in_addr, sizeof(dl.osd_addr)); 2018f4e91deSSage Weil } else { 2028f4e91deSSage Weil memset(&dl.osd_addr, 0, sizeof(dl.osd_addr)); 2038f4e91deSSage Weil } 2048f4e91deSSage Weil up_read(&osdc->map_sem); 2058f4e91deSSage Weil 2068f4e91deSSage Weil /* send result back to user */ 2078f4e91deSSage Weil if (copy_to_user(arg, &dl, sizeof(dl))) 2088f4e91deSSage Weil return -EFAULT; 2098f4e91deSSage Weil 2108f4e91deSSage Weil return 0; 2118f4e91deSSage Weil } 2128f4e91deSSage Weil 2138c6e9229SSage Weil static long ceph_ioctl_lazyio(struct file *file) 2148c6e9229SSage Weil { 2158c6e9229SSage Weil struct ceph_file_info *fi = file->private_data; 2168c6e9229SSage Weil struct inode *inode = file->f_dentry->d_inode; 2178c6e9229SSage Weil struct ceph_inode_info *ci = ceph_inode(inode); 2188c6e9229SSage Weil 2198c6e9229SSage Weil if ((fi->fmode & CEPH_FILE_MODE_LAZY) == 0) { 2208c6e9229SSage Weil spin_lock(&inode->i_lock); 2218c6e9229SSage Weil ci->i_nr_by_mode[fi->fmode]--; 2228c6e9229SSage Weil fi->fmode |= CEPH_FILE_MODE_LAZY; 2238c6e9229SSage Weil ci->i_nr_by_mode[fi->fmode]++; 2248c6e9229SSage Weil spin_unlock(&inode->i_lock); 2258c6e9229SSage Weil dout("ioctl_layzio: file %p marked lazy\n", file); 2268c6e9229SSage Weil 2278c6e9229SSage Weil ceph_check_caps(ci, 0, NULL); 2288c6e9229SSage Weil } else { 2298c6e9229SSage Weil dout("ioctl_layzio: file %p already lazy\n", file); 2308c6e9229SSage Weil } 2318c6e9229SSage Weil return 0; 2328c6e9229SSage Weil } 2338c6e9229SSage Weil 2348f4e91deSSage Weil long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 2358f4e91deSSage Weil { 2368f4e91deSSage Weil dout("ioctl file %p cmd %u arg %lu\n", file, cmd, arg); 2378f4e91deSSage Weil switch (cmd) { 2388f4e91deSSage Weil case CEPH_IOC_GET_LAYOUT: 2398f4e91deSSage Weil return ceph_ioctl_get_layout(file, (void __user *)arg); 2408f4e91deSSage Weil 2418f4e91deSSage Weil case CEPH_IOC_SET_LAYOUT: 2428f4e91deSSage Weil return ceph_ioctl_set_layout(file, (void __user *)arg); 2438f4e91deSSage Weil 244571dba52SGreg Farnum case CEPH_IOC_SET_LAYOUT_POLICY: 245571dba52SGreg Farnum return ceph_ioctl_set_layout_policy(file, (void __user *)arg); 246571dba52SGreg Farnum 2478f4e91deSSage Weil case CEPH_IOC_GET_DATALOC: 2488f4e91deSSage Weil return ceph_ioctl_get_dataloc(file, (void __user *)arg); 2498c6e9229SSage Weil 2508c6e9229SSage Weil case CEPH_IOC_LAZYIO: 2518c6e9229SSage Weil return ceph_ioctl_lazyio(file); 2528f4e91deSSage Weil } 253571dba52SGreg Farnum 2548f4e91deSSage Weil return -ENOTTY; 2558f4e91deSSage Weil } 256