aboutsummaryrefslogtreecommitdiff
path: root/fs/affs/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/affs/file.c')
-rw-r--r--fs/affs/file.c149
1 files changed, 92 insertions, 57 deletions
diff --git a/fs/affs/file.c b/fs/affs/file.c
index 6e0c9399200..a7fe57d2cd9 100644
--- a/fs/affs/file.c
+++ b/fs/affs/file.c
@@ -27,41 +27,43 @@ static int affs_file_release(struct inode *inode, struct file *filp);
const struct file_operations affs_file_operations = {
.llseek = generic_file_llseek,
- .read = do_sync_read,
- .aio_read = generic_file_aio_read,
- .write = do_sync_write,
- .aio_write = generic_file_aio_write,
+ .read = new_sync_read,
+ .read_iter = generic_file_read_iter,
+ .write = new_sync_write,
+ .write_iter = generic_file_write_iter,
.mmap = generic_file_mmap,
.open = affs_file_open,
.release = affs_file_release,
- .fsync = file_fsync,
+ .fsync = affs_file_fsync,
.splice_read = generic_file_splice_read,
};
const struct inode_operations affs_file_inode_operations = {
- .truncate = affs_truncate,
.setattr = affs_notify_change,
};
static int
affs_file_open(struct inode *inode, struct file *filp)
{
- if (atomic_read(&filp->f_count) != 1)
- return 0;
- pr_debug("AFFS: open(%d)\n", AFFS_I(inode)->i_opencnt);
- AFFS_I(inode)->i_opencnt++;
+ 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;
}
static int
affs_file_release(struct inode *inode, struct file *filp)
{
- if (atomic_read(&filp->f_count) != 0)
- return 0;
- pr_debug("AFFS: release(%d)\n", AFFS_I(inode)->i_opencnt);
- AFFS_I(inode)->i_opencnt--;
- if (!AFFS_I(inode)->i_opencnt)
+ 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)) {
+ mutex_lock(&inode->i_mutex);
+ if (inode->i_size != AFFS_I(inode)->mmu_private)
+ affs_truncate(inode);
affs_free_prealloc(inode);
+ mutex_unlock(&inode->i_mutex);
+ }
return 0;
}
@@ -180,7 +182,7 @@ 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)
- atomic_inc(&bh->b_count);
+ get_bh(bh);
else
/* we have to do more (not inlined) */
bh = affs_get_extblock_slow(inode, ext);
@@ -306,7 +308,7 @@ store_ext:
affs_brelse(AFFS_I(inode)->i_ext_bh);
AFFS_I(inode)->i_ext_last = ext;
AFFS_I(inode)->i_ext_bh = bh;
- atomic_inc(&bh->b_count);
+ get_bh(bh);
return bh;
@@ -322,11 +324,10 @@ affs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_resul
struct buffer_head *ext_bh;
u32 ext;
- pr_debug("AFFS: get_block(%u, %lu)\n", (u32)inode->i_ino, (unsigned long)block);
-
+ pr_debug("%s(%u, %lu)\n",
+ __func__, (u32)inode->i_ino, (unsigned long)block);
- if (block > (sector_t)0x7fffffffUL)
- BUG();
+ BUG_ON(block > (sector_t)0x7fffffffUL);
if (block >= AFFS_I(inode)->i_blkcnt) {
if (block > AFFS_I(inode)->i_blkcnt || !create)
@@ -401,14 +402,30 @@ static int affs_readpage(struct file *file, struct page *page)
return block_read_full_page(page, affs_get_block);
}
+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);
+ }
+}
+
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;
- return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
+ 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;
}
static sector_t _affs_bmap(struct address_space *mapping, sector_t block)
@@ -419,7 +436,6 @@ static sector_t _affs_bmap(struct address_space *mapping, sector_t block)
const struct address_space_operations affs_aops = {
.readpage = affs_readpage,
.writepage = affs_writepage,
- .sync_page = block_sync_page,
.write_begin = affs_write_begin,
.write_end = generic_write_end,
.bmap = _affs_bmap
@@ -483,36 +499,36 @@ affs_getemptyblk_ino(struct inode *inode, int block)
}
static int
-affs_do_readpage_ofs(struct file *file, struct page *page, unsigned from, unsigned to)
+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("AFFS: read_page(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to);
- if (from > to || to > PAGE_CACHE_SIZE)
- BUG();
+ pr_debug("%s(%u, %ld, 0, %d)\n", __func__, (u32)inode->i_ino,
+ page->index, to);
+ BUG_ON(to > PAGE_CACHE_SIZE);
kmap(page);
data = page_address(page);
bsize = AFFS_SB(sb)->s_data_blksize;
- tmp = (page->index << PAGE_CACHE_SHIFT) + from;
+ tmp = page->index << PAGE_CACHE_SHIFT;
bidx = tmp / bsize;
boff = tmp % bsize;
- while (from < to) {
+ while (pos < 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);
+ tmp = min(bsize - boff, to - pos);
+ BUG_ON(pos + tmp > to || tmp > bsize);
+ memcpy(data + pos, AFFS_DATA(bh) + boff, tmp);
affs_brelse(bh);
bidx++;
- from += tmp;
+ pos += tmp;
boff = 0;
}
flush_dcache_page(page);
@@ -529,7 +545,7 @@ affs_extent_file_ofs(struct inode *inode, u32 newsize)
u32 size, bsize;
u32 tmp;
- pr_debug("AFFS: extent_file(%u, %d)\n", (u32)inode->i_ino, newsize);
+ pr_debug("%s(%u, %d)\n", __func__, (u32)inode->i_ino, newsize);
bsize = AFFS_SB(sb)->s_data_blksize;
bh = NULL;
size = AFFS_I(inode)->mmu_private;
@@ -540,10 +556,9 @@ affs_extent_file_ofs(struct inode *inode, u32 newsize)
if (IS_ERR(bh))
return PTR_ERR(bh);
tmp = min(bsize - boff, newsize - size);
- if (boff + tmp > bsize || tmp > bsize)
- BUG();
+ BUG_ON(boff + tmp > bsize || tmp > bsize);
memset(AFFS_DATA(bh) + boff, 0, tmp);
- AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp);
+ be32_add_cpu(&AFFS_DATA_HEAD(bh)->size, tmp);
affs_fix_checksum(sb, bh);
mark_buffer_dirty_inode(bh, inode);
size += tmp;
@@ -560,8 +575,7 @@ affs_extent_file_ofs(struct inode *inode, u32 newsize)
if (IS_ERR(bh))
goto out;
tmp = min(bsize, newsize - size);
- if (tmp > bsize)
- BUG();
+ 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);
@@ -597,14 +611,14 @@ affs_readpage_ofs(struct file *file, struct page *page)
u32 to;
int err;
- pr_debug("AFFS: read_page(%u, %ld)\n", (u32)inode->i_ino, page->index);
+ pr_debug("%s(%u, %ld)\n", __func__, (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);
+ err = affs_do_readpage_ofs(page, to);
if (!err)
SetPageUptodate(page);
unlock_page(page);
@@ -620,7 +634,8 @@ static int affs_write_begin_ofs(struct file *file, struct address_space *mapping
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);
+ pr_debug("%s(%u, %llu, %llu)\n", __func__, (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
@@ -631,7 +646,7 @@ static int affs_write_begin_ofs(struct file *file, struct address_space *mapping
}
index = pos >> PAGE_CACHE_SHIFT;
- page = __grab_cache_page(mapping, index);
+ page = grab_cache_page_write_begin(mapping, index, flags);
if (!page)
return -ENOMEM;
*pagep = page;
@@ -640,7 +655,7 @@ static int affs_write_begin_ofs(struct file *file, struct address_space *mapping
return 0;
/* XXX: inefficient but safe in the face of short writes */
- err = affs_do_readpage_ofs(file, page, 0, PAGE_CACHE_SIZE);
+ err = affs_do_readpage_ofs(page, PAGE_CACHE_SIZE);
if (err) {
unlock_page(page);
page_cache_release(page);
@@ -669,7 +684,9 @@ static int affs_write_end_ofs(struct file *file, struct address_space *mapping,
* 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);
+ pr_debug("%s(%u, %llu, %llu)\n",
+ __func__, (u32)inode->i_ino, (unsigned long long)pos,
+ (unsigned long long)pos + len);
bsize = AFFS_SB(sb)->s_data_blksize;
data = page_address(page);
@@ -683,10 +700,9 @@ static int affs_write_end_ofs(struct file *file, struct address_space *mapping,
if (IS_ERR(bh))
return PTR_ERR(bh);
tmp = min(bsize - boff, to - from);
- if (boff + tmp > bsize || tmp > bsize)
- BUG();
+ BUG_ON(boff + tmp > bsize || tmp > bsize);
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);
+ be32_add_cpu(&AFFS_DATA_HEAD(bh)->size, tmp);
affs_fix_checksum(sb, bh);
mark_buffer_dirty_inode(bh, inode);
written += tmp;
@@ -732,8 +748,7 @@ static int affs_write_end_ofs(struct file *file, struct address_space *mapping,
if (IS_ERR(bh))
goto out;
tmp = min(bsize, to - from);
- if (tmp > bsize)
- BUG();
+ 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);
@@ -782,7 +797,6 @@ out:
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
};
@@ -794,7 +808,7 @@ affs_free_prealloc(struct inode *inode)
{
struct super_block *sb = inode->i_sb;
- pr_debug("AFFS: free_prealloc(ino=%lu)\n", inode->i_ino);
+ pr_debug("free_prealloc(ino=%lu)\n", inode->i_ino);
while (AFFS_I(inode)->i_pa_cnt) {
AFFS_I(inode)->i_pa_cnt--;
@@ -814,7 +828,7 @@ affs_truncate(struct inode *inode)
struct buffer_head *ext_bh;
int i;
- pr_debug("AFFS: truncate(inode=%d, oldsize=%u, newsize=%u)\n",
+ pr_debug("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;
@@ -828,12 +842,14 @@ affs_truncate(struct inode *inode)
struct address_space *mapping = inode->i_mapping;
struct page *page;
void *fsdata;
- u32 size = inode->i_size;
+ loff_t 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);
+ else
+ inode->i_size = AFFS_I(inode)->mmu_private;
mark_inode_dirty(inode);
return;
} else if (inode->i_size == AFFS_I(inode)->mmu_private)
@@ -869,6 +885,7 @@ affs_truncate(struct inode *inode)
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;
@@ -887,9 +904,9 @@ affs_truncate(struct inode *inode)
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)) {
+ if (IS_ERR(bh)) {
affs_warning(sb, "truncate", "unexpected read error for last block %u (%d)",
- ext, PTR_ERR(ext_bh));
+ ext, PTR_ERR(bh));
return;
}
tmp = be32_to_cpu(AFFS_DATA_HEAD(bh)->next);
@@ -917,3 +934,21 @@ affs_truncate(struct inode *inode)
}
affs_free_prealloc(inode);
}
+
+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;
+
+ mutex_lock(&inode->i_mutex);
+ ret = write_inode_now(inode, 0);
+ err = sync_blockdev(inode->i_sb->s_bdev);
+ if (!ret)
+ ret = err;
+ mutex_unlock(&inode->i_mutex);
+ return ret;
+}