// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
*/
/** * gfs2_pin - Pin a buffer in memory * @sdp: The superblock * @bh: The buffer to be pinned * * The log lock must be held when calling this function
*/ void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh)
{ struct gfs2_bufdata *bd;
BUG_ON(!current->journal_info);
clear_buffer_dirty(bh); if (test_set_buffer_pinned(bh))
gfs2_assert_withdraw(sdp, 0); if (!buffer_uptodate(bh))
gfs2_io_error_bh_wd(sdp, bh);
bd = bh->b_private; /* If this buffer is in the AIL and it has already been written * to in-place disk block, remove it from the AIL.
*/
spin_lock(&sdp->sd_ail_lock); if (bd->bd_tr)
list_move(&bd->bd_ail_st_list, &bd->bd_tr->tr_ail2_list);
spin_unlock(&sdp->sd_ail_lock);
get_bh(bh);
atomic_inc(&sdp->sd_log_pinned);
trace_gfs2_pin(bd, 1);
}
/** * gfs2_unpin - Unpin a buffer * @sdp: the filesystem the buffer belongs to * @bh: The buffer to unpin * @tr: The system transaction being flushed
*/
/** * gfs2_end_log_write_bh - end log write of pagecache data with buffers * @sdp: The superblock * @folio: The folio * @offset: The first byte within the folio that completed * @size: The number of bytes that completed * @error: The i/o status * * This finds the relevant buffers and unlocks them and sets the * error flag according to the status of the i/o request. This is * used when the log is writing data which has an in-place version * that is pinned in the pagecache.
*/
bh = folio_buffers(folio); while (bh_offset(bh) < offset)
bh = bh->b_this_page; do { if (error)
mark_buffer_write_io_error(bh);
unlock_buffer(bh);
next = bh->b_this_page;
size -= bh->b_size;
brelse(bh);
bh = next;
} while (bh && size);
}
/** * gfs2_end_log_write - end of i/o to the log * @bio: The bio * * Each bio_vec contains either data from the pagecache or data * relating to the log itself. Here we iterate over the bio_vec * array, processing both kinds of data. *
*/
bio_put(bio); if (atomic_dec_and_test(&sdp->sd_log_in_flight))
wake_up(&sdp->sd_log_flush_wait);
}
/** * gfs2_log_submit_bio - Submit any pending log bio * @biop: Address of the bio pointer * @opf: REQ_OP | op_flags * * Submit any pending part-built or full bio to the block device. If * there is no pending bio, then this is a no-op.
*/
void gfs2_log_submit_bio(struct bio **biop, blk_opf_t opf)
{ struct bio *bio = *biop; if (bio) { struct gfs2_sbd *sdp = bio->bi_private;
atomic_inc(&sdp->sd_log_in_flight);
bio->bi_opf = opf;
submit_bio(bio);
*biop = NULL;
}
}
/** * gfs2_log_alloc_bio - Allocate a bio * @sdp: The super block * @blkno: The device block number we want to write to * @end_io: The bi_end_io callback * * Allocate a new bio, initialize it with the given parameters and return it. * * Returns: The newly allocated bio
*/
/** * gfs2_log_get_bio - Get cached log bio, or allocate a new one * @sdp: The super block * @blkno: The device block number we want to write to * @biop: The bio to get or allocate * @op: REQ_OP * @end_io: The bi_end_io callback * @flush: Always flush the current bio and allocate a new one? * * If there is a cached bio, then if the next block number is sequential * with the previous one, return it, otherwise flush the bio to the * device. If there is no cached bio, or we just flushed it, then * allocate a new one. * * Returns: The bio to use for log writes
*/
staticstruct bio *gfs2_log_get_bio(struct gfs2_sbd *sdp, u64 blkno, struct bio **biop, enum req_op op,
bio_end_io_t *end_io, bool flush)
{ struct bio *bio = *biop;
/** * gfs2_log_write - write to log * @sdp: the filesystem * @jd: The journal descriptor * @page: the page to write * @size: the size of the data to write * @offset: the offset within the page * @blkno: block number of the log entry * * Try and add the page segment to the current bio. If that fails, * submit the current bio to the device and create a new one, and * then add the page segment to that.
*/
bio = gfs2_log_get_bio(sdp, blkno, &jd->jd_log_bio, REQ_OP_WRITE,
gfs2_end_log_write, false);
ret = bio_add_page(bio, page, size, offset); if (ret == 0) {
bio = gfs2_log_get_bio(sdp, blkno, &jd->jd_log_bio,
REQ_OP_WRITE, gfs2_end_log_write, true);
ret = bio_add_page(bio, page, size, offset);
WARN_ON(ret == 0);
}
}
/** * gfs2_log_write_bh - write a buffer's content to the log * @sdp: The super block * @bh: The buffer pointing to the in-place location * * This writes the content of the buffer to the next available location * in the log. The buffer will be unlocked once the i/o to the log has * completed.
*/
/** * gfs2_log_write_page - write one block stored in a page, into the log * @sdp: The superblock * @page: The struct page * * This writes the first block-sized part of the page into the log. Note * that the page must have been allocated from the gfs2_page_pool mempool * and that after this has been called, ownership has been transferred and * the page may be freed at any time.
*/
/** * gfs2_end_log_read - end I/O callback for reads from the log * @bio: The bio * * Simply unlock the pages in the bio. The main thread will wait on them and * process them in order as necessary.
*/ staticvoid gfs2_end_log_read(struct bio *bio)
{ int error = blk_status_to_errno(bio->bi_status); struct folio_iter fi;
bio_for_each_folio_all(fi, bio) { /* We're abusing wb_err to get the error to gfs2_find_jhead */
filemap_set_wb_err(fi.folio->mapping, error);
folio_end_read(fi.folio, !error);
}
bio_put(bio);
}
/** * gfs2_jhead_folio_search - Look for the journal head in a given page. * @jd: The journal descriptor * @head: The journal head to start from * @folio: The folio to look in * * Returns: 1 if found, 0 otherwise.
*/ staticbool gfs2_jhead_folio_search(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head, struct folio *folio)
{ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); struct gfs2_log_header_host lh; void *kaddr; unsignedint offset; bool ret = false;
/** * gfs2_jhead_process_page - Search/cleanup a page * @jd: The journal descriptor * @index: Index of the page to look into * @head: The journal head to start from * @done: If set, perform only cleanup, else search and set if found. * * Find the folio with 'index' in the journal's mapping. Search the folio for * the journal head if requested (cleanup == false). Release refs on the * folio so the page cache can reclaim it. We grabbed a * reference on this folio twice, first when we did a filemap_grab_folio() * to obtain the folio to add it to the bio and second when we do a * filemap_get_folio() here to get the folio to wait on while I/O on it is being * completed. * This function is also used to free up a folio we might've grabbed but not * used. Maybe we added it to a bio, but not submitted it for I/O. Or we * submitted the I/O, but we already found the jhead so we only need to drop * our references to the folio.
*/
/** * gfs2_find_jhead - find the head of a log * @jd: The journal descriptor * @head: The log descriptor for the head of the log is returned here * * Do a search of a journal by reading it in large chunks using bios and find * the valid log entry with the highest sequence number. (i.e. the log head) * * Returns: 0 on success, errno otherwise
*/ int gfs2_find_jhead(struct gfs2_jdesc *jd, struct gfs2_log_header_host *head)
{ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode); struct address_space *mapping = jd->jd_inode->i_mapping; unsignedint block = 0, blocks_submitted = 0, blocks_read = 0; unsignedint bsize = sdp->sd_sb.sb_bsize, off; unsignedint bsize_shift = sdp->sd_sb.sb_bsize_shift; unsignedint shift = PAGE_SHIFT - bsize_shift; unsignedint max_blocks = 2 * 1024 * 1024 >> bsize_shift; struct gfs2_journal_extent *je; int ret = 0; struct bio *bio = NULL; struct folio *folio = NULL; bool done = false;
errseq_t since;
memset(head, 0, sizeof(*head)); if (list_empty(&jd->extent_list))
gfs2_map_journal_extents(sdp, jd);
if (bio_end_sector(bio) == sector) { if (bio_add_folio(bio, folio, bsize, off)) goto block_added;
} if (off) { unsignedint blocks =
(PAGE_SIZE - off) >> bsize_shift;
bio = gfs2_chain_bio(bio, blocks); goto add_block_to_new_bio;
}
}
if (bio) {
blocks_submitted = block;
submit_bio(bio);
}
bio = gfs2_log_alloc_bio(sdp, dblock, gfs2_end_log_read);
bio->bi_opf = REQ_OP_READ;
add_block_to_new_bio: if (!bio_add_folio(bio, folio, bsize, off))
BUG();
block_added:
off += bsize; if (off == folio_size(folio))
folio = NULL; if (blocks_submitted <= blocks_read + max_blocks) { /* Keep at least one bio in flight */ continue;
}
gfs2_jhead_process_page(jd, blocks_read >> shift, head, &done);
blocks_read += PAGE_SIZE >> bsize_shift; if (done) goto out; /* found */
}
}
#define obsolete_rgrp_replay \ "Replaying 0x%llx from jid=%d/0x%llx but we already have a bh!\n" #define obsolete_rgrp_replay2 \ "busy:%d, pinned:%d rg_gen:0x%llx, j_gen:0x%llx\n"
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.