0001
0002
0003
0004
0005
0006 #include <linux/vmalloc.h>
0007
0008 #include "blocklayout.h"
0009
0010 #define NFSDBG_FACILITY NFSDBG_PNFS_LD
0011
0012 static inline struct pnfs_block_extent *
0013 ext_node(struct rb_node *node)
0014 {
0015 return rb_entry(node, struct pnfs_block_extent, be_node);
0016 }
0017
0018 static struct pnfs_block_extent *
0019 ext_tree_first(struct rb_root *root)
0020 {
0021 struct rb_node *node = rb_first(root);
0022 return node ? ext_node(node) : NULL;
0023 }
0024
0025 static struct pnfs_block_extent *
0026 ext_tree_prev(struct pnfs_block_extent *be)
0027 {
0028 struct rb_node *node = rb_prev(&be->be_node);
0029 return node ? ext_node(node) : NULL;
0030 }
0031
0032 static struct pnfs_block_extent *
0033 ext_tree_next(struct pnfs_block_extent *be)
0034 {
0035 struct rb_node *node = rb_next(&be->be_node);
0036 return node ? ext_node(node) : NULL;
0037 }
0038
0039 static inline sector_t
0040 ext_f_end(struct pnfs_block_extent *be)
0041 {
0042 return be->be_f_offset + be->be_length;
0043 }
0044
0045 static struct pnfs_block_extent *
0046 __ext_tree_search(struct rb_root *root, sector_t start)
0047 {
0048 struct rb_node *node = root->rb_node;
0049 struct pnfs_block_extent *be = NULL;
0050
0051 while (node) {
0052 be = ext_node(node);
0053 if (start < be->be_f_offset)
0054 node = node->rb_left;
0055 else if (start >= ext_f_end(be))
0056 node = node->rb_right;
0057 else
0058 return be;
0059 }
0060
0061 if (be) {
0062 if (start < be->be_f_offset)
0063 return be;
0064
0065 if (start >= ext_f_end(be))
0066 return ext_tree_next(be);
0067 }
0068
0069 return NULL;
0070 }
0071
0072 static bool
0073 ext_can_merge(struct pnfs_block_extent *be1, struct pnfs_block_extent *be2)
0074 {
0075 if (be1->be_state != be2->be_state)
0076 return false;
0077 if (be1->be_device != be2->be_device)
0078 return false;
0079
0080 if (be1->be_f_offset + be1->be_length != be2->be_f_offset)
0081 return false;
0082
0083 if (be1->be_state != PNFS_BLOCK_NONE_DATA &&
0084 (be1->be_v_offset + be1->be_length != be2->be_v_offset))
0085 return false;
0086
0087 if (be1->be_state == PNFS_BLOCK_INVALID_DATA &&
0088 be1->be_tag != be2->be_tag)
0089 return false;
0090
0091 return true;
0092 }
0093
0094 static struct pnfs_block_extent *
0095 ext_try_to_merge_left(struct rb_root *root, struct pnfs_block_extent *be)
0096 {
0097 struct pnfs_block_extent *left = ext_tree_prev(be);
0098
0099 if (left && ext_can_merge(left, be)) {
0100 left->be_length += be->be_length;
0101 rb_erase(&be->be_node, root);
0102 nfs4_put_deviceid_node(be->be_device);
0103 kfree(be);
0104 return left;
0105 }
0106
0107 return be;
0108 }
0109
0110 static struct pnfs_block_extent *
0111 ext_try_to_merge_right(struct rb_root *root, struct pnfs_block_extent *be)
0112 {
0113 struct pnfs_block_extent *right = ext_tree_next(be);
0114
0115 if (right && ext_can_merge(be, right)) {
0116 be->be_length += right->be_length;
0117 rb_erase(&right->be_node, root);
0118 nfs4_put_deviceid_node(right->be_device);
0119 kfree(right);
0120 }
0121
0122 return be;
0123 }
0124
0125 static void __ext_put_deviceids(struct list_head *head)
0126 {
0127 struct pnfs_block_extent *be, *tmp;
0128
0129 list_for_each_entry_safe(be, tmp, head, be_list) {
0130 nfs4_put_deviceid_node(be->be_device);
0131 kfree(be);
0132 }
0133 }
0134
0135 static void
0136 __ext_tree_insert(struct rb_root *root,
0137 struct pnfs_block_extent *new, bool merge_ok)
0138 {
0139 struct rb_node **p = &root->rb_node, *parent = NULL;
0140 struct pnfs_block_extent *be;
0141
0142 while (*p) {
0143 parent = *p;
0144 be = ext_node(parent);
0145
0146 if (new->be_f_offset < be->be_f_offset) {
0147 if (merge_ok && ext_can_merge(new, be)) {
0148 be->be_f_offset = new->be_f_offset;
0149 if (be->be_state != PNFS_BLOCK_NONE_DATA)
0150 be->be_v_offset = new->be_v_offset;
0151 be->be_length += new->be_length;
0152 be = ext_try_to_merge_left(root, be);
0153 goto free_new;
0154 }
0155 p = &(*p)->rb_left;
0156 } else if (new->be_f_offset >= ext_f_end(be)) {
0157 if (merge_ok && ext_can_merge(be, new)) {
0158 be->be_length += new->be_length;
0159 be = ext_try_to_merge_right(root, be);
0160 goto free_new;
0161 }
0162 p = &(*p)->rb_right;
0163 } else {
0164 BUG();
0165 }
0166 }
0167
0168 rb_link_node(&new->be_node, parent, p);
0169 rb_insert_color(&new->be_node, root);
0170 return;
0171 free_new:
0172 nfs4_put_deviceid_node(new->be_device);
0173 kfree(new);
0174 }
0175
0176 static int
0177 __ext_tree_remove(struct rb_root *root,
0178 sector_t start, sector_t end, struct list_head *tmp)
0179 {
0180 struct pnfs_block_extent *be;
0181 sector_t len1 = 0, len2 = 0;
0182 sector_t orig_v_offset;
0183 sector_t orig_len;
0184
0185 be = __ext_tree_search(root, start);
0186 if (!be)
0187 return 0;
0188 if (be->be_f_offset >= end)
0189 return 0;
0190
0191 orig_v_offset = be->be_v_offset;
0192 orig_len = be->be_length;
0193
0194 if (start > be->be_f_offset)
0195 len1 = start - be->be_f_offset;
0196 if (ext_f_end(be) > end)
0197 len2 = ext_f_end(be) - end;
0198
0199 if (len2 > 0) {
0200 if (len1 > 0) {
0201 struct pnfs_block_extent *new;
0202
0203 new = kzalloc(sizeof(*new), GFP_ATOMIC);
0204 if (!new)
0205 return -ENOMEM;
0206
0207 be->be_length = len1;
0208
0209 new->be_f_offset = end;
0210 if (be->be_state != PNFS_BLOCK_NONE_DATA) {
0211 new->be_v_offset =
0212 orig_v_offset + orig_len - len2;
0213 }
0214 new->be_length = len2;
0215 new->be_state = be->be_state;
0216 new->be_tag = be->be_tag;
0217 new->be_device = nfs4_get_deviceid(be->be_device);
0218
0219 __ext_tree_insert(root, new, true);
0220 } else {
0221 be->be_f_offset = end;
0222 if (be->be_state != PNFS_BLOCK_NONE_DATA) {
0223 be->be_v_offset =
0224 orig_v_offset + orig_len - len2;
0225 }
0226 be->be_length = len2;
0227 }
0228 } else {
0229 if (len1 > 0) {
0230 be->be_length = len1;
0231 be = ext_tree_next(be);
0232 }
0233
0234 while (be && ext_f_end(be) <= end) {
0235 struct pnfs_block_extent *next = ext_tree_next(be);
0236
0237 rb_erase(&be->be_node, root);
0238 list_add_tail(&be->be_list, tmp);
0239 be = next;
0240 }
0241
0242 if (be && be->be_f_offset < end) {
0243 len1 = ext_f_end(be) - end;
0244 be->be_f_offset = end;
0245 if (be->be_state != PNFS_BLOCK_NONE_DATA)
0246 be->be_v_offset += be->be_length - len1;
0247 be->be_length = len1;
0248 }
0249 }
0250
0251 return 0;
0252 }
0253
0254 int
0255 ext_tree_insert(struct pnfs_block_layout *bl, struct pnfs_block_extent *new)
0256 {
0257 struct pnfs_block_extent *be;
0258 struct rb_root *root;
0259 int err = 0;
0260
0261 switch (new->be_state) {
0262 case PNFS_BLOCK_READWRITE_DATA:
0263 case PNFS_BLOCK_INVALID_DATA:
0264 root = &bl->bl_ext_rw;
0265 break;
0266 case PNFS_BLOCK_READ_DATA:
0267 case PNFS_BLOCK_NONE_DATA:
0268 root = &bl->bl_ext_ro;
0269 break;
0270 default:
0271 dprintk("invalid extent type\n");
0272 return -EINVAL;
0273 }
0274
0275 spin_lock(&bl->bl_ext_lock);
0276 retry:
0277 be = __ext_tree_search(root, new->be_f_offset);
0278 if (!be || be->be_f_offset >= ext_f_end(new)) {
0279 __ext_tree_insert(root, new, true);
0280 } else if (new->be_f_offset >= be->be_f_offset) {
0281 if (ext_f_end(new) <= ext_f_end(be)) {
0282 nfs4_put_deviceid_node(new->be_device);
0283 kfree(new);
0284 } else {
0285 sector_t new_len = ext_f_end(new) - ext_f_end(be);
0286 sector_t diff = new->be_length - new_len;
0287
0288 new->be_f_offset += diff;
0289 new->be_v_offset += diff;
0290 new->be_length = new_len;
0291 goto retry;
0292 }
0293 } else if (ext_f_end(new) <= ext_f_end(be)) {
0294 new->be_length = be->be_f_offset - new->be_f_offset;
0295 __ext_tree_insert(root, new, true);
0296 } else {
0297 struct pnfs_block_extent *split;
0298 sector_t new_len = ext_f_end(new) - ext_f_end(be);
0299 sector_t diff = new->be_length - new_len;
0300
0301 split = kmemdup(new, sizeof(*new), GFP_ATOMIC);
0302 if (!split) {
0303 err = -EINVAL;
0304 goto out;
0305 }
0306
0307 split->be_length = be->be_f_offset - split->be_f_offset;
0308 split->be_device = nfs4_get_deviceid(new->be_device);
0309 __ext_tree_insert(root, split, true);
0310
0311 new->be_f_offset += diff;
0312 new->be_v_offset += diff;
0313 new->be_length = new_len;
0314 goto retry;
0315 }
0316 out:
0317 spin_unlock(&bl->bl_ext_lock);
0318 return err;
0319 }
0320
0321 static bool
0322 __ext_tree_lookup(struct rb_root *root, sector_t isect,
0323 struct pnfs_block_extent *ret)
0324 {
0325 struct rb_node *node;
0326 struct pnfs_block_extent *be;
0327
0328 node = root->rb_node;
0329 while (node) {
0330 be = ext_node(node);
0331 if (isect < be->be_f_offset)
0332 node = node->rb_left;
0333 else if (isect >= ext_f_end(be))
0334 node = node->rb_right;
0335 else {
0336 *ret = *be;
0337 return true;
0338 }
0339 }
0340
0341 return false;
0342 }
0343
0344 bool
0345 ext_tree_lookup(struct pnfs_block_layout *bl, sector_t isect,
0346 struct pnfs_block_extent *ret, bool rw)
0347 {
0348 bool found = false;
0349
0350 spin_lock(&bl->bl_ext_lock);
0351 if (!rw)
0352 found = __ext_tree_lookup(&bl->bl_ext_ro, isect, ret);
0353 if (!found)
0354 found = __ext_tree_lookup(&bl->bl_ext_rw, isect, ret);
0355 spin_unlock(&bl->bl_ext_lock);
0356
0357 return found;
0358 }
0359
0360 int ext_tree_remove(struct pnfs_block_layout *bl, bool rw,
0361 sector_t start, sector_t end)
0362 {
0363 int err, err2;
0364 LIST_HEAD(tmp);
0365
0366 spin_lock(&bl->bl_ext_lock);
0367 err = __ext_tree_remove(&bl->bl_ext_ro, start, end, &tmp);
0368 if (rw) {
0369 err2 = __ext_tree_remove(&bl->bl_ext_rw, start, end, &tmp);
0370 if (!err)
0371 err = err2;
0372 }
0373 spin_unlock(&bl->bl_ext_lock);
0374
0375 __ext_put_deviceids(&tmp);
0376 return err;
0377 }
0378
0379 static int
0380 ext_tree_split(struct rb_root *root, struct pnfs_block_extent *be,
0381 sector_t split)
0382 {
0383 struct pnfs_block_extent *new;
0384 sector_t orig_len = be->be_length;
0385
0386 new = kzalloc(sizeof(*new), GFP_ATOMIC);
0387 if (!new)
0388 return -ENOMEM;
0389
0390 be->be_length = split - be->be_f_offset;
0391
0392 new->be_f_offset = split;
0393 if (be->be_state != PNFS_BLOCK_NONE_DATA)
0394 new->be_v_offset = be->be_v_offset + be->be_length;
0395 new->be_length = orig_len - be->be_length;
0396 new->be_state = be->be_state;
0397 new->be_tag = be->be_tag;
0398 new->be_device = nfs4_get_deviceid(be->be_device);
0399
0400 __ext_tree_insert(root, new, false);
0401 return 0;
0402 }
0403
0404 int
0405 ext_tree_mark_written(struct pnfs_block_layout *bl, sector_t start,
0406 sector_t len, u64 lwb)
0407 {
0408 struct rb_root *root = &bl->bl_ext_rw;
0409 sector_t end = start + len;
0410 struct pnfs_block_extent *be;
0411 int err = 0;
0412 LIST_HEAD(tmp);
0413
0414 spin_lock(&bl->bl_ext_lock);
0415
0416
0417
0418 err = __ext_tree_remove(&bl->bl_ext_ro, start, end, &tmp);
0419 if (err)
0420 goto out;
0421
0422
0423
0424
0425 for (be = __ext_tree_search(root, start); be; be = ext_tree_next(be)) {
0426 if (be->be_f_offset >= end)
0427 break;
0428
0429 if (be->be_state != PNFS_BLOCK_INVALID_DATA || be->be_tag)
0430 continue;
0431
0432 if (be->be_f_offset < start) {
0433 struct pnfs_block_extent *left = ext_tree_prev(be);
0434
0435 if (left && ext_can_merge(left, be)) {
0436 sector_t diff = start - be->be_f_offset;
0437
0438 left->be_length += diff;
0439
0440 be->be_f_offset += diff;
0441 be->be_v_offset += diff;
0442 be->be_length -= diff;
0443 } else {
0444 err = ext_tree_split(root, be, start);
0445 if (err)
0446 goto out;
0447 }
0448 }
0449
0450 if (ext_f_end(be) > end) {
0451 struct pnfs_block_extent *right = ext_tree_next(be);
0452
0453 if (right && ext_can_merge(be, right)) {
0454 sector_t diff = end - be->be_f_offset;
0455
0456 be->be_length -= diff;
0457
0458 right->be_f_offset -= diff;
0459 right->be_v_offset -= diff;
0460 right->be_length += diff;
0461 } else {
0462 err = ext_tree_split(root, be, end);
0463 if (err)
0464 goto out;
0465 }
0466 }
0467
0468 if (be->be_f_offset >= start && ext_f_end(be) <= end) {
0469 be->be_tag = EXTENT_WRITTEN;
0470 be = ext_try_to_merge_left(root, be);
0471 be = ext_try_to_merge_right(root, be);
0472 }
0473 }
0474 out:
0475 if (bl->bl_lwb < lwb)
0476 bl->bl_lwb = lwb;
0477 spin_unlock(&bl->bl_ext_lock);
0478
0479 __ext_put_deviceids(&tmp);
0480 return err;
0481 }
0482
0483 static size_t ext_tree_layoutupdate_size(struct pnfs_block_layout *bl, size_t count)
0484 {
0485 if (bl->bl_scsi_layout)
0486 return sizeof(__be32) + PNFS_SCSI_RANGE_SIZE * count;
0487 else
0488 return sizeof(__be32) + PNFS_BLOCK_EXTENT_SIZE * count;
0489 }
0490
0491 static void ext_tree_free_commitdata(struct nfs4_layoutcommit_args *arg,
0492 size_t buffer_size)
0493 {
0494 if (arg->layoutupdate_pages != &arg->layoutupdate_page) {
0495 int nr_pages = DIV_ROUND_UP(buffer_size, PAGE_SIZE), i;
0496
0497 for (i = 0; i < nr_pages; i++)
0498 put_page(arg->layoutupdate_pages[i]);
0499 vfree(arg->start_p);
0500 kfree(arg->layoutupdate_pages);
0501 } else {
0502 put_page(arg->layoutupdate_page);
0503 }
0504 }
0505
0506 static __be32 *encode_block_extent(struct pnfs_block_extent *be, __be32 *p)
0507 {
0508 p = xdr_encode_opaque_fixed(p, be->be_device->deviceid.data,
0509 NFS4_DEVICEID4_SIZE);
0510 p = xdr_encode_hyper(p, be->be_f_offset << SECTOR_SHIFT);
0511 p = xdr_encode_hyper(p, be->be_length << SECTOR_SHIFT);
0512 p = xdr_encode_hyper(p, 0LL);
0513 *p++ = cpu_to_be32(PNFS_BLOCK_READWRITE_DATA);
0514 return p;
0515 }
0516
0517 static __be32 *encode_scsi_range(struct pnfs_block_extent *be, __be32 *p)
0518 {
0519 p = xdr_encode_hyper(p, be->be_f_offset << SECTOR_SHIFT);
0520 return xdr_encode_hyper(p, be->be_length << SECTOR_SHIFT);
0521 }
0522
0523 static int ext_tree_encode_commit(struct pnfs_block_layout *bl, __be32 *p,
0524 size_t buffer_size, size_t *count, __u64 *lastbyte)
0525 {
0526 struct pnfs_block_extent *be;
0527 int ret = 0;
0528
0529 spin_lock(&bl->bl_ext_lock);
0530 for (be = ext_tree_first(&bl->bl_ext_rw); be; be = ext_tree_next(be)) {
0531 if (be->be_state != PNFS_BLOCK_INVALID_DATA ||
0532 be->be_tag != EXTENT_WRITTEN)
0533 continue;
0534
0535 (*count)++;
0536 if (ext_tree_layoutupdate_size(bl, *count) > buffer_size) {
0537
0538 ret = -ENOSPC;
0539 continue;
0540 }
0541
0542 if (bl->bl_scsi_layout)
0543 p = encode_scsi_range(be, p);
0544 else
0545 p = encode_block_extent(be, p);
0546 be->be_tag = EXTENT_COMMITTING;
0547 }
0548 *lastbyte = bl->bl_lwb - 1;
0549 bl->bl_lwb = 0;
0550 spin_unlock(&bl->bl_ext_lock);
0551
0552 return ret;
0553 }
0554
0555 int
0556 ext_tree_prepare_commit(struct nfs4_layoutcommit_args *arg)
0557 {
0558 struct pnfs_block_layout *bl = BLK_LO2EXT(NFS_I(arg->inode)->layout);
0559 size_t count = 0, buffer_size = PAGE_SIZE;
0560 __be32 *start_p;
0561 int ret;
0562
0563 dprintk("%s enter\n", __func__);
0564
0565 arg->layoutupdate_page = alloc_page(GFP_NOFS);
0566 if (!arg->layoutupdate_page)
0567 return -ENOMEM;
0568 start_p = page_address(arg->layoutupdate_page);
0569 arg->layoutupdate_pages = &arg->layoutupdate_page;
0570
0571 retry:
0572 ret = ext_tree_encode_commit(bl, start_p + 1, buffer_size, &count, &arg->lastbytewritten);
0573 if (unlikely(ret)) {
0574 ext_tree_free_commitdata(arg, buffer_size);
0575
0576 buffer_size = ext_tree_layoutupdate_size(bl, count);
0577 count = 0;
0578
0579 arg->layoutupdate_pages =
0580 kcalloc(DIV_ROUND_UP(buffer_size, PAGE_SIZE),
0581 sizeof(struct page *), GFP_NOFS);
0582 if (!arg->layoutupdate_pages)
0583 return -ENOMEM;
0584
0585 start_p = __vmalloc(buffer_size, GFP_NOFS);
0586 if (!start_p) {
0587 kfree(arg->layoutupdate_pages);
0588 return -ENOMEM;
0589 }
0590
0591 goto retry;
0592 }
0593
0594 *start_p = cpu_to_be32(count);
0595 arg->layoutupdate_len = ext_tree_layoutupdate_size(bl, count);
0596
0597 if (unlikely(arg->layoutupdate_pages != &arg->layoutupdate_page)) {
0598 void *p = start_p, *end = p + arg->layoutupdate_len;
0599 struct page *page = NULL;
0600 int i = 0;
0601
0602 arg->start_p = start_p;
0603 for ( ; p < end; p += PAGE_SIZE) {
0604 page = vmalloc_to_page(p);
0605 arg->layoutupdate_pages[i++] = page;
0606 get_page(page);
0607 }
0608 }
0609
0610 dprintk("%s found %zu ranges\n", __func__, count);
0611 return 0;
0612 }
0613
0614 void
0615 ext_tree_mark_committed(struct nfs4_layoutcommit_args *arg, int status)
0616 {
0617 struct pnfs_block_layout *bl = BLK_LO2EXT(NFS_I(arg->inode)->layout);
0618 struct rb_root *root = &bl->bl_ext_rw;
0619 struct pnfs_block_extent *be;
0620
0621 dprintk("%s status %d\n", __func__, status);
0622
0623 ext_tree_free_commitdata(arg, arg->layoutupdate_len);
0624
0625 spin_lock(&bl->bl_ext_lock);
0626 for (be = ext_tree_first(root); be; be = ext_tree_next(be)) {
0627 if (be->be_state != PNFS_BLOCK_INVALID_DATA ||
0628 be->be_tag != EXTENT_COMMITTING)
0629 continue;
0630
0631 if (status) {
0632
0633
0634
0635
0636
0637 be->be_tag = EXTENT_WRITTEN;
0638 } else {
0639 be->be_state = PNFS_BLOCK_READWRITE_DATA;
0640 be->be_tag = 0;
0641 }
0642
0643 be = ext_try_to_merge_left(root, be);
0644 be = ext_try_to_merge_right(root, be);
0645 }
0646 spin_unlock(&bl->bl_ext_lock);
0647 }