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); 768f4e91deSSage Weil req->r_inode = igrab(inode); 778f4e91deSSage Weil req->r_inode_drop = CEPH_CAP_FILE_SHARED | CEPH_CAP_FILE_EXCL; 788f4e91deSSage Weil 798f4e91deSSage Weil req->r_args.setlayout.layout.fl_stripe_unit = 808f4e91deSSage Weil cpu_to_le32(l.stripe_unit); 818f4e91deSSage Weil req->r_args.setlayout.layout.fl_stripe_count = 828f4e91deSSage Weil cpu_to_le32(l.stripe_count); 838f4e91deSSage Weil req->r_args.setlayout.layout.fl_object_size = 848f4e91deSSage Weil cpu_to_le32(l.object_size); 858f4e91deSSage Weil req->r_args.setlayout.layout.fl_pg_pool = cpu_to_le32(l.data_pool); 8633d4909cSSage Weil req->r_args.setlayout.layout.fl_pg_preferred = 8733d4909cSSage Weil cpu_to_le32(l.preferred_osd); 888f4e91deSSage Weil 898f4e91deSSage Weil err = ceph_mdsc_do_request(mdsc, parent_inode, req); 908f4e91deSSage Weil ceph_mdsc_put_request(req); 918f4e91deSSage Weil return err; 928f4e91deSSage Weil } 938f4e91deSSage Weil 948f4e91deSSage Weil /* 95*571dba52SGreg Farnum * Set a layout policy on a directory inode. All items in the tree 96*571dba52SGreg Farnum * rooted at this inode will inherit this layout on creation, 97*571dba52SGreg Farnum * (It doesn't apply retroactively ) 98*571dba52SGreg Farnum * unless a subdirectory has its own layout policy. 99*571dba52SGreg Farnum */ 100*571dba52SGreg Farnum static long ceph_ioctl_set_layout_policy (struct file *file, void __user *arg) 101*571dba52SGreg Farnum { 102*571dba52SGreg Farnum struct inode *inode = file->f_dentry->d_inode; 103*571dba52SGreg Farnum struct ceph_mds_request *req; 104*571dba52SGreg Farnum struct ceph_ioctl_layout l; 105*571dba52SGreg Farnum int err, i; 106*571dba52SGreg Farnum struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc; 107*571dba52SGreg Farnum 108*571dba52SGreg Farnum /* copy and validate */ 109*571dba52SGreg Farnum if (copy_from_user(&l, arg, sizeof(l))) 110*571dba52SGreg Farnum return -EFAULT; 111*571dba52SGreg Farnum 112*571dba52SGreg Farnum if ((l.object_size & ~PAGE_MASK) || 113*571dba52SGreg Farnum (l.stripe_unit & ~PAGE_MASK) || 114*571dba52SGreg Farnum !l.stripe_unit || 115*571dba52SGreg Farnum (l.object_size && 116*571dba52SGreg Farnum (unsigned)l.object_size % (unsigned)l.stripe_unit)) 117*571dba52SGreg Farnum return -EINVAL; 118*571dba52SGreg Farnum 119*571dba52SGreg Farnum /* make sure it's a valid data pool */ 120*571dba52SGreg Farnum if (l.data_pool > 0) { 121*571dba52SGreg Farnum mutex_lock(&mdsc->mutex); 122*571dba52SGreg Farnum err = -EINVAL; 123*571dba52SGreg Farnum for (i = 0; i < mdsc->mdsmap->m_num_data_pg_pools; i++) 124*571dba52SGreg Farnum if (mdsc->mdsmap->m_data_pg_pools[i] == l.data_pool) { 125*571dba52SGreg Farnum err = 0; 126*571dba52SGreg Farnum break; 127*571dba52SGreg Farnum } 128*571dba52SGreg Farnum mutex_unlock(&mdsc->mutex); 129*571dba52SGreg Farnum if (err) 130*571dba52SGreg Farnum return err; 131*571dba52SGreg Farnum } 132*571dba52SGreg Farnum 133*571dba52SGreg Farnum req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETDIRLAYOUT, 134*571dba52SGreg Farnum USE_AUTH_MDS); 135*571dba52SGreg Farnum 136*571dba52SGreg Farnum if (IS_ERR(req)) 137*571dba52SGreg Farnum return PTR_ERR(req); 138*571dba52SGreg Farnum req->r_inode = igrab(inode); 139*571dba52SGreg Farnum 140*571dba52SGreg Farnum req->r_args.setlayout.layout.fl_stripe_unit = 141*571dba52SGreg Farnum cpu_to_le32(l.stripe_unit); 142*571dba52SGreg Farnum req->r_args.setlayout.layout.fl_stripe_count = 143*571dba52SGreg Farnum cpu_to_le32(l.stripe_count); 144*571dba52SGreg Farnum req->r_args.setlayout.layout.fl_object_size = 145*571dba52SGreg Farnum cpu_to_le32(l.object_size); 146*571dba52SGreg Farnum req->r_args.setlayout.layout.fl_pg_pool = 147*571dba52SGreg Farnum cpu_to_le32(l.data_pool); 148*571dba52SGreg Farnum req->r_args.setlayout.layout.fl_pg_preferred = 149*571dba52SGreg Farnum cpu_to_le32(l.preferred_osd); 150*571dba52SGreg Farnum 151*571dba52SGreg Farnum err = ceph_mdsc_do_request(mdsc, inode, req); 152*571dba52SGreg Farnum ceph_mdsc_put_request(req); 153*571dba52SGreg Farnum return err; 154*571dba52SGreg Farnum } 155*571dba52SGreg Farnum 156*571dba52SGreg Farnum /* 1578f4e91deSSage Weil * Return object name, size/offset information, and location (OSD 1588f4e91deSSage Weil * number, network address) for a given file offset. 1598f4e91deSSage Weil */ 1608f4e91deSSage Weil static long ceph_ioctl_get_dataloc(struct file *file, void __user *arg) 1618f4e91deSSage Weil { 1628f4e91deSSage Weil struct ceph_ioctl_dataloc dl; 1638f4e91deSSage Weil struct inode *inode = file->f_dentry->d_inode; 1648f4e91deSSage Weil struct ceph_inode_info *ci = ceph_inode(inode); 1653d14c5d2SYehuda Sadeh struct ceph_osd_client *osdc = 1663d14c5d2SYehuda Sadeh &ceph_sb_to_client(inode->i_sb)->client->osdc; 1678f4e91deSSage Weil u64 len = 1, olen; 1688f4e91deSSage Weil u64 tmp; 1698f4e91deSSage Weil struct ceph_object_layout ol; 17051042122SSage Weil struct ceph_pg pgid; 1718f4e91deSSage Weil 1728f4e91deSSage Weil /* copy and validate */ 1738f4e91deSSage Weil if (copy_from_user(&dl, arg, sizeof(dl))) 1748f4e91deSSage Weil return -EFAULT; 1758f4e91deSSage Weil 1768f4e91deSSage Weil down_read(&osdc->map_sem); 1778f4e91deSSage Weil ceph_calc_file_object_mapping(&ci->i_layout, dl.file_offset, &len, 1788f4e91deSSage Weil &dl.object_no, &dl.object_offset, &olen); 1798f4e91deSSage Weil dl.file_offset -= dl.object_offset; 1808f4e91deSSage Weil dl.object_size = ceph_file_layout_object_size(ci->i_layout); 1818f4e91deSSage Weil dl.block_size = ceph_file_layout_su(ci->i_layout); 1828f4e91deSSage Weil 1838f4e91deSSage Weil /* block_offset = object_offset % block_size */ 1848f4e91deSSage Weil tmp = dl.object_offset; 1858f4e91deSSage Weil dl.block_offset = do_div(tmp, dl.block_size); 1868f4e91deSSage Weil 1878f4e91deSSage Weil snprintf(dl.object_name, sizeof(dl.object_name), "%llx.%08llx", 1888f4e91deSSage Weil ceph_ino(inode), dl.object_no); 1898f4e91deSSage Weil ceph_calc_object_layout(&ol, dl.object_name, &ci->i_layout, 1908f4e91deSSage Weil osdc->osdmap); 1918f4e91deSSage Weil 19251042122SSage Weil pgid = ol.ol_pgid; 1938f4e91deSSage Weil dl.osd = ceph_calc_pg_primary(osdc->osdmap, pgid); 1948f4e91deSSage Weil if (dl.osd >= 0) { 1958f4e91deSSage Weil struct ceph_entity_addr *a = 1968f4e91deSSage Weil ceph_osd_addr(osdc->osdmap, dl.osd); 1978f4e91deSSage Weil if (a) 1988f4e91deSSage Weil memcpy(&dl.osd_addr, &a->in_addr, sizeof(dl.osd_addr)); 1998f4e91deSSage Weil } else { 2008f4e91deSSage Weil memset(&dl.osd_addr, 0, sizeof(dl.osd_addr)); 2018f4e91deSSage Weil } 2028f4e91deSSage Weil up_read(&osdc->map_sem); 2038f4e91deSSage Weil 2048f4e91deSSage Weil /* send result back to user */ 2058f4e91deSSage Weil if (copy_to_user(arg, &dl, sizeof(dl))) 2068f4e91deSSage Weil return -EFAULT; 2078f4e91deSSage Weil 2088f4e91deSSage Weil return 0; 2098f4e91deSSage Weil } 2108f4e91deSSage Weil 2118c6e9229SSage Weil static long ceph_ioctl_lazyio(struct file *file) 2128c6e9229SSage Weil { 2138c6e9229SSage Weil struct ceph_file_info *fi = file->private_data; 2148c6e9229SSage Weil struct inode *inode = file->f_dentry->d_inode; 2158c6e9229SSage Weil struct ceph_inode_info *ci = ceph_inode(inode); 2168c6e9229SSage Weil 2178c6e9229SSage Weil if ((fi->fmode & CEPH_FILE_MODE_LAZY) == 0) { 2188c6e9229SSage Weil spin_lock(&inode->i_lock); 2198c6e9229SSage Weil ci->i_nr_by_mode[fi->fmode]--; 2208c6e9229SSage Weil fi->fmode |= CEPH_FILE_MODE_LAZY; 2218c6e9229SSage Weil ci->i_nr_by_mode[fi->fmode]++; 2228c6e9229SSage Weil spin_unlock(&inode->i_lock); 2238c6e9229SSage Weil dout("ioctl_layzio: file %p marked lazy\n", file); 2248c6e9229SSage Weil 2258c6e9229SSage Weil ceph_check_caps(ci, 0, NULL); 2268c6e9229SSage Weil } else { 2278c6e9229SSage Weil dout("ioctl_layzio: file %p already lazy\n", file); 2288c6e9229SSage Weil } 2298c6e9229SSage Weil return 0; 2308c6e9229SSage Weil } 2318c6e9229SSage Weil 2328f4e91deSSage Weil long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 2338f4e91deSSage Weil { 2348f4e91deSSage Weil dout("ioctl file %p cmd %u arg %lu\n", file, cmd, arg); 2358f4e91deSSage Weil switch (cmd) { 2368f4e91deSSage Weil case CEPH_IOC_GET_LAYOUT: 2378f4e91deSSage Weil return ceph_ioctl_get_layout(file, (void __user *)arg); 2388f4e91deSSage Weil 2398f4e91deSSage Weil case CEPH_IOC_SET_LAYOUT: 2408f4e91deSSage Weil return ceph_ioctl_set_layout(file, (void __user *)arg); 2418f4e91deSSage Weil 242*571dba52SGreg Farnum case CEPH_IOC_SET_LAYOUT_POLICY: 243*571dba52SGreg Farnum return ceph_ioctl_set_layout_policy(file, (void __user *)arg); 244*571dba52SGreg Farnum 2458f4e91deSSage Weil case CEPH_IOC_GET_DATALOC: 2468f4e91deSSage Weil return ceph_ioctl_get_dataloc(file, (void __user *)arg); 2478c6e9229SSage Weil 2488c6e9229SSage Weil case CEPH_IOC_LAZYIO: 2498c6e9229SSage Weil return ceph_ioctl_lazyio(file); 2508f4e91deSSage Weil } 251*571dba52SGreg Farnum 2528f4e91deSSage Weil return -ENOTTY; 2538f4e91deSSage Weil } 254