/* * We're now finished for good with this ioend structure. Update the page * state, release holds on bios, and finally free up memory. Do not use the * ioend after this. */ STATIC void xfs_destroy_ioend( struct xfs_ioend *ioend, int error) { struct inode *inode = ioend->io_inode; struct bio *last = ioend->io_bio; struct bio *bio, *next; for (bio = &ioend->io_inline_bio; bio; bio = next) { struct bio_vec *bvec; int i; /* * For the last bio, bi_private points to the ioend, so we * need to explicitly end the iteration here. */ if (bio == last) next = NULL; else next = bio->bi_private; /* walk each page on bio, ending page IO on them */ bio_for_each_segment_all(bvec, bio, i) xfs_finish_page_writeback(inode, bvec, error); bio_put(bio); } }
static void log_end_io(struct bio *bio) { struct log_writes_c *lc = bio->bi_private; struct bio_vec *bvec; int i; if (bio->bi_error) { unsigned long flags; DMERR("Error writing log block, error=%d", bio->bi_error); spin_lock_irqsave(&lc->blocks_lock, flags); lc->logging_enabled = false; spin_unlock_irqrestore(&lc->blocks_lock, flags); } bio_for_each_segment_all(bvec, bio, i) __free_page(bvec->bv_page); put_io_block(lc); bio_put(bio); }
/** * blkdev_report_zones - Get zones information * @bdev: Target block device * @sector: Sector from which to report zones * @zones: Array of zone structures where to return the zones information * @nr_zones: Number of zone structures in the zone array * @gfp_mask: Memory allocation flags (for bio_alloc) * * Description: * Get zone information starting from the zone containing @sector. * The number of zone information reported may be less than the number * requested by @nr_zones. The number of zones actually reported is * returned in @nr_zones. */ int blkdev_report_zones(struct block_device *bdev, sector_t sector, struct blk_zone *zones, unsigned int *nr_zones, gfp_t gfp_mask) { struct request_queue *q = bdev_get_queue(bdev); struct blk_zone_report_hdr *hdr; unsigned int nrz = *nr_zones; struct page *page; unsigned int nr_rep; size_t rep_bytes; unsigned int nr_pages; struct bio *bio; struct bio_vec *bv; unsigned int i, n, nz; unsigned int ofst; void *addr; int ret = 0; if (!q) return -ENXIO; if (!blk_queue_is_zoned(q)) return -EOPNOTSUPP; if (!nrz) return 0; if (sector > bdev->bd_part->nr_sects) { *nr_zones = 0; return 0; } /* * The zone report has a header. So make room for it in the * payload. Also make sure that the report fits in a single BIO * that will not be split down the stack. */ rep_bytes = sizeof(struct blk_zone_report_hdr) + sizeof(struct blk_zone) * nrz; rep_bytes = (rep_bytes + PAGE_SIZE - 1) & PAGE_MASK; if (rep_bytes > (queue_max_sectors(q) << 9)) rep_bytes = queue_max_sectors(q) << 9; nr_pages = min_t(unsigned int, BIO_MAX_PAGES, rep_bytes >> PAGE_SHIFT); nr_pages = min_t(unsigned int, nr_pages, queue_max_segments(q)); bio = bio_alloc(gfp_mask, nr_pages); if (!bio) return -ENOMEM; bio->bi_bdev = bdev; bio->bi_iter.bi_sector = blk_zone_start(q, sector); bio_set_op_attrs(bio, REQ_OP_ZONE_REPORT, 0); for (i = 0; i < nr_pages; i++) { page = alloc_page(gfp_mask); if (!page) { ret = -ENOMEM; goto out; } if (!bio_add_page(bio, page, PAGE_SIZE, 0)) { __free_page(page); break; } } if (i == 0) ret = -ENOMEM; else ret = submit_bio_wait(bio); if (ret) goto out; /* * Process the report result: skip the header and go through the * reported zones to fixup and fixup the zone information for * partitions. At the same time, return the zone information into * the zone array. */ n = 0; nz = 0; nr_rep = 0; bio_for_each_segment_all(bv, bio, i) { if (!bv->bv_page) break; addr = kmap_atomic(bv->bv_page); /* Get header in the first page */ ofst = 0; if (!nr_rep) { hdr = (struct blk_zone_report_hdr *) addr; nr_rep = hdr->nr_zones; ofst = sizeof(struct blk_zone_report_hdr); } /* Fixup and report zones */ while (ofst < bv->bv_len && n < nr_rep && nz < nrz) { if (blkdev_report_zone(bdev, addr + ofst, &zones[nz])) nz++; ofst += sizeof(struct blk_zone); n++; } kunmap_atomic(addr); if (n >= nr_rep || nz >= nrz) break; } out: bio_for_each_segment_all(bv, bio, i) __free_page(bv->bv_page); bio_put(bio); if (ret == 0) *nr_zones = nz; return ret; }