filter_io_26.c
来自「lustre 1.6.5 source code」· C语言 代码 · 共 811 行 · 第 1/3 页
C
811 行
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- * vim:expandtab:shiftwidth=8:tabstop=8: * * linux/fs/obdfilter/filter_io.c * * Copyright (c) 2001-2003 Cluster File Systems, Inc. * Author: Peter Braam <braam@clusterfs.com> * Author: Andreas Dilger <adilger@clusterfs.com> * Author: Phil Schwan <phil@clusterfs.com> * * This file is part of the Lustre file system, http://www.lustre.org * Lustre is a trademark of Cluster File Systems, Inc. * * You may have signed or agreed to another license before downloading * this software. If so, you are bound by the terms and conditions * of that agreement, and the following does not apply to you. See the * LICENSE file included with this distribution for more information. * * If you did not agree to a different license, then this copy of Lustre * is open source software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * In either case, Lustre is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * license text for more details. */#ifndef AUTOCONF_INCLUDED#include <linux/config.h>#endif#include <linux/module.h>#include <linux/pagemap.h> // XXX kill me soon#include <linux/version.h>#include <linux/buffer_head.h>#define DEBUG_SUBSYSTEM S_FILTER#include <obd_class.h>#include <lustre_fsfilt.h>#include <lustre_quota.h>#include "filter_internal.h"/* 512byte block min */#define MAX_BLOCKS_PER_PAGE (CFS_PAGE_SIZE / 512)struct filter_iobuf { atomic_t dr_numreqs; /* number of reqs being processed */ wait_queue_head_t dr_wait; int dr_max_pages; int dr_npages; int dr_error; struct page **dr_pages; unsigned long *dr_blocks; spinlock_t dr_lock; /* IRQ lock */ unsigned int dr_ignore_quota:1; struct filter_obd *dr_filter;};static void record_start_io(struct filter_iobuf *iobuf, int rw, int size, struct obd_export *exp){ struct filter_obd *filter = iobuf->dr_filter; atomic_inc(&iobuf->dr_numreqs); if (rw == OBD_BRW_READ) { atomic_inc(&filter->fo_r_in_flight); lprocfs_oh_tally(&filter->fo_filter_stats.hist[BRW_R_RPC_HIST], atomic_read(&filter->fo_r_in_flight)); lprocfs_oh_tally_log2(&filter->fo_filter_stats.hist[BRW_R_DISK_IOSIZE], size); lprocfs_oh_tally(&exp->exp_filter_data.fed_brw_stats.hist[BRW_R_RPC_HIST], atomic_read(&filter->fo_r_in_flight)); lprocfs_oh_tally_log2(&exp->exp_filter_data.fed_brw_stats.hist[BRW_R_DISK_IOSIZE], size); } else { atomic_inc(&filter->fo_w_in_flight); lprocfs_oh_tally(&filter->fo_filter_stats.hist[BRW_W_RPC_HIST], atomic_read(&filter->fo_w_in_flight)); lprocfs_oh_tally_log2(&filter->fo_filter_stats.hist[BRW_W_DISK_IOSIZE], size); lprocfs_oh_tally(&exp->exp_filter_data.fed_brw_stats.hist[BRW_W_RPC_HIST], atomic_read(&filter->fo_w_in_flight)); lprocfs_oh_tally_log2(&exp->exp_filter_data.fed_brw_stats.hist[BRW_W_DISK_IOSIZE], size); }}static void record_finish_io(struct filter_iobuf *iobuf, int rw, int rc){ struct filter_obd *filter = iobuf->dr_filter; /* CAVEAT EMPTOR: possibly in IRQ context * DO NOT record procfs stats here!!! */ if (rw == OBD_BRW_READ) atomic_dec(&filter->fo_r_in_flight); else atomic_dec(&filter->fo_w_in_flight); if (atomic_dec_and_test(&iobuf->dr_numreqs)) wake_up(&iobuf->dr_wait);}static int dio_complete_routine(struct bio *bio, unsigned int done, int error){ struct filter_iobuf *iobuf = bio->bi_private; unsigned long flags;#ifdef HAVE_PAGE_CONSTANT struct bio_vec *bvl; int i;#endif /* CAVEAT EMPTOR: possibly in IRQ context * DO NOT record procfs stats here!!! */ if (bio->bi_size) /* Not complete */ return 1; if (iobuf == NULL) { CERROR("***** bio->bi_private is NULL! This should never " "happen. Normally, I would crash here, but instead I " "will dump the bio contents to the console. Please " "report this to CFS, along with any interesting " "messages leading up to this point (like SCSI errors, " "perhaps). Because bi_private is NULL, I can't wake up " "the thread that initiated this I/O -- so you will " "probably have to reboot this node.\n"); CERROR("bi_next: %p, bi_flags: %lx, bi_rw: %lu, bi_vcnt: %d, " "bi_idx: %d, bi->size: %d, bi_end_io: %p, bi_cnt: %d, " "bi_private: %p\n", bio->bi_next, bio->bi_flags, bio->bi_rw, bio->bi_vcnt, bio->bi_idx, bio->bi_size, bio->bi_end_io, atomic_read(&bio->bi_cnt), bio->bi_private); return 0; }#ifdef HAVE_PAGE_CONSTANT bio_for_each_segment(bvl, bio, i) ClearPageConstant(bvl->bv_page);#endif spin_lock_irqsave(&iobuf->dr_lock, flags); if (iobuf->dr_error == 0) iobuf->dr_error = error; spin_unlock_irqrestore(&iobuf->dr_lock, flags); record_finish_io(iobuf, test_bit(BIO_RW, &bio->bi_rw) ? OBD_BRW_WRITE : OBD_BRW_READ, error); /* Completed bios used to be chained off iobuf->dr_bios and freed in * filter_clear_dreq(). It was then possible to exhaust the biovec-256 * mempool when serious on-disk fragmentation was encountered, * deadlocking the OST. The bios are now released as soon as complete * so the pool cannot be exhausted while IOs are competing. bug 10076 */ bio_put(bio); return 0;}static int can_be_merged(struct bio *bio, sector_t sector){ unsigned int size; if (!bio) return 0; size = bio->bi_size >> 9; return bio->bi_sector + size == sector ? 1 : 0;}struct filter_iobuf *filter_alloc_iobuf(struct filter_obd *filter, int rw, int num_pages){ struct filter_iobuf *iobuf; LASSERTF(rw == OBD_BRW_WRITE || rw == OBD_BRW_READ, "%x\n", rw); OBD_ALLOC(iobuf, sizeof(*iobuf)); if (iobuf == NULL) goto failed_0; OBD_ALLOC(iobuf->dr_pages, num_pages * sizeof(*iobuf->dr_pages)); if (iobuf->dr_pages == NULL) goto failed_1; OBD_ALLOC(iobuf->dr_blocks, MAX_BLOCKS_PER_PAGE * num_pages * sizeof(*iobuf->dr_blocks)); if (iobuf->dr_blocks == NULL) goto failed_2; iobuf->dr_filter = filter; init_waitqueue_head(&iobuf->dr_wait); atomic_set(&iobuf->dr_numreqs, 0); spin_lock_init(&iobuf->dr_lock); iobuf->dr_max_pages = num_pages; iobuf->dr_npages = 0; iobuf->dr_error = 0; RETURN(iobuf); failed_2: OBD_FREE(iobuf->dr_pages, num_pages * sizeof(*iobuf->dr_pages)); failed_1: OBD_FREE(iobuf, sizeof(*iobuf)); failed_0: RETURN(ERR_PTR(-ENOMEM));}static void filter_clear_iobuf(struct filter_iobuf *iobuf){ iobuf->dr_npages = 0; iobuf->dr_error = 0; atomic_set(&iobuf->dr_numreqs, 0);}void filter_free_iobuf(struct filter_iobuf *iobuf){ int num_pages = iobuf->dr_max_pages; filter_clear_iobuf(iobuf); OBD_FREE(iobuf->dr_blocks, MAX_BLOCKS_PER_PAGE * num_pages * sizeof(*iobuf->dr_blocks)); OBD_FREE(iobuf->dr_pages, num_pages * sizeof(*iobuf->dr_pages)); OBD_FREE_PTR(iobuf);}void filter_iobuf_put(struct filter_obd *filter, struct filter_iobuf *iobuf, struct obd_trans_info *oti){ int thread_id = oti ? oti->oti_thread_id : -1; if (unlikely(thread_id < 0)) { filter_free_iobuf(iobuf); return; } LASSERTF(filter->fo_iobuf_pool[thread_id] == iobuf, "iobuf mismatch for thread %d: pool %p iobuf %p\n", thread_id, filter->fo_iobuf_pool[thread_id], iobuf); filter_clear_iobuf(iobuf);}int filter_iobuf_add_page(struct obd_device *obd, struct filter_iobuf *iobuf, struct inode *inode, struct page *page){ LASSERT(iobuf->dr_npages < iobuf->dr_max_pages); iobuf->dr_pages[iobuf->dr_npages++] = page; return 0;}int filter_do_bio(struct obd_export *exp, struct inode *inode, struct filter_iobuf *iobuf, int rw){ struct obd_device *obd = exp->exp_obd; int blocks_per_page = CFS_PAGE_SIZE >> inode->i_blkbits; struct page **pages = iobuf->dr_pages; int npages = iobuf->dr_npages; unsigned long *blocks = iobuf->dr_blocks; int total_blocks = npages * blocks_per_page; int sector_bits = inode->i_sb->s_blocksize_bits - 9; unsigned int blocksize = inode->i_sb->s_blocksize; struct bio *bio = NULL; int frags = 0; unsigned long start_time = jiffies; struct page *page; unsigned int page_offset; sector_t sector; int nblocks; int block_idx;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?