0001
0002
0003 #include <linux/ceph/ceph_debug.h>
0004
0005 #include <linux/math64.h>
0006 #include <linux/slab.h>
0007
0008 #include <linux/ceph/striper.h>
0009 #include <linux/ceph/types.h>
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024 void ceph_calc_file_object_mapping(struct ceph_file_layout *l,
0025 u64 off, u64 len,
0026 u64 *objno, u64 *objoff, u32 *xlen)
0027 {
0028 u32 stripes_per_object = l->object_size / l->stripe_unit;
0029 u64 blockno;
0030 u32 blockoff;
0031 u64 stripeno;
0032 u32 stripepos;
0033
0034 u64 objsetno;
0035 u32 objsetpos;
0036
0037 blockno = div_u64_rem(off, l->stripe_unit, &blockoff);
0038 stripeno = div_u64_rem(blockno, l->stripe_count, &stripepos);
0039 objsetno = div_u64_rem(stripeno, stripes_per_object, &objsetpos);
0040
0041 *objno = objsetno * l->stripe_count + stripepos;
0042 *objoff = objsetpos * l->stripe_unit + blockoff;
0043 *xlen = min_t(u64, len, l->stripe_unit - blockoff);
0044 }
0045 EXPORT_SYMBOL(ceph_calc_file_object_mapping);
0046
0047
0048
0049
0050
0051
0052 static struct ceph_object_extent *
0053 lookup_last(struct list_head *object_extents, u64 objno,
0054 struct list_head **add_pos)
0055 {
0056 struct list_head *pos;
0057
0058 list_for_each_prev(pos, object_extents) {
0059 struct ceph_object_extent *ex =
0060 list_entry(pos, typeof(*ex), oe_item);
0061
0062 if (ex->oe_objno == objno)
0063 return ex;
0064
0065 if (ex->oe_objno < objno)
0066 break;
0067 }
0068
0069 *add_pos = pos;
0070 return NULL;
0071 }
0072
0073 static struct ceph_object_extent *
0074 lookup_containing(struct list_head *object_extents, u64 objno,
0075 u64 objoff, u32 xlen)
0076 {
0077 struct ceph_object_extent *ex;
0078
0079 list_for_each_entry(ex, object_extents, oe_item) {
0080 if (ex->oe_objno == objno &&
0081 ex->oe_off <= objoff &&
0082 ex->oe_off + ex->oe_len >= objoff + xlen)
0083 return ex;
0084
0085 if (ex->oe_objno > objno)
0086 break;
0087 }
0088
0089 return NULL;
0090 }
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110 int ceph_file_to_extents(struct ceph_file_layout *l, u64 off, u64 len,
0111 struct list_head *object_extents,
0112 struct ceph_object_extent *alloc_fn(void *arg),
0113 void *alloc_arg,
0114 ceph_object_extent_fn_t action_fn,
0115 void *action_arg)
0116 {
0117 struct ceph_object_extent *last_ex, *ex;
0118
0119 while (len) {
0120 struct list_head *add_pos = NULL;
0121 u64 objno, objoff;
0122 u32 xlen;
0123
0124 ceph_calc_file_object_mapping(l, off, len, &objno, &objoff,
0125 &xlen);
0126
0127 last_ex = lookup_last(object_extents, objno, &add_pos);
0128 if (!last_ex || last_ex->oe_off + last_ex->oe_len != objoff) {
0129 ex = alloc_fn(alloc_arg);
0130 if (!ex)
0131 return -ENOMEM;
0132
0133 ex->oe_objno = objno;
0134 ex->oe_off = objoff;
0135 ex->oe_len = xlen;
0136 if (action_fn)
0137 action_fn(ex, xlen, action_arg);
0138
0139 if (!last_ex)
0140 list_add(&ex->oe_item, add_pos);
0141 else
0142 list_add(&ex->oe_item, &last_ex->oe_item);
0143 } else {
0144 last_ex->oe_len += xlen;
0145 if (action_fn)
0146 action_fn(last_ex, xlen, action_arg);
0147 }
0148
0149 off += xlen;
0150 len -= xlen;
0151 }
0152
0153 for (last_ex = list_first_entry(object_extents, typeof(*ex), oe_item),
0154 ex = list_next_entry(last_ex, oe_item);
0155 &ex->oe_item != object_extents;
0156 last_ex = ex, ex = list_next_entry(ex, oe_item)) {
0157 if (last_ex->oe_objno > ex->oe_objno ||
0158 (last_ex->oe_objno == ex->oe_objno &&
0159 last_ex->oe_off + last_ex->oe_len >= ex->oe_off)) {
0160 WARN(1, "%s: object_extents list not sorted!\n",
0161 __func__);
0162 return -EINVAL;
0163 }
0164 }
0165
0166 return 0;
0167 }
0168 EXPORT_SYMBOL(ceph_file_to_extents);
0169
0170
0171
0172
0173
0174 int ceph_iterate_extents(struct ceph_file_layout *l, u64 off, u64 len,
0175 struct list_head *object_extents,
0176 ceph_object_extent_fn_t action_fn,
0177 void *action_arg)
0178 {
0179 while (len) {
0180 struct ceph_object_extent *ex;
0181 u64 objno, objoff;
0182 u32 xlen;
0183
0184 ceph_calc_file_object_mapping(l, off, len, &objno, &objoff,
0185 &xlen);
0186
0187 ex = lookup_containing(object_extents, objno, objoff, xlen);
0188 if (!ex) {
0189 WARN(1, "%s: objno %llu %llu~%u not found!\n",
0190 __func__, objno, objoff, xlen);
0191 return -EINVAL;
0192 }
0193
0194 action_fn(ex, xlen, action_arg);
0195
0196 off += xlen;
0197 len -= xlen;
0198 }
0199
0200 return 0;
0201 }
0202 EXPORT_SYMBOL(ceph_iterate_extents);
0203
0204
0205
0206
0207
0208
0209
0210
0211 int ceph_extent_to_file(struct ceph_file_layout *l,
0212 u64 objno, u64 objoff, u64 objlen,
0213 struct ceph_file_extent **file_extents,
0214 u32 *num_file_extents)
0215 {
0216 u32 stripes_per_object = l->object_size / l->stripe_unit;
0217 u64 blockno;
0218 u32 blockoff;
0219 u64 stripeno;
0220 u32 stripepos;
0221
0222 u64 objsetno;
0223 u32 i = 0;
0224
0225 if (!objlen) {
0226 *file_extents = NULL;
0227 *num_file_extents = 0;
0228 return 0;
0229 }
0230
0231 *num_file_extents = DIV_ROUND_UP_ULL(objoff + objlen, l->stripe_unit) -
0232 DIV_ROUND_DOWN_ULL(objoff, l->stripe_unit);
0233 *file_extents = kmalloc_array(*num_file_extents, sizeof(**file_extents),
0234 GFP_NOIO);
0235 if (!*file_extents)
0236 return -ENOMEM;
0237
0238 div_u64_rem(objoff, l->stripe_unit, &blockoff);
0239 while (objlen) {
0240 u64 off, len;
0241
0242 objsetno = div_u64_rem(objno, l->stripe_count, &stripepos);
0243 stripeno = div_u64(objoff, l->stripe_unit) +
0244 objsetno * stripes_per_object;
0245 blockno = stripeno * l->stripe_count + stripepos;
0246 off = blockno * l->stripe_unit + blockoff;
0247 len = min_t(u64, objlen, l->stripe_unit - blockoff);
0248
0249 (*file_extents)[i].fe_off = off;
0250 (*file_extents)[i].fe_len = len;
0251
0252 blockoff = 0;
0253 objoff += len;
0254 objlen -= len;
0255 i++;
0256 }
0257
0258 BUG_ON(i != *num_file_extents);
0259 return 0;
0260 }
0261 EXPORT_SYMBOL(ceph_extent_to_file);
0262
0263 u64 ceph_get_num_objects(struct ceph_file_layout *l, u64 size)
0264 {
0265 u64 period = (u64)l->stripe_count * l->object_size;
0266 u64 num_periods = DIV64_U64_ROUND_UP(size, period);
0267 u64 remainder_bytes;
0268 u64 remainder_objs = 0;
0269
0270 div64_u64_rem(size, period, &remainder_bytes);
0271 if (remainder_bytes > 0 &&
0272 remainder_bytes < (u64)l->stripe_count * l->stripe_unit)
0273 remainder_objs = l->stripe_count -
0274 DIV_ROUND_UP_ULL(remainder_bytes, l->stripe_unit);
0275
0276 return num_periods * l->stripe_count - remainder_objs;
0277 }
0278 EXPORT_SYMBOL(ceph_get_num_objects);