You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
/* * Historically, a buffer_head was used to map a single block * within a page, and of course as the unit of I/O through the * filesystem and block layers. Nowadays the basic I/O unit * is the bio, and buffer_heads are used for extracting block * mappings (via a get_block_t call), for tracking state within * a page (via a page_mapping) and for wrapping bio submission * for backward compatibility reasons (e.g. submit_bh). */structbuffer_head {
unsigned longb_state; /* buffer state bitmap (see above) */structbuffer_head*b_this_page;/* circular list of page's buffers */structpage*b_page; /* the page this bh is mapped to */sector_tb_blocknr; /* start block number */size_tb_size; /* size of mapping */char*b_data; /* pointer to data within the page */structblock_device*b_bdev;
bh_end_io_t*b_end_io; /* I/O completion */void*b_private; /* reserved for b_end_io */structlist_headb_assoc_buffers; /* associated with another mapping */structaddress_space*b_assoc_map; /* mapping this buffer is associated with */atomic_tb_count; /* users using this buffer_head */
};
/* * was unsigned short, but we might as well be ready for > 64kB I/O pages */structbio_vec {
structpage*bv_page; /*指向这个缓冲区所驻留的物理页*/unsigned intbv_len; /*这个缓冲区以字节为单位的大小*/unsigned intbv_offset; /*缓冲区所驻留的页中以字节为单位的偏移量*/
};
...
structbvec_iter {
sector_tbi_sector; /* device address in 512 byte sectors */unsigned intbi_size; /* residual I/O count */unsigned intbi_idx; /* current index into bvl_vec */unsigned intbi_bvec_done; /* number of bytes completed in current bvec */
};
/* * main unit of I/O for the block layer and lower layers (ie drivers and * stacking drivers) */structbio {
structbio*bi_next; /* request queue link */structblock_device*bi_bdev; /* 相关的块设备 */unsigned intbi_flags; /* status, command, etc */intbi_error;
unsigned longbi_rw; /* bottom bits READ/WRITE, * top bits priority */structbvec_iterbi_iter;
/* Number of segments in this BIO after * physical address coalescing is performed. */unsigned intbi_phys_segments;
/* * To keep track of the max segment size, we account for the * sizes of the first and last mergeable segments in this bio. */unsigned intbi_seg_front_size;
unsigned intbi_seg_back_size;
atomic_t__bi_remaining;
bio_end_io_t*bi_end_io;
void*bi_private;
#ifdefCONFIG_BLK_CGROUP/* * Optional ioc and css associated with this bio. Put on bio * release. Read comment on top of bio_associate_current(). */structio_context*bi_ioc;
structcgroup_subsys_state*bi_css;
#endifunion {
#if defined(CONFIG_BLK_DEV_INTEGRITY)
structbio_integrity_payload*bi_integrity; /* data integrity */#endif
};
unsigned shortbi_vcnt; /* how many bio_vec's *//* * Everything starting with bi_max_vecs will be preserved by bio_reset() */unsigned shortbi_max_vecs; /* max bvl_vecs we can hold */atomic_t__bi_cnt; /* pin count */structbio_vec*bi_io_vec; /* the actual vec list */structbio_set*bi_pool;
/* * We can inline a number of vecs at the end of the bio, to avoid * double allocations for a small number of bio_vecs. This member * MUST obviously be kept at the very end of the bio. */structbio_vecbi_inline_vecs[0];
};
/* * get a reference to a bio, so it won't disappear. the intended use is * something like: * * bio_get(bio); * submit_bio(rw, bio); * if (bio->bi_flags ...) * do_something * bio_put(bio); * * without the bio_get(), it could potentially complete I/O before submit_bio * returns. and then bio would be freed memory when if (bio->bi_flags ...) * runs */staticinlinevoidbio_get(structbio*bio)
{
bio->bi_flags |= (1 << BIO_REFFED);
smp_mb__before_atomic();
atomic_inc(&bio->__bi_cnt);
}
block/bio.c
/** * bio_put - release a reference to a bio * @bio: bio to release reference to * * Description: * Put a reference to a &struct bio, either one you have gotten with * bio_alloc, bio_get or bio_clone. The last put of a bio will free it. **/voidbio_put(structbio*bio)
{
if (!bio_flagged(bio, BIO_REFFED)) /*该bio没有被引用*/bio_free(bio); /*释放该bio*/else { /*该bio被引用了*/BIO_BUG_ON(!atomic_read(&bio->__bi_cnt));
/* * last put frees it */if (atomic_dec_and_test(&bio->__bi_cnt)) /*引用计数减1后测试,如果引用计数不为0,则什么都不做*/bio_free(bio); /*引用计数减为0,释放该bio*/
}
}
EXPORT_SYMBOL(bio_put);