📄 file.c
字号:
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 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(); kmap(page); data = page_address(page); bsize = AFFS_SB(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; } flush_dcache_page(page); kunmap(page); 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(sb)->s_data_blksize; bh = NULL; size = AFFS_I(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_I(inode)->mmu_private = newsize; return 0;out: inode->i_size = AFFS_I(inode)->mmu_private = newsize; 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); unlock_page(page); return err;}static int affs_write_begin_ofs(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata){ struct inode *inode = mapping->host; struct page *page; pgoff_t index; int err = 0; pr_debug("AFFS: write_begin(%u, %llu, %llu)\n", (u32)inode->i_ino, (unsigned long long)pos, (unsigned long long)pos + len); if (pos > AFFS_I(inode)->mmu_private) { /* XXX: this probably leaves a too-big i_size in case of * failure. Should really be updating i_size at write_end time */ err = affs_extent_file_ofs(inode, pos); if (err) return err; } index = pos >> PAGE_CACHE_SHIFT; page = __grab_cache_page(mapping, index); if (!page) return -ENOMEM; *pagep = page; if (PageUptodate(page)) return 0; /* XXX: inefficient but safe in the face of short writes */ err = affs_do_readpage_ofs(file, page, 0, PAGE_CACHE_SIZE); if (err) { unlock_page(page); page_cache_release(page); } return err;}static int affs_write_end_ofs(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned copied, struct page *page, void *fsdata){ struct inode *inode = mapping->host; struct super_block *sb = inode->i_sb; struct buffer_head *bh, *prev_bh; char *data; u32 bidx, boff, bsize; unsigned from, to; u32 tmp; int written; from = pos & (PAGE_CACHE_SIZE - 1); to = pos + len; /* * XXX: not sure if this can handle short copies (len < copied), but * we don't have to, because the page should always be uptodate here, * due to write_begin. */ pr_debug("AFFS: write_begin(%u, %llu, %llu)\n", (u32)inode->i_ino, (unsigned long long)pos, (unsigned long long)pos + len); bsize = AFFS_SB(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 (buffer_new(bh)) { 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 (buffer_new(bh)) { 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_I(inode)->mmu_private = tmp; unlock_page(page); page_cache_release(page); return written;out: bh = prev_bh; if (!written) written = PTR_ERR(bh); goto done;}const struct address_space_operations affs_aops_ofs = { .readpage = affs_readpage_ofs, //.writepage = affs_writepage_ofs, //.sync_page = affs_sync_page_ofs, .write_begin = affs_write_begin_ofs, .write_end = affs_write_end_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 (AFFS_I(inode)->i_pa_cnt) { AFFS_I(inode)->i_pa_cnt--; affs_free_block(sb, ++AFFS_I(inode)->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_I(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(sb)->s_data_blksize; ext = last_blk / AFFS_SB(sb)->s_hashsize; } if (inode->i_size > AFFS_I(inode)->mmu_private) { struct address_space *mapping = inode->i_mapping; struct page *page; void *fsdata; u32 size = inode->i_size; int res; res = mapping->a_ops->write_begin(NULL, mapping, size, 0, 0, &page, &fsdata); if (!res) res = mapping->a_ops->write_end(NULL, mapping, size, 0, 0, page, fsdata); mark_inode_dirty(inode); return; } else if (inode->i_size == AFFS_I(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_I(inode)->i_lc) { /* clear linear cache */ i = (ext + 1) >> AFFS_I(inode)->i_lc_shift; if (AFFS_I(inode)->i_lc_size > i) { AFFS_I(inode)->i_lc_size = i; for (; i < AFFS_LC_SIZE; i++) AFFS_I(inode)->i_lc[i] = 0; } /* clear associative cache */ for (i = 0; i < AFFS_AC_SIZE; i++) if (AFFS_I(inode)->i_ac[i].ext >= ext) AFFS_I(inode)->i_ac[i].ext = 0; } ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension); blkcnt = AFFS_I(inode)->i_blkcnt; i = 0; blk = last_blk; if (inode->i_size) { i = last_blk % AFFS_SB(sb)->s_hashsize + 1; blk++; } else AFFS_HEAD(ext_bh)->first_data = 0; size = AFFS_SB(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_I(inode)->i_blkcnt = last_blk + 1; AFFS_I(inode)->i_extcnt = ext + 1; if (AFFS_SB(sb)->s_flags & SF_OFS) { struct buffer_head *bh = affs_bread_ino(inode, last_blk, 0); u32 tmp; if (IS_ERR(ext_bh)) { affs_warning(sb, "truncate", "unexpected read error for last block %u (%d)", ext, PTR_ERR(ext_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_I(inode)->i_blkcnt = 0; AFFS_I(inode)->i_extcnt = 1; } AFFS_I(inode)->mmu_private = inode->i_size; // unlock cache while (ext_key) { ext_bh = affs_bread(sb, ext_key); size = AFFS_SB(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 + -