xfs_aops.c
来自「linux-2.4.29操作系统的源码」· C语言 代码 · 共 1,300 行 · 第 1/3 页
C
1,300 行
ssize_t size; loff_t offset = (loff_t)iblock << inode->i_blkbits; size = 1 << inode->i_blkbits; VOP_BMAP(vp, offset, size, create ? flags : BMAPI_READ, &iomap, &retpbbm, error); if (error) return -error; if (retpbbm == 0) return 0; if (iomap.iomap_bn != IOMAP_DADDR_NULL) { xfs_daddr_t bn; loff_t delta; /* For unwritten extents do not report a disk address on * the read case (treat as if we're reading into a hole). */ if (create || !(iomap.iomap_flags & IOMAP_UNWRITTEN)) { delta = offset - iomap.iomap_offset; delta >>= inode->i_blkbits; bn = iomap.iomap_bn >> (inode->i_blkbits - BBSHIFT); bn += delta; BUG_ON(!bn && !(iomap.iomap_flags & IOMAP_REALTIME)); bh_result->b_blocknr = bn; set_buffer_mapped(bh_result); } if (create && (iomap.iomap_flags & IOMAP_UNWRITTEN)) { set_buffer_unwritten(bh_result); set_buffer_delay(bh_result); } } /* If this is a realtime file, data might be on a new device */ bh_result->b_dev = iomap.iomap_target->pbr_kdev; /* If we previously allocated a block out beyond eof and * we are now coming back to use it then we will need to * flag it as new even if it has a disk address. */ if (create && ((!buffer_mapped(bh_result) && !buffer_uptodate(bh_result)) || (offset >= i_size_read(inode)))) { set_buffer_new(bh_result); } if (iomap.iomap_flags & IOMAP_DELAY) { BUG_ON(direct); if (create) { set_buffer_mapped(bh_result); set_buffer_uptodate(bh_result); } set_buffer_delay(bh_result); } return 0;}intlinvfs_get_block( struct inode *inode, long iblock, struct buffer_head *bh_result, int create){ return linvfs_get_block_core(inode, iblock, bh_result, create, 0, BMAPI_WRITE);}STATIC intlinvfs_get_block_direct( struct inode *inode, long iblock, struct buffer_head *bh_result, int create){ return linvfs_get_block_core(inode, iblock, bh_result, create, 1, BMAPI_WRITE|BMAPI_DIRECT);}STATIC intlinvfs_bmap( struct address_space *mapping, long block){ struct inode *inode = (struct inode *)mapping->host; vnode_t *vp = LINVFS_GET_VP(inode); int error; vn_trace_entry(vp, "linvfs_bmap", (inst_t *)__return_address); VOP_RWLOCK(vp, VRWLOCK_READ); VOP_FLUSH_PAGES(vp, (xfs_off_t)0, -1, 0, FI_REMAPF, error); VOP_RWUNLOCK(vp, VRWLOCK_READ); return generic_block_bmap(mapping, block, linvfs_get_block_direct);}STATIC intlinvfs_readpage( struct file *unused, struct page *page){ return block_read_full_page(page, linvfs_get_block);}STATIC voidxfs_count_page_state( struct page *page, int *delalloc, int *unmapped, int *unwritten){ struct buffer_head *bh, *head; *delalloc = *unmapped = *unwritten = 0; bh = head = page_buffers(page); do { if (buffer_uptodate(bh) && !buffer_mapped(bh)) (*unmapped) = 1; else if (buffer_unwritten(bh) && !buffer_delay(bh)) clear_buffer_unwritten(bh); else if (buffer_unwritten(bh)) (*unwritten) = 1; else if (buffer_delay(bh)) (*delalloc) = 1; } while ((bh = bh->b_this_page) != head);}/* * writepage: Called from one of two places: * * 1. we are flushing a delalloc buffer head. * * 2. we are writing out a dirty page. Typically the page dirty * state is cleared before we get here. In this case is it * conceivable we have no buffer heads. * * For delalloc space on the page we need to allocate space and * flush it. For unmapped buffer heads on the page we should * allocate space if the page is uptodate. For any other dirty * buffer heads on the page we should flush them. * * If we detect that a transaction would be required to flush * the page, we have to check the process flags first, if we * are already in a transaction or disk I/O during allocations * is off, we need to fail the writepage and redirty the page. */STATIC intlinvfs_writepage( struct page *page){ int error; int need_trans; int delalloc, unmapped, unwritten; struct inode *inode = page->mapping->host; xfs_page_trace(XFS_WRITEPAGE_ENTER, inode, page, 0); /* * We need a transaction if: * 1. There are delalloc buffers on the page * 2. The page is uptodate and we have unmapped buffers * 3. The page is uptodate and we have no buffers * 4. There are unwritten buffers on the page */ if (!page_has_buffers(page)) { unmapped = 1; need_trans = 1; } else { xfs_count_page_state(page, &delalloc, &unmapped, &unwritten); if (!PageUptodate(page)) unmapped = 0; need_trans = delalloc + unmapped + unwritten; } /* * If we need a transaction and the process flags say * we are already in a transaction, or no IO is allowed * then mark the page dirty again and leave the page * as is. */ if ((PFLAGS_TEST_FSTRANS() || PFLAGS_TEST_NOIO()) && need_trans) goto out_fail; /* * Delay hooking up buffer heads until we have * made our go/no-go decision. */ if (!page_has_buffers(page)) create_empty_buffers(page, inode->i_dev, 1 << inode->i_blkbits); /* * Convert delayed allocate, unwritten or unmapped space * to real space and flush out to disk. */ if (need_trans) PFLAGS_SET_NOIO(); error = xfs_page_state_convert(inode, page, 1, unmapped); if (need_trans) PFLAGS_CLEAR_NOIO(); if (error == -EAGAIN) goto out_fail; if (unlikely(error < 0)) { unlock_page(page); return error; } return 0;out_fail: SetPageDirty(page); unlock_page(page); return 0;}/* * Called to move a page into cleanable state - and from there * to be released. Possibly the page is already clean. We always * have buffer heads in this call. * * Returns 0 if the page is ok to release, 1 otherwise. * * Possible scenarios are: * * 1. We are being called to release a page which has been written * to via regular I/O. buffer heads will be dirty and possibly * delalloc. If no delalloc buffer heads in this case then we * can just return zero. * * 2. We are called to release a page which has been written via * mmap, all we need to do is ensure there is no delalloc * state in the buffer heads, if not we can let the caller * free them and we should come back later via writepage. */STATIC intlinvfs_release_page( struct page *page, int gfp_mask){ struct inode *inode = page->mapping->host; int dirty, delalloc, unmapped, unwritten; xfs_page_trace(XFS_RELEASEPAGE_ENTER, inode, page, gfp_mask); xfs_count_page_state(page, &delalloc, &unmapped, &unwritten); if (!delalloc && !unwritten) return 1; if (!(gfp_mask & __GFP_FS)) return 0; /* If we are already inside a transaction or the thread cannot * do I/O, we cannot release this page. */ if (PFLAGS_TEST_FSTRANS() || PFLAGS_TEST_NOIO()) return 0; /* * Convert delalloc space to real space, do not flush the * data out to disk, that will be done by the caller. * Never need to allocate space here - we will always * come back to writepage in that case. */ dirty = xfs_page_state_convert(inode, page, 0, 0); return (dirty == 0 && !unwritten) ? 1 : 0;}STATIC intlinvfs_prepare_write( struct file *file, struct page *page, unsigned int from, unsigned int to){ return block_prepare_write(page, from, to, linvfs_get_block);}/* * Initiate I/O on a kiobuf of user memory */STATIC intlinvfs_direct_IO( int rw, struct inode *inode, struct kiobuf *iobuf, unsigned long blocknr, int blocksize){ struct page **maplist; size_t page_offset; xfs_buf_t *pb; xfs_iomap_t iomap; int niomap, error = 0; int pb_flags, map_flags, pg_index = 0; size_t length, total; loff_t offset, map_size; size_t size; vnode_t *vp = LINVFS_GET_VP(inode); /* Note - although the iomap could have a 64-bit size, * kiobuf->length is only an int, so the min(map_size, length) * test will keep us from overflowing the pagebuf size_t size. */ total = length = iobuf->length; offset = blocknr; offset <<= inode->i_blkbits; maplist = iobuf->maplist; page_offset = iobuf->offset; map_flags = (rw ? BMAPI_WRITE : BMAPI_READ) | BMAPI_DIRECT; pb_flags = (rw ? PBF_WRITE : PBF_READ) | PBF_FORCEIO | PBF_DIRECTIO; while (length) { niomap = 1; VOP_BMAP(vp, offset, length, map_flags, &iomap, &niomap, error); if (unlikely(!error && niomap && (iomap.iomap_flags & IOMAP_DELAY))) {#ifdef DEBUG printk( "XFS: %s - direct IO (%lld:%ld) into a delayed allocate extent?\n", __FUNCTION__, (long long)offset, (long)length); xfs_stack_trace();#endif VOP_BMAP(vp, offset, length, BMAPI_ALLOCATE, &iomap, &niomap, error); } if (error) break; if (rw == WRITE) VMODIFY(vp); BUG_ON(niomap != 1); BUG_ON(iomap.iomap_flags & IOMAP_DELAY); map_size = iomap.iomap_bsize - iomap.iomap_delta; size = (size_t)min(map_size, (loff_t)length); if ((iomap.iomap_flags & IOMAP_HOLE) || ((iomap.iomap_flags & IOMAP_UNWRITTEN) && rw == READ)) { size_t zero_len = size; if (rw == WRITE) break; /* Need to zero it all */ while (zero_len) { struct page *page; size_t pg_len; pg_len = min((size_t) (PAGE_CACHE_SIZE - page_offset), zero_len); page = maplist[pg_index]; memset(kmap(page) + page_offset, 0, pg_len); flush_dcache_page(page); kunmap(page); zero_len -= pg_len; if ((pg_len + page_offset) == PAGE_CACHE_SIZE) { pg_index++; page_offset = 0; } else { page_offset = (page_offset + pg_len) & ~PAGE_CACHE_MASK; } } } else { int pg_count; pg_count = (size + page_offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; if ((pb = pagebuf_lookup(iomap.iomap_target, offset, size, pb_flags)) == NULL) { error = ENOMEM; break; } /* Need to hook up pagebuf to kiobuf pages */ pb->pb_pages = &maplist[pg_index]; pb->pb_offset = page_offset; pb->pb_page_count = pg_count; pb->pb_bn = iomap.iomap_bn + (iomap.iomap_delta >> BBSHIFT); error = pagebuf_iostart(pb, pb_flags); if (!error && (iomap.iomap_flags & IOMAP_UNWRITTEN)) { VOP_BMAP(vp, XFS_BUF_OFFSET(pb), XFS_BUF_SIZE(pb), BMAPI_UNWRITTEN, NULL, NULL, error); } pagebuf_rele(pb); if (error) break; page_offset = (page_offset + size) & ~PAGE_CACHE_MASK; if (page_offset) pg_count--; pg_index += pg_count; } offset += size; length -= size; } if (error) return -error; return (int)(total - length);}struct address_space_operations linvfs_aops = { .readpage = linvfs_readpage, .writepage = linvfs_writepage, .sync_page = block_sync_page, .releasepage = linvfs_release_page, .prepare_write = linvfs_prepare_write, .commit_write = generic_commit_write, .bmap = linvfs_bmap, .direct_IO = linvfs_direct_IO,};
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?