cregit-Linux how code gets into the kernel

Release 4.11 fs/affs/file.c

Directory: fs/affs
/*
 *  linux/fs/affs/file.c
 *
 *  (c) 1996  Hans-Joachim Widmaier - Rewritten
 *
 *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
 *
 *  (C) 1992  Eric Youngdale Modified for ISO 9660 filesystem.
 *
 *  (C) 1991  Linus Torvalds - minix filesystem
 *
 *  affs regular file handling primitives
 */

#include <linux/uio.h>
#include "affs.h"

static struct buffer_head *affs_get_extblock_slow(struct inode *inode, u32 ext);


static int affs_file_open(struct inode *inode, struct file *filp) { pr_debug("open(%lu,%d)\n", inode->i_ino, atomic_read(&AFFS_I(inode)->i_opencnt)); atomic_inc(&AFFS_I(inode)->i_opencnt); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds2856.00%233.33%
Roman Zippel1224.00%116.67%
Linus Torvalds (pre-git)918.00%233.33%
Fabian Frederick12.00%116.67%
Total50100.00%6100.00%


static int affs_file_release(struct inode *inode, struct file *filp) { pr_debug("release(%lu, %d)\n", inode->i_ino, atomic_read(&AFFS_I(inode)->i_opencnt)); if (atomic_dec_and_test(&AFFS_I(inode)->i_opencnt)) { inode_lock(inode); if (inode->i_size != AFFS_I(inode)->mmu_private) affs_truncate(inode); affs_free_prealloc(inode); inode_unlock(inode); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds4349.43%225.00%
Roman Zippel3439.08%112.50%
Linus Torvalds (pre-git)78.05%337.50%
Al Viro22.30%112.50%
Fabian Frederick11.15%112.50%
Total87100.00%8100.00%


static int affs_grow_extcache(struct inode *inode, u32 lc_idx) { struct super_block *sb = inode->i_sb; struct buffer_head *bh; u32 lc_max; int i, j, key; if (!AFFS_I(inode)->i_lc) { char *ptr = (char *)get_zeroed_page(GFP_NOFS); if (!ptr) return -ENOMEM; AFFS_I(inode)->i_lc = (u32 *)ptr; AFFS_I(inode)->i_ac = (struct affs_ext_key *)(ptr + AFFS_CACHE_SIZE / 2); } lc_max = AFFS_LC_SIZE << AFFS_I(inode)->i_lc_shift; if (AFFS_I(inode)->i_extcnt > lc_max) { u32 lc_shift, lc_mask, tmp, off; /* need to recalculate linear cache, start from old size */ lc_shift = AFFS_I(inode)->i_lc_shift; tmp = (AFFS_I(inode)->i_extcnt / AFFS_LC_SIZE) >> lc_shift; for (; tmp; tmp >>= 1) lc_shift++; lc_mask = (1 << lc_shift) - 1; /* fix idx and old size to new shift */ lc_idx >>= (lc_shift - AFFS_I(inode)->i_lc_shift); AFFS_I(inode)->i_lc_size >>= (lc_shift - AFFS_I(inode)->i_lc_shift); /* first shrink old cache to make more space */ off = 1 << (lc_shift - AFFS_I(inode)->i_lc_shift); for (i = 1, j = off; j < AFFS_LC_SIZE; i++, j += off) AFFS_I(inode)->i_ac[i] = AFFS_I(inode)->i_ac[j]; AFFS_I(inode)->i_lc_shift = lc_shift; AFFS_I(inode)->i_lc_mask = lc_mask; } /* fill cache to the needed index */ i = AFFS_I(inode)->i_lc_size; AFFS_I(inode)->i_lc_size = lc_idx + 1; for (; i <= lc_idx; i++) { if (!i) { AFFS_I(inode)->i_lc[0] = inode->i_ino; continue; } key = AFFS_I(inode)->i_lc[i - 1]; j = AFFS_I(inode)->i_lc_mask + 1; // unlock cache for (; j > 0; j--) { bh = affs_bread(sb, key); if (!bh) goto err; key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension); affs_brelse(bh); } // lock cache AFFS_I(inode)->i_lc[i] = key; } return 0; err: // lock cache return -EIO; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds36481.98%350.00%
Linus Torvalds (pre-git)8018.02%350.00%
Total444100.00%6100.00%


static struct buffer_head * affs_alloc_extblock(struct inode *inode, struct buffer_head *bh, u32 ext) { struct super_block *sb = inode->i_sb; struct buffer_head *new_bh; u32 blocknr, tmp; blocknr = affs_alloc_block(inode, bh->b_blocknr); if (!blocknr) return ERR_PTR(-ENOSPC); new_bh = affs_getzeroblk(sb, blocknr); if (!new_bh) { affs_free_block(sb, blocknr); return ERR_PTR(-EIO); } AFFS_HEAD(new_bh)->ptype = cpu_to_be32(T_LIST); AFFS_HEAD(new_bh)->key = cpu_to_be32(blocknr); AFFS_TAIL(sb, new_bh)->stype = cpu_to_be32(ST_FILE); AFFS_TAIL(sb, new_bh)->parent = cpu_to_be32(inode->i_ino); affs_fix_checksum(sb, new_bh); mark_buffer_dirty_inode(new_bh, inode); tmp = be32_to_cpu(AFFS_TAIL(sb, bh)->extension); if (tmp) affs_warning(sb, "alloc_ext", "previous extension set (%x)", tmp); AFFS_TAIL(sb, bh)->extension = cpu_to_be32(blocknr); affs_adjust_checksum(bh, blocknr - tmp); mark_buffer_dirty_inode(bh, inode); AFFS_I(inode)->i_extcnt++; mark_inode_dirty(inode); return new_bh; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds14561.44%337.50%
Linus Torvalds (pre-git)9138.56%562.50%
Total236100.00%8100.00%


static inline struct buffer_head * affs_get_extblock(struct inode *inode, u32 ext) { /* inline the simplest case: same extended block as last time */ struct buffer_head *bh = AFFS_I(inode)->i_ext_bh; if (ext == AFFS_I(inode)->i_ext_last) get_bh(bh); else /* we have to do more (not inlined) */ bh = affs_get_extblock_slow(inode, ext); return bh; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds4778.33%240.00%
Linus Torvalds (pre-git)1220.00%240.00%
Roman Zippel11.67%120.00%
Total60100.00%5100.00%


static struct buffer_head * affs_get_extblock_slow(struct inode *inode, u32 ext) { struct super_block *sb = inode->i_sb; struct buffer_head *bh; u32 ext_key; u32 lc_idx, lc_off, ac_idx; u32 tmp, idx; if (ext == AFFS_I(inode)->i_ext_last + 1) { /* read the next extended block from the current one */ bh = AFFS_I(inode)->i_ext_bh; ext_key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension); if (ext < AFFS_I(inode)->i_extcnt) goto read_ext; BUG_ON(ext > AFFS_I(inode)->i_extcnt); bh = affs_alloc_extblock(inode, bh, ext); if (IS_ERR(bh)) return bh; goto store_ext; } if (ext == 0) { /* we seek back to the file header block */ ext_key = inode->i_ino; goto read_ext; } if (ext >= AFFS_I(inode)->i_extcnt) { struct buffer_head *prev_bh; /* allocate a new extended block */ BUG_ON(ext > AFFS_I(inode)->i_extcnt); /* get previous extended block */ prev_bh = affs_get_extblock(inode, ext - 1); if (IS_ERR(prev_bh)) return prev_bh; bh = affs_alloc_extblock(inode, prev_bh, ext); affs_brelse(prev_bh); if (IS_ERR(bh)) return bh; goto store_ext; } again: /* check if there is an extended cache and whether it's large enough */ lc_idx = ext >> AFFS_I(inode)->i_lc_shift; lc_off = ext & AFFS_I(inode)->i_lc_mask; if (lc_idx >= AFFS_I(inode)->i_lc_size) { int err; err = affs_grow_extcache(inode, lc_idx); if (err) return ERR_PTR(err); goto again; } /* every n'th key we find in the linear cache */ if (!lc_off) { ext_key = AFFS_I(inode)->i_lc[lc_idx]; goto read_ext; } /* maybe it's still in the associative cache */ ac_idx = (ext - lc_idx - 1) & AFFS_AC_MASK; if (AFFS_I(inode)->i_ac[ac_idx].ext == ext) { ext_key = AFFS_I(inode)->i_ac[ac_idx].key; goto read_ext; } /* try to find one of the previous extended blocks */ tmp = ext; idx = ac_idx; while (--tmp, --lc_off > 0) { idx = (idx - 1) & AFFS_AC_MASK; if (AFFS_I(inode)->i_ac[idx].ext == tmp) { ext_key = AFFS_I(inode)->i_ac[idx].key; goto find_ext; } } /* fall back to the linear cache */ ext_key = AFFS_I(inode)->i_lc[lc_idx]; find_ext: /* read all extended blocks until we find the one we need */ //unlock cache do { bh = affs_bread(sb, ext_key); if (!bh) goto err_bread; ext_key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension); affs_brelse(bh); tmp++; } while (tmp < ext); //lock cache /* store it in the associative cache */ // recalculate ac_idx? AFFS_I(inode)->i_ac[ac_idx].ext = ext; AFFS_I(inode)->i_ac[ac_idx].key = ext_key; read_ext: /* finally read the right extended block */ //unlock cache bh = affs_bread(sb, ext_key); if (!bh) goto err_bread; //lock cache store_ext: /* release old cached extended block and store the new one */ affs_brelse(AFFS_I(inode)->i_ext_bh); AFFS_I(inode)->i_ext_last = ext; AFFS_I(inode)->i_ext_bh = bh; get_bh(bh); return bh; err_bread: affs_brelse(bh); return ERR_PTR(-EIO); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds48479.87%222.22%
Linus Torvalds (pre-git)11518.98%555.56%
Fabian Frederick60.99%111.11%
Roman Zippel10.17%111.11%
Total606100.00%9100.00%


static int affs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_result, int create) { struct super_block *sb = inode->i_sb; struct buffer_head *ext_bh; u32 ext; pr_debug("%s(%lu, %llu)\n", __func__, inode->i_ino, (unsigned long long)block); BUG_ON(block > (sector_t)0x7fffffffUL); if (block >= AFFS_I(inode)->i_blkcnt) { if (block > AFFS_I(inode)->i_blkcnt || !create) goto err_big; } else create = 0; //lock cache affs_lock_ext(inode); ext = (u32)block / AFFS_SB(sb)->s_hashsize; block -= ext * AFFS_SB(sb)->s_hashsize; ext_bh = affs_get_extblock(inode, ext); if (IS_ERR(ext_bh)) goto err_ext; map_bh(bh_result, sb, (sector_t)be32_to_cpu(AFFS_BLOCK(sb, ext_bh, block))); if (create) { u32 blocknr = affs_alloc_block(inode, ext_bh->b_blocknr); if (!blocknr) goto err_alloc; set_buffer_new(bh_result); AFFS_I(inode)->mmu_private += AFFS_SB(sb)->s_data_blksize; AFFS_I(inode)->i_blkcnt++; /* store new block */ if (bh_result->b_blocknr) affs_warning(sb, "get_block", "block already set (%llx)", (unsigned long long)bh_result->b_blocknr); AFFS_BLOCK(sb, ext_bh, block) = cpu_to_be32(blocknr); AFFS_HEAD(ext_bh)->block_count = cpu_to_be32(block + 1); affs_adjust_checksum(ext_bh, blocknr - bh_result->b_blocknr + 1); bh_result->b_blocknr = blocknr; if (!block) { /* insert first block into header block */ u32 tmp = be32_to_cpu(AFFS_HEAD(ext_bh)->first_data); if (tmp) affs_warning(sb, "get_block", "first block already set (%d)", tmp); AFFS_HEAD(ext_bh)->first_data = cpu_to_be32(blocknr); affs_adjust_checksum(ext_bh, blocknr - tmp); } } affs_brelse(ext_bh); //unlock cache affs_unlock_ext(inode); return 0; err_big: affs_error(inode->i_sb, "get_block", "strange block request %llu", (unsigned long long)block); return -EIO; err_ext: // unlock cache affs_unlock_ext(inode); return PTR_ERR(ext_bh); err_alloc: brelse(ext_bh); clear_buffer_mapped(bh_result); bh_result->b_bdev = NULL; // unlock cache affs_unlock_ext(inode); return -ENOSPC; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds36784.17%640.00%
Andrew Morton225.05%213.33%
Linus Torvalds (pre-git)194.36%213.33%
Brian Gerst92.06%16.67%
Geert Uytterhoeven81.83%16.67%
Fabian Frederick81.83%213.33%
Julia Lawall30.69%16.67%
Total436100.00%15100.00%


static int affs_writepage(struct page *page, struct writeback_control *wbc) { return block_write_full_page(page, affs_get_block, wbc); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds1973.08%150.00%
Andrew Morton726.92%150.00%
Total26100.00%2100.00%


static int affs_readpage(struct file *file, struct page *page) { return block_read_full_page(page, affs_get_block); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds24100.00%1100.00%
Total24100.00%1100.00%


static void affs_write_failed(struct address_space *mapping, loff_t to) { struct inode *inode = mapping->host; if (to > inode->i_size) { truncate_pagecache(inode, inode->i_size); affs_truncate(inode); } }

Contributors

PersonTokensPropCommitsCommitProp
Marco Stornelli47100.00%1100.00%
Total47100.00%1100.00%


static ssize_t affs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; struct inode *inode = mapping->host; size_t count = iov_iter_count(iter); loff_t offset = iocb->ki_pos; ssize_t ret; if (iov_iter_rw(iter) == WRITE) { loff_t size = offset + count; if (AFFS_I(inode)->mmu_private < size) return 0; } ret = blockdev_direct_IO(iocb, inode, iter, affs_get_block); if (ret < 0 && iov_iter_rw(iter) == WRITE) affs_write_failed(mapping, offset + count); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Fabian Frederick11587.79%250.00%
Omar Sandoval96.87%125.00%
Christoph Hellwig75.34%125.00%
Total131100.00%4100.00%


static int affs_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata) { int ret; *pagep = NULL; ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, affs_get_block, &AFFS_I(mapping->host)->mmu_private); if (unlikely(ret)) affs_write_failed(mapping, pos + len); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Piggin3638.30%120.00%
Linus Torvalds3436.17%240.00%
Christoph Hellwig2122.34%120.00%
Marco Stornelli33.19%120.00%
Total94100.00%5100.00%


static sector_t _affs_bmap(struct address_space *mapping, sector_t block) { return generic_block_bmap(mapping,block,affs_get_block); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds2291.67%150.00%
Andrew Morton28.33%150.00%
Total24100.00%2100.00%

const struct address_space_operations affs_aops = { .readpage = affs_readpage, .writepage = affs_writepage, .write_begin = affs_write_begin, .write_end = generic_write_end, .direct_IO = affs_direct_IO, .bmap = _affs_bmap };
static inline struct buffer_head * affs_bread_ino(struct inode *inode, int block, int create) { struct buffer_head *bh, tmp_bh; int err; tmp_bh.b_state = 0; err = affs_get_block(inode, block, &tmp_bh, create); if (!err) { bh = affs_bread(inode->i_sb, tmp_bh.b_blocknr); if (bh) { bh->b_state |= tmp_bh.b_state; return bh; } err = -EIO; } return ERR_PTR(err); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds98100.00%1100.00%
Total98100.00%1100.00%


static inline struct buffer_head * affs_getzeroblk_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_getzeroblk(inode->i_sb, tmp_bh.b_blocknr); if (bh) { bh->b_state |= tmp_bh.b_state; return bh; } err = -EIO; } return ERR_PTR(err); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds95100.00%1100.00%
Total95100.00%1100.00%


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); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds95100.00%1100.00%
Total95100.00%1100.00%


static int affs_do_readpage_ofs(struct page *page, unsigned to) { struct inode *inode = page->mapping->host; struct super_block *sb = inode->i_sb; struct buffer_head *bh; char *data; unsigned pos = 0; u32 bidx, boff, bsize; u32 tmp; pr_debug("%s(%lu, %ld, 0, %d)\n", __func__, inode->i_ino, page->index, to); BUG_ON(to > PAGE_SIZE); bsize = AFFS_SB(sb)->s_data_blksize; tmp = page->index << PAGE_SHIFT; bidx = tmp / bsize; boff = tmp % bsize; while (pos < to) { bh = affs_bread_ino(inode, bidx, 0); if (IS_ERR(bh)) return PTR_ERR(bh); tmp = min(bsize - boff, to - pos); BUG_ON(pos + tmp > to || tmp > bsize); data = kmap_atomic(page); memcpy(data + pos, AFFS_DATA(bh) + boff, tmp); kunmap_atomic(data); affs_brelse(bh); bidx++; pos += tmp; boff = 0; } flush_dcache_page(page); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds16474.21%218.18%
Roman Zippel167.24%19.09%
Fabian Frederick125.43%218.18%
Al Viro125.43%19.09%
Julia Lawall62.71%19.09%
Andrew Morton52.26%19.09%
Brian Gerst31.36%19.09%
Kirill A. Shutemov20.90%19.09%
Geert Uytterhoeven10.45%19.09%
Total221100.00%11100.00%


static int affs_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("%s(%lu, %d)\n", __func__, 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); BUG_ON(boff + tmp > bsize || tmp > bsize); memset(AFFS_DATA(bh) + boff, 0, tmp); be32_add_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); BUG_ON(tmp > bsize); 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_next = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next); if (tmp_next) affs_warning(sb, "extent_file_ofs", "next block already set for %d (%d)", bidx, tmp_next); AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr); affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp_next); 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); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds41888.19%436.36%
Roman Zippel377.81%19.09%
Julia Lawall61.27%19.09%
Fabian Frederick61.27%218.18%
Brian Gerst30.63%19.09%
Marcin Ślusarz30.63%19.09%
Geert Uytterhoeven10.21%19.09%
Total474100.00%11100.00%


static int affs_readpage_ofs(struct file *file, struct page *page) { struct inode *inode = page->mapping->host; u32 to; int err; pr_debug("%s(%lu, %ld)\n", __func__, inode->i_ino, page->index); to = PAGE_SIZE; if (((page->index + 1) << PAGE_SHIFT) > inode->i_size) { to = inode->i_size & ~PAGE_MASK; memset(page_address(page) + to, 0, PAGE_SIZE - to); } err = affs_do_readpage_ofs(page, to); if (!err) SetPageUptodate(page); unlock_page(page); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds6048.39%19.09%
Linus Torvalds (pre-git)5342.74%545.45%
Kirill A. Shutemov43.23%19.09%
Roman Zippel32.42%19.09%
Fabian Frederick21.61%19.09%
Geert Uytterhoeven10.81%19.09%
Andrew Morton10.81%19.09%
Total124100.00%11100.00%


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("%s(%lu, %llu, %llu)\n", __func__, inode->i_ino, pos, 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_SHIFT; page = grab_cache_page_write_begin(mapping, index, flags); 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(page, PAGE_SIZE); if (err) { unlock_page(page); put_page(page); } return err; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Piggin6235.43%215.38%
Linus Torvalds5430.86%17.69%
Linus Torvalds (pre-git)3017.14%538.46%
Roman Zippel2112.00%17.69%
Kirill A. Shutemov31.71%17.69%
Andrew Morton21.14%17.69%
Fabian Frederick21.14%17.69%
Geert Uytterhoeven10.57%17.69%
Total175100.00%13100.00%


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_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("%s(%lu, %llu, %llu)\n", __func__, inode->i_ino, pos, pos + len); bsize = AFFS_SB(sb)->s_data_blksize; data = page_address(page); bh = NULL; written = 0; tmp = (page->index << PAGE_SHIFT) + from; bidx = tmp / bsize; boff = tmp % bsize; if (boff) { bh = affs_bread_ino(inode, bidx, 0); if (IS_ERR(bh)) { written = PTR_ERR(bh); goto err_first_bh; } tmp = min(bsize - boff, to - from); BUG_ON(boff + tmp > bsize || tmp > bsize); memcpy(AFFS_DATA(bh) + boff, data + from, tmp); be32_add_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)) { written = PTR_ERR(bh); goto err_first_bh; } } while (from + bsize <= to) { prev_bh = bh; bh = affs_getemptyblk_ino(inode, bidx); if (IS_ERR(bh)) goto err_bh; 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_next = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next); if (tmp_next) affs_warning(sb, "commit_write_ofs", "next block already set for %d (%d)", bidx, tmp_next); AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr); affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp_next); 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 err_bh; tmp = min(bsize, to - from); BUG_ON(tmp > bsize); 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_next = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next); if (tmp_next) affs_warning(sb, "commit_write_ofs", "next block already set for %d (%d)", bidx, tmp_next); AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr); affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp_next); 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_SHIFT) + from; if (tmp > inode->i_size) inode->i_size = AFFS_I(inode)->mmu_private = tmp; err_first_bh: unlock_page(page); put_page(page); return written; err_bh: bh = prev_bh; if (!written) written = PTR_ERR(bh); goto done; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds47052.63%417.39%
Linus Torvalds (pre-git)27230.46%834.78%
Nicholas Piggin515.71%14.35%
Roman Zippel465.15%14.35%
Taesoo Kim212.35%14.35%
Fabian Frederick101.12%28.70%
Andrew Morton60.67%14.35%
Julia Lawall60.67%14.35%
Kirill A. Shutemov40.45%14.35%
Brian Gerst30.34%14.35%
Marcin Ślusarz30.34%14.35%
Geert Uytterhoeven10.11%14.35%
Total893100.00%23100.00%

const struct address_space_operations affs_aops_ofs = { .readpage = affs_readpage_ofs, //.writepage = affs_writepage_ofs, .write_begin = affs_write_begin_ofs, .write_end = affs_write_end_ofs }; /* Free any preallocated blocks. */
void affs_free_prealloc(struct inode *inode) { struct super_block *sb = inode->i_sb; pr_debug("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); } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)4778.33%562.50%
Linus Torvalds1220.00%225.00%
Fabian Frederick11.67%112.50%
Total60100.00%8100.00%

/* Truncate (or enlarge) a file to the requested size. */
void affs_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("truncate(inode=%lu, oldsize=%llu, newsize=%llu)\n", inode->i_ino, AFFS_I(inode)->mmu_private, 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; loff_t isize = inode->i_size; int res; res = mapping->a_ops->write_begin(NULL, mapping, isize, 0, 0, &page, &fsdata); if (!res) res = mapping->a_ops->write_end(NULL, mapping, isize, 0, 0, page, fsdata); else inode->i_size = AFFS_I(inode)->mmu_private; 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 (%ld)", 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; AFFS_HEAD(ext_bh)->block_count = cpu_to_be32(i); 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_test_opt(AFFS_SB(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 (%ld)", ext, 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_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); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds39948.42%312.50%
Linus Torvalds (pre-git)20224.51%1041.67%
Roman Zippel17120.75%28.33%
Nicholas Piggin232.79%14.17%
Brian Gerst151.82%14.17%
Fabian Frederick91.09%312.50%
Dan Carpenter30.36%28.33%
Geert Uytterhoeven10.12%14.17%
Al Viro10.12%14.17%
Total824100.00%24100.00%


int affs_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync) { struct inode *inode = filp->f_mapping->host; int ret, err; err = filemap_write_and_wait_range(inode->i_mapping, start, end); if (err) return err; inode_lock(inode); ret = write_inode_now(inode, 0); err = sync_blockdev(inode->i_sb->s_bdev); if (!ret) ret = err; inode_unlock(inode); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro5960.82%250.00%
Josef Bacik3435.05%125.00%
Christoph Hellwig44.12%125.00%
Total97100.00%4100.00%

const struct file_operations affs_file_operations = { .llseek = generic_file_llseek, .read_iter = generic_file_read_iter, .write_iter = generic_file_write_iter, .mmap = generic_file_mmap, .open = affs_file_open, .release = affs_file_release, .fsync = affs_file_fsync, .splice_read = generic_file_splice_read, }; const struct inode_operations affs_file_inode_operations = { .setattr = affs_notify_change, };

Overall Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds347562.46%812.31%
Linus Torvalds (pre-git)95217.11%1624.62%
Roman Zippel3426.15%23.08%
Fabian Frederick2394.30%913.85%
Nicholas Piggin1803.24%23.08%
Al Viro751.35%57.69%
Marco Stornelli500.90%11.54%
Andrew Morton460.83%69.23%
Christoph Hellwig350.63%57.69%
Josef Bacik340.61%11.54%
Brian Gerst330.59%11.54%
Julia Lawall210.38%11.54%
Taesoo Kim210.38%11.54%
Art Haas160.29%11.54%
Geert Uytterhoeven140.25%11.54%
Kirill A. Shutemov130.23%11.54%
Omar Sandoval90.16%11.54%
Marcin Ślusarz60.11%11.54%
Dan Carpenter30.05%23.08%
Total5564100.00%65100.00%
Directory: fs/affs
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.