Commit 5faab9e0 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull UFS fixes from Al Viro:
 "This is just the obvious backport fodder; I'm pretty sure that there
  will be more - definitely so wrt performance and quite possibly
  correctness as well"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  ufs: we need to sync inode before freeing it
  excessive checks in ufs_write_failed() and ufs_evict_inode()
  ufs_getfrag_block(): we only grab ->truncate_mutex on block creation path
  ufs_extend_tail(): fix the braino in calling conventions of ufs_new_fragments()
  ufs: set correct ->s_maxsize
  ufs: restore maintaining ->i_blocks
  fix ufs_isblockset()
  ufs: restore proper tail allocation
parents 66cea28a 67a70017
...@@ -672,6 +672,7 @@ void __inode_add_bytes(struct inode *inode, loff_t bytes) ...@@ -672,6 +672,7 @@ void __inode_add_bytes(struct inode *inode, loff_t bytes)
inode->i_bytes -= 512; inode->i_bytes -= 512;
} }
} }
EXPORT_SYMBOL(__inode_add_bytes);
void inode_add_bytes(struct inode *inode, loff_t bytes) void inode_add_bytes(struct inode *inode, loff_t bytes)
{ {
......
...@@ -82,7 +82,8 @@ void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count) ...@@ -82,7 +82,8 @@ void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count)
ufs_error (sb, "ufs_free_fragments", ufs_error (sb, "ufs_free_fragments",
"bit already cleared for fragment %u", i); "bit already cleared for fragment %u", i);
} }
inode_sub_bytes(inode, count << uspi->s_fshift);
fs32_add(sb, &ucg->cg_cs.cs_nffree, count); fs32_add(sb, &ucg->cg_cs.cs_nffree, count);
uspi->cs_total.cs_nffree += count; uspi->cs_total.cs_nffree += count;
fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count); fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
...@@ -184,6 +185,7 @@ void ufs_free_blocks(struct inode *inode, u64 fragment, unsigned count) ...@@ -184,6 +185,7 @@ void ufs_free_blocks(struct inode *inode, u64 fragment, unsigned count)
ufs_error(sb, "ufs_free_blocks", "freeing free fragment"); ufs_error(sb, "ufs_free_blocks", "freeing free fragment");
} }
ubh_setblock(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno); ubh_setblock(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
inode_sub_bytes(inode, uspi->s_fpb << uspi->s_fshift);
if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD) if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
ufs_clusteracct (sb, ucpi, blkno, 1); ufs_clusteracct (sb, ucpi, blkno, 1);
...@@ -494,6 +496,20 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment, ...@@ -494,6 +496,20 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment,
return 0; return 0;
} }
static bool try_add_frags(struct inode *inode, unsigned frags)
{
unsigned size = frags * i_blocksize(inode);
spin_lock(&inode->i_lock);
__inode_add_bytes(inode, size);
if (unlikely((u32)inode->i_blocks != inode->i_blocks)) {
__inode_sub_bytes(inode, size);
spin_unlock(&inode->i_lock);
return false;
}
spin_unlock(&inode->i_lock);
return true;
}
static u64 ufs_add_fragments(struct inode *inode, u64 fragment, static u64 ufs_add_fragments(struct inode *inode, u64 fragment,
unsigned oldcount, unsigned newcount) unsigned oldcount, unsigned newcount)
{ {
...@@ -530,6 +546,9 @@ static u64 ufs_add_fragments(struct inode *inode, u64 fragment, ...@@ -530,6 +546,9 @@ static u64 ufs_add_fragments(struct inode *inode, u64 fragment,
for (i = oldcount; i < newcount; i++) for (i = oldcount; i < newcount; i++)
if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i)) if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i))
return 0; return 0;
if (!try_add_frags(inode, count))
return 0;
/* /*
* Block can be extended * Block can be extended
*/ */
...@@ -647,6 +666,7 @@ static u64 ufs_alloc_fragments(struct inode *inode, unsigned cgno, ...@@ -647,6 +666,7 @@ static u64 ufs_alloc_fragments(struct inode *inode, unsigned cgno,
ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, goal + i); ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, goal + i);
i = uspi->s_fpb - count; i = uspi->s_fpb - count;
inode_sub_bytes(inode, i << uspi->s_fshift);
fs32_add(sb, &ucg->cg_cs.cs_nffree, i); fs32_add(sb, &ucg->cg_cs.cs_nffree, i);
uspi->cs_total.cs_nffree += i; uspi->cs_total.cs_nffree += i;
fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, i); fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, i);
...@@ -657,6 +677,8 @@ static u64 ufs_alloc_fragments(struct inode *inode, unsigned cgno, ...@@ -657,6 +677,8 @@ static u64 ufs_alloc_fragments(struct inode *inode, unsigned cgno,
result = ufs_bitmap_search (sb, ucpi, goal, allocsize); result = ufs_bitmap_search (sb, ucpi, goal, allocsize);
if (result == INVBLOCK) if (result == INVBLOCK)
return 0; return 0;
if (!try_add_frags(inode, count))
return 0;
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, result + i); ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, result + i);
...@@ -716,6 +738,8 @@ static u64 ufs_alloccg_block(struct inode *inode, ...@@ -716,6 +738,8 @@ static u64 ufs_alloccg_block(struct inode *inode,
return INVBLOCK; return INVBLOCK;
ucpi->c_rotor = result; ucpi->c_rotor = result;
gotit: gotit:
if (!try_add_frags(inode, uspi->s_fpb))
return 0;
blkno = ufs_fragstoblks(result); blkno = ufs_fragstoblks(result);
ubh_clrblock (UCPI_UBH(ucpi), ucpi->c_freeoff, blkno); ubh_clrblock (UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD) if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
......
...@@ -235,7 +235,8 @@ ufs_extend_tail(struct inode *inode, u64 writes_to, ...@@ -235,7 +235,8 @@ ufs_extend_tail(struct inode *inode, u64 writes_to,
p = ufs_get_direct_data_ptr(uspi, ufsi, block); p = ufs_get_direct_data_ptr(uspi, ufsi, block);
tmp = ufs_new_fragments(inode, p, lastfrag, ufs_data_ptr_to_cpu(sb, p), tmp = ufs_new_fragments(inode, p, lastfrag, ufs_data_ptr_to_cpu(sb, p),
new_size, err, locked_page); new_size - (lastfrag & uspi->s_fpbmask), err,
locked_page);
return tmp != 0; return tmp != 0;
} }
...@@ -284,7 +285,7 @@ ufs_inode_getfrag(struct inode *inode, unsigned index, ...@@ -284,7 +285,7 @@ ufs_inode_getfrag(struct inode *inode, unsigned index,
goal += uspi->s_fpb; goal += uspi->s_fpb;
} }
tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment), tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment),
goal, uspi->s_fpb, err, locked_page); goal, nfrags, err, locked_page);
if (!tmp) { if (!tmp) {
*err = -ENOSPC; *err = -ENOSPC;
...@@ -402,7 +403,9 @@ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buff ...@@ -402,7 +403,9 @@ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buff
if (!create) { if (!create) {
phys64 = ufs_frag_map(inode, offsets, depth); phys64 = ufs_frag_map(inode, offsets, depth);
goto out; if (phys64)
map_bh(bh_result, sb, phys64 + frag);
return 0;
} }
/* This code entered only while writing ....? */ /* This code entered only while writing ....? */
...@@ -841,8 +844,11 @@ void ufs_evict_inode(struct inode * inode) ...@@ -841,8 +844,11 @@ void ufs_evict_inode(struct inode * inode)
truncate_inode_pages_final(&inode->i_data); truncate_inode_pages_final(&inode->i_data);
if (want_delete) { if (want_delete) {
inode->i_size = 0; inode->i_size = 0;
if (inode->i_blocks) if (inode->i_blocks &&
(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode)))
ufs_truncate_blocks(inode); ufs_truncate_blocks(inode);
ufs_update_inode(inode, inode_needs_sync(inode));
} }
invalidate_inode_buffers(inode); invalidate_inode_buffers(inode);
...@@ -1100,7 +1106,7 @@ static int ufs_alloc_lastblock(struct inode *inode, loff_t size) ...@@ -1100,7 +1106,7 @@ static int ufs_alloc_lastblock(struct inode *inode, loff_t size)
return err; return err;
} }
static void __ufs_truncate_blocks(struct inode *inode) static void ufs_truncate_blocks(struct inode *inode)
{ {
struct ufs_inode_info *ufsi = UFS_I(inode); struct ufs_inode_info *ufsi = UFS_I(inode);
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
...@@ -1183,7 +1189,7 @@ static int ufs_truncate(struct inode *inode, loff_t size) ...@@ -1183,7 +1189,7 @@ static int ufs_truncate(struct inode *inode, loff_t size)
truncate_setsize(inode, size); truncate_setsize(inode, size);
__ufs_truncate_blocks(inode); ufs_truncate_blocks(inode);
inode->i_mtime = inode->i_ctime = current_time(inode); inode->i_mtime = inode->i_ctime = current_time(inode);
mark_inode_dirty(inode); mark_inode_dirty(inode);
out: out:
...@@ -1191,16 +1197,6 @@ static int ufs_truncate(struct inode *inode, loff_t size) ...@@ -1191,16 +1197,6 @@ static int ufs_truncate(struct inode *inode, loff_t size)
return err; return err;
} }
static void ufs_truncate_blocks(struct inode *inode)
{
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode)))
return;
if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
return;
__ufs_truncate_blocks(inode);
}
int ufs_setattr(struct dentry *dentry, struct iattr *attr) int ufs_setattr(struct dentry *dentry, struct iattr *attr)
{ {
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
......
...@@ -746,6 +746,23 @@ static void ufs_put_super(struct super_block *sb) ...@@ -746,6 +746,23 @@ static void ufs_put_super(struct super_block *sb)
return; return;
} }
static u64 ufs_max_bytes(struct super_block *sb)
{
struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
int bits = uspi->s_apbshift;
u64 res;
if (bits > 21)
res = ~0ULL;
else
res = UFS_NDADDR + (1LL << bits) + (1LL << (2*bits)) +
(1LL << (3*bits));
if (res >= (MAX_LFS_FILESIZE >> uspi->s_bshift))
return MAX_LFS_FILESIZE;
return res << uspi->s_bshift;
}
static int ufs_fill_super(struct super_block *sb, void *data, int silent) static int ufs_fill_super(struct super_block *sb, void *data, int silent)
{ {
struct ufs_sb_info * sbi; struct ufs_sb_info * sbi;
...@@ -1211,6 +1228,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -1211,6 +1228,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
"fast symlink size (%u)\n", uspi->s_maxsymlinklen); "fast symlink size (%u)\n", uspi->s_maxsymlinklen);
uspi->s_maxsymlinklen = maxsymlen; uspi->s_maxsymlinklen = maxsymlen;
} }
sb->s_maxbytes = ufs_max_bytes(sb);
sb->s_max_links = UFS_LINK_MAX; sb->s_max_links = UFS_LINK_MAX;
inode = ufs_iget(sb, UFS_ROOTINO); inode = ufs_iget(sb, UFS_ROOTINO);
......
...@@ -473,15 +473,19 @@ static inline unsigned _ubh_find_last_zero_bit_( ...@@ -473,15 +473,19 @@ static inline unsigned _ubh_find_last_zero_bit_(
static inline int _ubh_isblockset_(struct ufs_sb_private_info * uspi, static inline int _ubh_isblockset_(struct ufs_sb_private_info * uspi,
struct ufs_buffer_head * ubh, unsigned begin, unsigned block) struct ufs_buffer_head * ubh, unsigned begin, unsigned block)
{ {
u8 mask;
switch (uspi->s_fpb) { switch (uspi->s_fpb) {
case 8: case 8:
return (*ubh_get_addr (ubh, begin + block) == 0xff); return (*ubh_get_addr (ubh, begin + block) == 0xff);
case 4: case 4:
return (*ubh_get_addr (ubh, begin + (block >> 1)) == (0x0f << ((block & 0x01) << 2))); mask = 0x0f << ((block & 0x01) << 2);
return (*ubh_get_addr (ubh, begin + (block >> 1)) & mask) == mask;
case 2: case 2:
return (*ubh_get_addr (ubh, begin + (block >> 2)) == (0x03 << ((block & 0x03) << 1))); mask = 0x03 << ((block & 0x03) << 1);
return (*ubh_get_addr (ubh, begin + (block >> 2)) & mask) == mask;
case 1: case 1:
return (*ubh_get_addr (ubh, begin + (block >> 3)) == (0x01 << (block & 0x07))); mask = 0x01 << (block & 0x07);
return (*ubh_get_addr (ubh, begin + (block >> 3)) & mask) == mask;
} }
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment