/* * calculate the mapping of a file extent onto an object, and fill out the * request accordingly. shorten extent as necessary if it crosses an * object boundary. * * fill osd op in request message. */ static void calc_layout(struct ceph_osd_client *osdc, struct ceph_vino vino, struct ceph_file_layout *layout, u64 off, u64 *plen, struct ceph_osd_request *req) { struct ceph_osd_request_head *reqhead = req->r_request->front.iov_base; struct ceph_osd_op *op = (void *)(reqhead + 1); u64 orig_len = *plen; u64 objoff, objlen; /* extent in object */ u64 bno; reqhead->snapid = cpu_to_le64(vino.snap); /* object extent? */ ceph_calc_file_object_mapping(layout, off, plen, &bno, &objoff, &objlen); if (*plen < orig_len) dout(" skipping last %llu, final file extent %llu~%llu\n", orig_len - *plen, off, *plen); sprintf(req->r_oid, "%llx.%08llx", vino.ino, bno); req->r_oid_len = strlen(req->r_oid); op->extent.offset = cpu_to_le64(objoff); op->extent.length = cpu_to_le64(objlen); req->r_num_pages = calc_pages_for(off, *plen); dout("calc_layout %s (%d) %llu~%llu (%d pages)\n", req->r_oid, req->r_oid_len, objoff, objlen, req->r_num_pages); }
void ceph_calc_raw_layout(struct ceph_osd_client *osdc, struct ceph_file_layout *layout, u64 snapid, u64 off, u64 *plen, u64 *bno, struct ceph_osd_request *req, struct ceph_osd_req_op *op) { struct ceph_osd_request_head *reqhead = req->r_request->front.iov_base; u64 orig_len = *plen; u64 objoff, objlen; /* extent in object */ reqhead->snapid = cpu_to_le64(snapid); /* object extent? */ ceph_calc_file_object_mapping(layout, off, plen, bno, &objoff, &objlen); if (*plen < orig_len) dout(" skipping last %llu, final file extent %llu~%llu\n", orig_len - *plen, off, *plen); if (op_has_extent(op->op)) { op->extent.offset = objoff; op->extent.length = objlen; } req->r_num_pages = calc_pages_for(off, *plen); req->r_page_alignment = off & ~PAGE_MASK; if (op->op == CEPH_OSD_OP_WRITE) op->payload_len = *plen; dout("calc_layout bno=%llx %llu~%llu (%d pages)\n", *bno, objoff, objlen, req->r_num_pages); }
/* * 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_inode(file); struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_osd_client *osdc = &ceph_sb_to_client(inode->i_sb)->client->osdc; u64 len = 1, olen; u64 tmp; struct ceph_object_layout ol; struct ceph_pg pgid; int r; /* copy and validate */ if (copy_from_user(&dl, arg, sizeof(dl))) return -EFAULT; down_read(&osdc->map_sem); r = ceph_calc_file_object_mapping(&ci->i_layout, dl.file_offset, &len, &dl.object_no, &dl.object_offset, &olen); if (r < 0) return -EIO; 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); pgid = ol.ol_pgid; 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; }