📄 file.c
字号:
if (bh) { bh->b_state |= tmp_bh.b_state; return bh; } err = -EIO; } return ERR_PTR(err);}static inline struct buffer_head *affs_getemptyblk_ino(struct inode *inode, int block){ struct buffer_head *bh, tmp_bh; int err; tmp_bh.b_state = 0; err = affs_get_block(inode, block, &tmp_bh, 1); if (!err) { bh = affs_getemptyblk(inode->i_sb, tmp_bh.b_blocknr); if (bh) { bh->b_state |= tmp_bh.b_state; return bh; } err = -EIO; } return ERR_PTR(err);}static ssize_taffs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos){ ssize_t retval; retval = generic_file_write (file, buf, count, ppos); if (retval >0) { struct inode *inode = file->f_dentry->d_inode; inode->i_ctime = inode->i_mtime = CURRENT_TIME; mark_inode_dirty(inode); } return retval;}static intaffs_do_readpage_ofs(struct file *file, struct page *page, unsigned from, unsigned to){ struct inode *inode = page->mapping->host; struct super_block *sb = inode->i_sb; struct buffer_head *bh; char *data; u32 bidx, boff, bsize; u32 tmp; pr_debug("AFFS: read_page(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to); if (from > to || to > PAGE_CACHE_SIZE) BUG(); data = page_address(page); bsize = AFFS_SB->s_data_blksize; tmp = (page->index << PAGE_CACHE_SHIFT) + from; bidx = tmp / bsize; boff = tmp % bsize; while (from < to) { bh = affs_bread_ino(inode, bidx, 0); if (IS_ERR(bh)) return PTR_ERR(bh); tmp = min(bsize - boff, to - from); if (from + tmp > to || tmp > bsize) BUG(); memcpy(data + from, AFFS_DATA(bh) + boff, tmp); affs_brelse(bh); bidx++; from += tmp; boff = 0; } return 0;}static intaffs_extent_file_ofs(struct inode *inode, u32 newsize){ struct super_block *sb = inode->i_sb; struct buffer_head *bh, *prev_bh; u32 bidx, boff; u32 size, bsize; u32 tmp; pr_debug("AFFS: extent_file(%u, %d)\n", (u32)inode->i_ino, newsize); bsize = AFFS_SB->s_data_blksize; bh = NULL; size = AFFS_INODE->mmu_private; bidx = size / bsize; boff = size % bsize; if (boff) { bh = affs_bread_ino(inode, bidx, 0); if (IS_ERR(bh)) return PTR_ERR(bh); tmp = min(bsize - boff, newsize - size); if (boff + tmp > bsize || tmp > bsize) BUG(); memset(AFFS_DATA(bh) + boff, 0, tmp); AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp); affs_fix_checksum(sb, bh); mark_buffer_dirty_inode(bh, inode); size += tmp; bidx++; } else if (bidx) { bh = affs_bread_ino(inode, bidx - 1, 0); if (IS_ERR(bh)) return PTR_ERR(bh); } while (size < newsize) { prev_bh = bh; bh = affs_getzeroblk_ino(inode, bidx); if (IS_ERR(bh)) goto out; tmp = min(bsize, newsize - size); if (tmp > bsize) BUG(); AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA); AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino); AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx); AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp); affs_fix_checksum(sb, bh); bh->b_state &= ~(1UL << BH_New); mark_buffer_dirty_inode(bh, inode); if (prev_bh) { u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next); if (tmp) affs_warning(sb, "extent_file_ofs", "next block already set for %d (%d)", bidx, tmp); AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr); affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp); mark_buffer_dirty_inode(prev_bh, inode); affs_brelse(prev_bh); } size += bsize; bidx++; } affs_brelse(bh); inode->i_size = AFFS_INODE->mmu_private = newsize; return 0;out: inode->i_size = AFFS_INODE->mmu_private = size; return PTR_ERR(bh);}static intaffs_readpage_ofs(struct file *file, struct page *page){ struct inode *inode = page->mapping->host; u32 to; int err; pr_debug("AFFS: read_page(%u, %ld)\n", (u32)inode->i_ino, page->index); to = PAGE_CACHE_SIZE; if (((page->index + 1) << PAGE_CACHE_SHIFT) > inode->i_size) { to = inode->i_size & ~PAGE_CACHE_MASK; memset(page_address(page) + to, 0, PAGE_CACHE_SIZE - to); } err = affs_do_readpage_ofs(file, page, 0, to); if (!err) SetPageUptodate(page); UnlockPage(page); return err;}static int affs_prepare_write_ofs(struct file *file, struct page *page, unsigned from, unsigned to){ struct inode *inode = page->mapping->host; u32 size, offset; u32 tmp; int err = 0; pr_debug("AFFS: prepare_write(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to); offset = page->index << PAGE_CACHE_SHIFT; if (offset + from > AFFS_INODE->mmu_private) { err = affs_extent_file_ofs(inode, offset + from); if (err) return err; } size = inode->i_size; if (Page_Uptodate(page)) return 0; if (from) { err = affs_do_readpage_ofs(file, page, 0, from); if (err) return err; } if (to < PAGE_CACHE_SIZE) { memset(page_address(page) + to, 0, PAGE_CACHE_SIZE - to); if (size > offset + to) { if (size < offset + PAGE_CACHE_SIZE) tmp = size & ~PAGE_CACHE_MASK; else tmp = PAGE_CACHE_SIZE; err = affs_do_readpage_ofs(file, page, to, tmp); } } return err;}static int affs_commit_write_ofs(struct file *file, struct page *page, unsigned from, unsigned to){ struct inode *inode = page->mapping->host; struct super_block *sb = inode->i_sb; struct buffer_head *bh, *prev_bh; char *data; u32 bidx, boff, bsize; u32 tmp; int written; pr_debug("AFFS: commit_write(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to); bsize = AFFS_SB->s_data_blksize; data = page_address(page); bh = NULL; written = 0; tmp = (page->index << PAGE_CACHE_SHIFT) + from; bidx = tmp / bsize; boff = tmp % bsize; if (boff) { bh = affs_bread_ino(inode, bidx, 0); if (IS_ERR(bh)) return PTR_ERR(bh); tmp = min(bsize - boff, to - from); if (boff + tmp > bsize || tmp > bsize) BUG(); memcpy(AFFS_DATA(bh) + boff, data + from, tmp); AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp); affs_fix_checksum(sb, bh); mark_buffer_dirty_inode(bh, inode); written += tmp; from += tmp; bidx++; } else if (bidx) { bh = affs_bread_ino(inode, bidx - 1, 0); if (IS_ERR(bh)) return PTR_ERR(bh); } while (from + bsize <= to) { prev_bh = bh; bh = affs_getemptyblk_ino(inode, bidx); if (IS_ERR(bh)) goto out; memcpy(AFFS_DATA(bh), data + from, bsize); if (bh->b_state & (1UL << BH_New)) { AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA); AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino); AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx); AFFS_DATA_HEAD(bh)->size = cpu_to_be32(bsize); AFFS_DATA_HEAD(bh)->next = 0; bh->b_state &= ~(1UL << BH_New); if (prev_bh) { u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next); if (tmp) affs_warning(sb, "commit_write_ofs", "next block already set for %d (%d)", bidx, tmp); AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr); affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp); mark_buffer_dirty_inode(prev_bh, inode); } } affs_brelse(prev_bh); affs_fix_checksum(sb, bh); mark_buffer_dirty_inode(bh, inode); written += bsize; from += bsize; bidx++; } if (from < to) { prev_bh = bh; bh = affs_bread_ino(inode, bidx, 1); if (IS_ERR(bh)) goto out; tmp = min(bsize, to - from); if (tmp > bsize) BUG(); memcpy(AFFS_DATA(bh), data + from, tmp); if (bh->b_state & (1UL << BH_New)) { AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA); AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino); AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx); AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp); AFFS_DATA_HEAD(bh)->next = 0; bh->b_state &= ~(1UL << BH_New); if (prev_bh) { u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next); if (tmp) affs_warning(sb, "commit_write_ofs", "next block already set for %d (%d)", bidx, tmp); AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr); affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp); mark_buffer_dirty_inode(prev_bh, inode); } } else if (be32_to_cpu(AFFS_DATA_HEAD(bh)->size) < tmp) AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp); affs_brelse(prev_bh); affs_fix_checksum(sb, bh); mark_buffer_dirty_inode(bh, inode); written += tmp; from += tmp; bidx++; } SetPageUptodate(page);done: affs_brelse(bh); tmp = (page->index << PAGE_CACHE_SHIFT) + from; if (tmp > inode->i_size) inode->i_size = AFFS_INODE->mmu_private = tmp; return written;out: bh = prev_bh; if (!written) written = PTR_ERR(bh); goto done;}struct address_space_operations affs_aops_ofs = { readpage: affs_readpage_ofs, //writepage: affs_writepage_ofs, //sync_page: affs_sync_page_ofs, prepare_write: affs_prepare_write_ofs, commit_write: affs_commit_write_ofs};/* Free any preallocated blocks. */voidaffs_free_prealloc(struct inode *inode){ struct super_block *sb = inode->i_sb; pr_debug("AFFS: free_prealloc(ino=%lu)\n", inode->i_ino); while (inode->u.affs_i.i_pa_cnt) { inode->u.affs_i.i_pa_cnt--; affs_free_block(sb, ++inode->u.affs_i.i_lastalloc); }}/* Truncate (or enlarge) a file to the requested size. */voidaffs_truncate(struct inode *inode){ struct super_block *sb = inode->i_sb; u32 ext, ext_key; u32 last_blk, blkcnt, blk; u32 size; struct buffer_head *ext_bh; int i; pr_debug("AFFS: truncate(inode=%d, oldsize=%u, newsize=%u)\n", (u32)inode->i_ino, (u32)AFFS_INODE->mmu_private, (u32)inode->i_size); last_blk = 0; ext = 0; if (inode->i_size) { last_blk = ((u32)inode->i_size - 1) / AFFS_SB->s_data_blksize; ext = last_blk / AFFS_SB->s_hashsize; } if (inode->i_size > AFFS_INODE->mmu_private) { struct address_space *mapping = inode->i_mapping; struct page *page; u32 size = inode->i_size - 1; int res; page = grab_cache_page(mapping, size >> PAGE_CACHE_SHIFT); if (!page) return; size = (size & (PAGE_CACHE_SIZE - 1)) + 1; res = mapping->a_ops->prepare_write(NULL, page, size, size); if (!res) res = mapping->a_ops->commit_write(NULL, page, size, size); UnlockPage(page); page_cache_release(page); mark_inode_dirty(inode); return; } else if (inode->i_size == AFFS_INODE->mmu_private) return; // lock cache ext_bh = affs_get_extblock(inode, ext); if (IS_ERR(ext_bh)) { affs_warning(sb, "truncate", "unexpected read error for ext block %u (%d)", ext, PTR_ERR(ext_bh)); return; } if (AFFS_INODE->i_lc) { /* clear linear cache */ i = (ext + 1) >> AFFS_INODE->i_lc_shift; if (AFFS_INODE->i_lc_size > i) { AFFS_INODE->i_lc_size = i; for (; i < AFFS_LC_SIZE; i++) AFFS_INODE->i_lc[i] = 0; } /* clear associative cache */ for (i = 0; i < AFFS_AC_SIZE; i++) if (AFFS_INODE->i_ac[i].ext >= ext) AFFS_INODE->i_ac[i].ext = 0; } ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension); blkcnt = AFFS_INODE->i_blkcnt; i = 0; blk = last_blk; if (inode->i_size) { i = last_blk % AFFS_SB->s_hashsize + 1; blk++; } else AFFS_HEAD(ext_bh)->first_data = 0; size = AFFS_SB->s_hashsize; if (size > blkcnt - blk + i) size = blkcnt - blk + i; for (; i < size; i++, blk++) { affs_free_block(sb, be32_to_cpu(AFFS_BLOCK(sb, ext_bh, i))); AFFS_BLOCK(sb, ext_bh, i) = 0; } AFFS_TAIL(sb, ext_bh)->extension = 0; affs_fix_checksum(sb, ext_bh); mark_buffer_dirty_inode(ext_bh, inode); affs_brelse(ext_bh); if (inode->i_size) { AFFS_INODE->i_blkcnt = last_blk + 1; AFFS_INODE->i_extcnt = ext + 1; if (AFFS_SB->s_flags & SF_OFS) { struct buffer_head *bh = affs_bread_ino(inode, last_blk, 0); u32 tmp; if (IS_ERR(bh)) { affs_warning(sb, "truncate", "unexpected read error for last block %u (%d)", last_blk, PTR_ERR(bh)); return; } tmp = be32_to_cpu(AFFS_DATA_HEAD(bh)->next); AFFS_DATA_HEAD(bh)->next = 0; affs_adjust_checksum(bh, -tmp); affs_brelse(bh); } } else { AFFS_INODE->i_blkcnt = 0; AFFS_INODE->i_extcnt = 1; } AFFS_INODE->mmu_private = inode->i_size; // unlock cache while (ext_key) { ext_bh = affs_bread(sb, ext_key); size = AFFS_SB->s_hashsize; if (size > blkcnt - blk) size = blkcnt - blk; for (i = 0; i < size; i++, blk++) affs_free_block(sb, be32_to_cpu(AFFS_BLOCK(sb, ext_bh, i))); affs_free_block(sb, ext_key); ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension); affs_brelse(ext_bh); } affs_free_prealloc(inode);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -