Support for write stream IDs
Subsystems (7)
PATCH v2 1/1 Support for write stream IDs
Hi,
v2 of this posting. Changes since v1:
- Rebased on top of current master.
- Fix EINVAL -> -EINVAL typo.
- Cleanup up BIO_STREAM_OFFSET definition.
- Pack i_streamid and f_streamid better into struct file and struct inode.
- Add a separate per-file hint, FADV_FILE_STREAMID. This only sets the write stream on the file, not the inode. FADV_STREAMID sets the hint both in the file and the inode.
block/bio.c | 2 ++ block/blk-core.c | 3 +++ fs/btrfs/extent_io.c | 1 + fs/btrfs/inode.c | 1 + fs/buffer.c | 4 ++-- fs/direct-io.c | 4 ++++ fs/ext4/page-io.c | 1 + fs/inode.c | 1 + fs/mpage.c | 1 + fs/open.c | 1 + fs/xfs/xfs_aops.c | 1 + include/linux/blk_types.h | 28 +++++++++++++++++++++++++++- include/linux/fs.h | 22 ++++++++++++++++++++++ include/uapi/linux/fadvise.h | 3 +++ mm/fadvise.c | 25 +++++++++++++++++++++++++ 15 files changed, 95 insertions(+), 3 deletions(-)
PATCH 1/7 block: add support for carrying a stream ID in a bio
The top bits of bio->bi_flags are reserved for keeping the allocation pool, set aside the next eight bits for carrying a stream ID. That leaves us with support for 255 streams, 0 is reserved as a "stream not set" value.
Add helpers for setting/getting stream ID of a bio.
--- block/bio.c | 2 ++ block/blk-core.c | 3 +++ include/linux/blk_types.h | 28 +++++++++++++++++++++++++++- 3 files changed, 32 insertions(+), 1 deletion(-)
block/bio.c +2 -0
@@ -567,6 +567,7 @@ void __bio_clone_fast(struct bio *bio, struct bio *bio_src) bio->bi_rw = bio_src->bi_rw; bio->bi_iter = bio_src->bi_iter; bio->bi_io_vec = bio_src->bi_io_vec; +bio_set_streamid (bio,bio_get_streamid (bio_src)); }EXPORT_SYMBOL (__bio_clone_fast);
@@ -672,6 +673,7 @@ integrity_clone: } } +bio_set_streamid (bio,bio_get_streamid (bio_src));return bio; }EXPORT_SYMBOL (bio_clone_bioset);
block/blk-core.c +3 -0
@@ -1941,6 +1941,9 @@ void generic_make_request(struct bio *bio) do { struct request_queue *q = bdev_get_queue(bio->bi_bdev); + if (bio_streamid_valid(bio)) + blk_add_trace_msg(q, "StreamID=%u", bio_get_streamid(bio)); + q->make_request_fn(q, bio); bio = bio_list_pop(current->bio_list);
include/linux/blk_types.h +27 -1
@@ -138,9 +138,35 @@ struct bio {#define BIO_POOL_BITS (4)#define BIO_POOL_NONE ((1UL << BIO_POOL_BITS) - 1)#define BIO_POOL_OFFSET (BITS_PER_LONG - BIO_POOL_BITS) -#define BIO_POOL_MASK (1UL << BIO_POOL_OFFSET)#define BIO_POOL_IDX (bio) ((bio)->bi_flags >> BIO_POOL_OFFSET) +/* +* after the pool bits, next 8 bits are for the stream id +*/ +#define BIO_STREAM_BITS (8) +#define BIO_STREAM_OFFSET (BIO_POOL_OFFSET - BIO_STREAM_BITS) +#define BIO_STREAM_MASK ((1 << BIO_STREAM_BITS) - 1) + +static inline unsigned long streamid_to_flags (unsigned int id) +{ +return (unsigned long ) (id &BIO_STREAM_MASK ) <<BIO_STREAM_OFFSET ; +} + +static inline void bio_set_streamid (struct bio *bio,unsigned int id) +{ + bio->bi_flags |=streamid_to_flags (id); +} + +static inline unsigned int bio_get_streamid (struct bio *bio) +{ +return (bio->bi_flags >>BIO_STREAM_OFFSET ) &BIO_STREAM_MASK ; +} + +static inline bool bio_streamid_valid (struct bio *bio) +{ +return bio_get_streamid (bio) !=0 ; +} +#endif /* CONFIG_BLOCK */ /*
Signature · 1 line
2.4.0.rc2.1.g3d6bc9a
PATCH 2/7 Add support for per-file/inode stream ID
In reply to Jens AxboeWriting on flash devices can be much more efficient, if we can inform the device what kind of data can be grouped together. If the device is able to group data together with similar lifetimes, then it can be more efficient in garbage collection. This, in turn, leads to lower write amplification, which is a win on both device wear and performance.
Add a new fadvise hint, POSIX_FADV_STREAMID, which sets the file and inode streamid. The file streamid is used if we have the file available at the time of the write (O_DIRECT), we use the inode streamid if not (buffered writeback). The fadvise hint uses the 'offset' field to specify a stream ID. A second POSIX_FADV_FILE_STREAMID sets only the stream ID on the file, not the inode.
--- fs/inode.c | 1 + fs/open.c | 1 + include/linux/fs.h | 22 ++++++++++++++++++++++ include/uapi/linux/fadvise.h | 3 +++ mm/fadvise.c | 25 +++++++++++++++++++++++++ 5 files changed, 52 insertions(+)
fs/inode.c +1 -0
@@ -149,6 +149,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode) inode->i_blocks =0 ; inode->i_bytes =0 ; inode->i_generation =0 ; + inode->i_streamid =0 ; inode->i_pipe =NULL ; inode->i_bdev =NULL ; inode->i_cdev =NULL ;
fs/open.c +1 -0
@@ -743,6 +743,7 @@ static int do_dentry_open(struct file *f, f->f_flags &= ~(O_CREAT |O_EXCL |O_NOCTTY |O_TRUNC );file_ra_state_init (&f->f_ra, f->f_mapping->host->i_mapping); + f->f_streamid =0 ;return 0 ;
include/linux/fs.h +22 -0
@@ -648,6 +648,7 @@ struct inode {#ifdef CONFIG_IMA atomic_t i_readcount;/* struct files open RO */ #endif +unsigned int i_streamid;const struct file_operations *i_fop;/* former ->i_op->default_file_ops */ struct file_lock_context *i_flctx;struct address_space i_data;
@@ -668,6 +669,14 @@ struct inode {void *i_private;/* fs or device private pointer */ }; +static inline unsigned int inode_streamid (struct inode *inode) +{ +if (inode) +return inode->i_streamid; + +return 0 ; +} +static inline int inode_unhashed (struct inode *inode) {return hlist_unhashed (&inode->i_hash);
@@ -839,6 +848,7 @@ struct file {* Must not be taken from IRQ context. */ spinlock_t f_lock; +unsigned int f_streamid;atomic_long_t f_count;unsigned int f_flags;fmode_t f_mode;
@@ -870,6 +880,18 @@ struct file_handle {unsigned char f_handle[0 ]; }; +/* +* If the file doesn't have a stream ID set, return the inode stream ID +* in case that has been set. +*/ +static inline unsigned int file_streamid (struct file *f) +{ +if (f->f_streamid) +return f->f_streamid; + +return inode_streamid (f->f_inode); +} +static inline struct file *get_file (struct file *f) {atomic_long_inc (&f->f_count);
include/uapi/linux/fadvise.h +3 -0
@@ -18,4 +18,7 @@#define POSIX_FADV_NOREUSE 5/* Data will be accessed once. */ #endif +#define POSIX_FADV_STREAMID 8/* associate stream ID with file+inode */ +#define POSIX_FADV_FILE_STREAMID 9/* associate stream ID with file */ +#endif /* FADVISE_H_INCLUDED */
mm/fadvise.c +25 -0
@@ -60,6 +60,8 @@ SYSCALL_DEFINE4(fadvise64_64, int, fd, loff_t, offset, loff_t, len, int, advice)case POSIX_FADV_WILLNEED :case POSIX_FADV_NOREUSE :case POSIX_FADV_DONTNEED : +case POSIX_FADV_STREAMID : +case POSIX_FADV_FILE_STREAMID :/* no bad return value, but ignore advice */ break ;default :
@@ -144,6 +146,29 @@ SYSCALL_DEFINE4(fadvise64_64, int, fd, loff_t, offset, loff_t, len, int, advice) } }break ; +case POSIX_FADV_STREAMID : +case POSIX_FADV_FILE_STREAMID : +/* +* streamid is stored in offset... we don't limit or check +* if the device supports streams, or if it does, if the +* stream nr is within the limits. 1 is the lowest valid +* stream id, 0 is "don't care/know". +*/ +if (offset != (unsigned int ) offset) { + ret = -EINVAL ; +break ; + } +/* +* FILE_STREAMID stores only in the file, STREAMID stores +* the stream hint in both the file and the inode. +*/ + f.file->f_streamid = offset; +if (advice ==POSIX_FADV_STREAMID ) { +spin_lock (&inode->i_lock); + inode->i_streamid = offset; +spin_unlock (&inode->i_lock); + } +break ;default : ret = -EINVAL ; }
Signature · 1 line
2.4.0.rc2.1.g3d6bc9a
PATCH 3/7 direct-io: add support for write stream IDs
In reply to Jens AxboeGet the streamid from the file, if any, and set it on the bio.
--- fs/direct-io.c | 4 ++++ 1 file changed, 4 insertions(+)
fs/direct-io.c +4 -0
@@ -76,6 +76,7 @@ struct dio_submit {int reap_counter;/* rate limit reaping */ sector_t final_block_in_request;/* doesn't change */ int boundary;/* prev block is at a boundary */ +int streamid;/* Write stream ID */ get_block_t *get_block;/* block mapping function */ dio_submit_t *submit_io;/* IO submition function */
@@ -371,6 +372,8 @@ dio_bio_alloc(struct dio *dio, struct dio_submit *sdio, sdio->bio = bio; sdio->logical_offset_in_bio = sdio->cur_page_fs_offset; + +bio_set_streamid (bio, sdio->streamid); }/*
@@ -1201,6 +1204,7 @@ do_blockdev_direct_IO(struct kiocb *iocb, struct inode *inode, sdio.blkbits = blkbits; sdio.blkfactor = i_blkbits - blkbits; sdio.block_in_file = offset >> blkbits; + sdio.streamid =file_streamid (iocb->ki_filp); sdio.get_block = get_block; dio->end_io = end_io;
Signature · 1 line
2.4.0.rc2.1.g3d6bc9a
PATCH 4/7 Add stream ID support for buffered mpage/__block_write_full_page()
In reply to Jens AxboePass on the inode stream ID to the bio allocation.
--- fs/buffer.c | 4 ++-- fs/mpage.c | 1 + 2 files changed, 3 insertions(+), 2 deletions(-)
fs/buffer.c +2 -2
@@ -1774,7 +1774,7 @@ static int __block_write_full_page(struct inode *inode, struct page *page, do { struct buffer_head *next = bh->b_this_page; if (buffer_async_write(bh)) { - submit_bh(write_op, bh); + _submit_bh(write_op, bh, streamid_to_flags(inode_streamid(inode))); nr_underway++; } bh = next;
@@ -1828,7 +1828,7 @@ recover:struct buffer_head *next = bh->b_this_page;if (buffer_async_write (bh)) {clear_buffer_dirty (bh); -submit_bh (write_op, bh); +_submit_bh (write_op, bh,streamid_to_flags (inode_streamid (inode))); nr_underway++; } bh = next;
fs/mpage.c +1 -0
@@ -605,6 +605,7 @@ alloc_new: bio_get_nr_vecs(bdev), GFP_NOFS|__GFP_HIGH);if (bio ==NULL ) goto confused; +bio_set_streamid (bio,inode_streamid (inode)); }/*
Signature · 1 line
2.4.0.rc2.1.g3d6bc9a
PATCH 5/7 btrfs: add support for write stream IDs
In reply to Jens AxboeBoth buffered and O_DIRECT.
--- fs/btrfs/extent_io.c | 1 + fs/btrfs/inode.c | 1 + 2 files changed, 2 insertions(+)
fs/btrfs/extent_io.c +1 -0
@@ -2838,6 +2838,7 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree,bio_add_page (bio, page, page_size, offset); bio->bi_end_io = end_io_func; bio->bi_private = tree; +bio_set_streamid (bio,inode_streamid (page->mapping->host));if (bio_ret) *bio_ret = bio;
fs/btrfs/inode.c +1 -0
@@ -8046,6 +8046,7 @@ static void btrfs_submit_direct(int rw, struct bio *dio_bio,atomic_set (&dip->pending_bios,0 ); btrfs_bio =btrfs_io_bio (io_bio); btrfs_bio->logical = file_offset; +bio_set_streamid (io_bio,inode_streamid (inode));if (write) { io_bio->bi_end_io = btrfs_endio_direct_write;
Signature · 1 line
2.4.0.rc2.1.g3d6bc9a
PATCH 6/7 xfs: add support for buffered writeback stream ID
In reply to Jens Axboe--- fs/xfs/xfs_aops.c | 1 + 1 file changed, 1 insertion(+)
fs/xfs/xfs_aops.c +1 -0
@@ -376,6 +376,7 @@ xfs_submit_ioend_bio(atomic_inc (&ioend->io_remaining); bio->bi_private = ioend; bio->bi_end_io = xfs_end_bio; +bio_set_streamid (bio, ioend->io_inode->i_streamid);submit_bio (wbc->sync_mode ==WB_SYNC_ALL ?WRITE_SYNC :WRITE , bio); }
Signature · 1 line
2.4.0.rc2.1.g3d6bc9a
PATCH 7/7 ext4: add support for write stream IDs
In reply to Jens Axboe--- fs/ext4/page-io.c | 1 + 1 file changed, 1 insertion(+)
fs/ext4/page-io.c +1 -0
@@ -389,6 +389,7 @@ submit_and_retry: ret =io_submit_init_bio (io, bh);if (ret)return ret; +bio_set_streamid (io->io_bio,inode_streamid (inode)); } ret =bio_add_page (io->io_bio, bh->b_page, bh->b_size,bh_offset (bh));if (ret != bh->b_size)
Signature · 1 line
2.4.0.rc2.1.g3d6bc9a