summaryrefslogtreecommitdiffstats
path: root/fs/ufs/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ufs/inode.c')
-rw-r--r--fs/ufs/inode.c400
1 files changed, 204 insertions, 196 deletions
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index 636b0aabd..3d9c8f602 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -36,6 +36,7 @@
#include <linux/string.h>
#include <linux/locks.h>
#include <linux/mm.h>
+#include <linux/smp_lock.h>
#include "swab.h"
#include "util.h"
@@ -82,10 +83,10 @@ static void ufs_print_inode(struct inode * inode)
#define ufs_inode_bmap(inode, nr) \
(SWAB32((inode)->u.ufs_i.i_u1.i_data[(nr) >> uspi->s_fpbshift]) + ((nr) & uspi->s_fpbmask))
-static inline unsigned ufs_block_bmap (struct buffer_head * bh, unsigned nr,
+static inline unsigned int ufs_block_bmap (struct buffer_head * bh, unsigned nr,
struct ufs_sb_private_info * uspi, unsigned swab)
{
- unsigned tmp;
+ unsigned int tmp;
UFSD(("ENTER, nr %u\n", nr))
if (!bh)
@@ -96,86 +97,90 @@ static inline unsigned ufs_block_bmap (struct buffer_head * bh, unsigned nr,
return tmp;
}
-int ufs_bmap (struct inode * inode, int fragment)
+int ufs_frag_map(struct inode *inode, int frag)
{
- struct super_block * sb;
- struct ufs_sb_private_info * uspi;
- unsigned tmp;
- unsigned swab;
+ struct super_block *sb;
+ struct ufs_sb_private_info *uspi;
+ unsigned int swab;
+ int i, ret;
+
+ ret = 0;
+ lock_kernel();
sb = inode->i_sb;
uspi = sb->u.ufs_sb.s_uspi;
swab = sb->u.ufs_sb.s_swab;
-
- UFSD(("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment))
-
- if (fragment >= ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb) << uspi->s_fpbshift)) {
- ufs_warning (sb, "ufs_bmap", "block > big");
- return 0;
+ if (frag < 0) {
+ ufs_warning(sb, "ufs_frag_map", "frag < 0");
+ goto out;
}
-
- /*
- * direct fragment
- */
- if (fragment < UFS_NDIR_FRAGMENT)
- return (uspi->s_sbbase + ufs_inode_bmap (inode, fragment));
-
- /*
- * indirect fragment
- */
- fragment -= UFS_NDIR_FRAGMENT;
- if (fragment < (1 << (uspi->s_apbshift + uspi->s_fpbshift))) {
- tmp = ufs_inode_bmap (inode,
- UFS_IND_FRAGMENT + (fragment >> uspi->s_apbshift));
- if (!tmp)
- return 0;
- return (uspi->s_sbbase +
- ufs_block_bmap (bread (sb->s_dev, uspi->s_sbbase + tmp, sb->s_blocksize),
- fragment & uspi->s_apbmask, uspi, swab));
+ if (frag >=
+ ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb)
+ << uspi->s_fpbshift)) {
+ ufs_warning(sb, "ufs_frag_map", "frag > big");
+ goto out;
}
- /*
- * dindirect fragment
- */
- fragment -= 1 << (uspi->s_apbshift + uspi->s_fpbshift);
- if (fragment < (1 << (uspi->s_2apbshift + uspi->s_fpbshift))) {
- tmp = ufs_inode_bmap (inode,
- UFS_DIND_FRAGMENT + (fragment >> uspi->s_2apbshift));
- if (!tmp)
- return 0;
- tmp = ufs_block_bmap (bread (sb->s_dev, uspi->s_sbbase + tmp, sb->s_blocksize),
- (fragment >> uspi->s_apbshift) & uspi->s_apbmask, uspi, swab);
- if (!tmp)
- return 0;
- return (uspi->s_sbbase +
- ufs_block_bmap (bread (sb->s_dev, uspi->s_sbbase + tmp, sb->s_blocksize),
- fragment & uspi->s_apbmask, uspi, swab));
+ if (frag < UFS_NDIR_FRAGMENT) {
+ ret = uspi->s_sbbase + ufs_inode_bmap(inode, frag);
+ goto out;
}
- /*
- * tindirect fragment
- */
- fragment -= 1 << (uspi->s_2apbshift + uspi->s_fpbshift);
- tmp = ufs_inode_bmap (inode,
- UFS_TIND_FRAGMENT + (fragment >> uspi->s_3apbshift));
- if (!tmp)
- return 0;
- tmp = ufs_block_bmap (bread (sb->s_dev, uspi->s_sbbase + tmp, sb->s_blocksize),
- (fragment >> uspi->s_2apbshift) & uspi->s_apbmask, uspi, swab);
- if (!tmp)
- return 0;
- tmp = ufs_block_bmap (bread (sb->s_dev, uspi->s_sbbase + tmp, sb->s_blocksize),
- (fragment >> uspi->s_apbshift) & uspi->s_apbmask, uspi, swab);
- if (!tmp)
- return 0;
- return (uspi->s_sbbase +
- ufs_block_bmap (bread (sb->s_dev, uspi->s_sbbase + tmp, sb->s_blocksize),
- fragment & uspi->s_apbmask, uspi, swab));
+ frag -= UFS_NDIR_FRAGMENT;
+ if (frag < (1 << (uspi->s_apbshift + uspi->s_fpbshift))) {
+ i = ufs_inode_bmap(inode,
+ UFS_IND_FRAGMENT + (frag >> uspi->s_apbshift));
+ if (!i)
+ goto out;
+ ret = (uspi->s_sbbase +
+ ufs_block_bmap(bread(sb->s_dev, uspi->s_sbbase + i,
+ sb->s_blocksize),
+ frag & uspi->s_apbmask, uspi, swab));
+ }
+ frag -= 1 << (uspi->s_apbshift + uspi->s_fpbshift);
+ if (frag < (1 << (uspi->s_2apbshift + uspi->s_fpbshift))) {
+ i = ufs_inode_bmap (inode,
+ UFS_DIND_FRAGMENT + (frag >> uspi->s_2apbshift));
+ if (!i)
+ goto out;
+ i = ufs_block_bmap(bread(sb->s_dev, uspi->s_sbbase + i,
+ sb->s_blocksize),
+ (frag >> uspi->s_apbshift) & uspi->s_apbmask,
+ uspi, swab);
+ if (!i)
+ goto out;
+ ret = (uspi->s_sbbase +
+ ufs_block_bmap(bread(sb->s_dev, uspi->s_sbbase + i,
+ sb->s_blocksize),
+ (frag & uspi->s_apbmask), uspi, swab));
+ goto out;
+ }
+ frag -= 1 << (uspi->s_2apbshift + uspi->s_fpbshift);
+ i = ufs_inode_bmap(inode,
+ UFS_TIND_FRAGMENT + (frag >> uspi->s_3apbshift));
+ if (!i)
+ goto out;
+ i = ufs_block_bmap(bread(sb->s_dev, uspi->s_sbbase + i, sb->s_blocksize),
+ (frag >> uspi->s_2apbshift) & uspi->s_apbmask,
+ uspi, swab);
+ if (!i)
+ goto out;
+ i = ufs_block_bmap(bread(sb->s_dev, uspi->s_sbbase + i, sb->s_blocksize),
+ (frag >> uspi->s_apbshift) & uspi->s_apbmask,
+ uspi, swab);
+ if (!i)
+ goto out;
+ ret = (uspi->s_sbbase +
+ ufs_block_bmap(bread(sb->s_dev, uspi->s_sbbase + i, sb->s_blocksize),
+ (frag & uspi->s_apbmask), uspi, swab));
+out:
+ unlock_kernel();
+ return ret;
}
-static struct buffer_head * ufs_inode_getfrag (struct inode * inode,
- unsigned fragment, unsigned new_fragment, int create,
- unsigned required, int *err, int metadata, int *phys_block, int *created)
+static struct buffer_head * ufs_inode_getfrag (struct inode *inode,
+ unsigned int fragment, unsigned int new_fragment,
+ unsigned int required, int *err, int metadata, long *phys, int *new)
{
struct super_block * sb;
struct ufs_sb_private_info * uspi;
@@ -184,7 +189,7 @@ static struct buffer_head * ufs_inode_getfrag (struct inode * inode,
unsigned block, blockoff, lastfrag, lastblock, lastblockoff;
unsigned tmp, goal;
u32 * p, * p2;
- unsigned swab;
+ unsigned int swab;
UFSD(("ENTER, ino %lu, fragment %u, new_fragment %u, required %u\n",
inode->i_ino, fragment, new_fragment, required))
@@ -206,18 +211,17 @@ repeat:
sb->s_blocksize);
if (tmp == SWAB32(*p)) {
UFSD(("EXIT, result %u\n", tmp + blockoff))
- return result;
+ return result;
}
brelse (result);
goto repeat;
} else {
- *phys_block = tmp;
+ *phys = tmp;
return NULL;
}
}
*err = -EFBIG;
- if (!create)
- return NULL;
+
limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
if (limit < RLIM_INFINITY) {
limit >>= sb->s_blocksize_bits;
@@ -226,6 +230,7 @@ repeat:
return NULL;
}
}
+
lastblock = ufs_fragstoblks (lastfrag);
lastblockoff = ufs_fragnum (lastfrag);
/*
@@ -270,10 +275,10 @@ repeat:
}
if (!tmp) {
if ((!blockoff && SWAB32(*p)) ||
- (blockoff && lastfrag != inode->u.ufs_i.i_lastfrag))
+ (blockoff && lastfrag != inode->u.ufs_i.i_lastfrag))
goto repeat;
- else
- return NULL;
+ *err = -ENOSPC;
+ return NULL;
}
/* The nullification of framgents done in ufs/balloc.c is
@@ -283,10 +288,10 @@ repeat:
if (metadata) {
result = getblk (inode->i_dev, tmp + blockoff, sb->s_blocksize);
} else {
- *phys_block = tmp;
+ *phys = tmp;
result = NULL;
*err = 0;
- *created = 1;
+ *new = 1;
}
inode->i_ctime = CURRENT_TIME;
@@ -297,16 +302,16 @@ repeat:
return result;
}
-static struct buffer_head * ufs_block_getfrag (struct inode * inode,
- struct buffer_head * bh, unsigned fragment, unsigned new_fragment,
- int create, unsigned blocksize, int * err, int metadata, int *phys_block, int *created)
+static struct buffer_head * ufs_block_getfrag (struct inode *inode,
+ struct buffer_head *bh, unsigned int fragment, unsigned int new_fragment,
+ unsigned int blocksize, int * err, int metadata, long *phys, int *new)
{
struct super_block * sb;
struct ufs_sb_private_info * uspi;
struct buffer_head * result;
unsigned tmp, goal, block, blockoff;
u32 * p;
- unsigned swab;
+ unsigned int swab;
sb = inode->i_sb;
swab = sb->u.ufs_sb.s_swab;
@@ -316,15 +321,14 @@ static struct buffer_head * ufs_block_getfrag (struct inode * inode,
UFSD(("ENTER, ino %lu, fragment %u, new_fragment %u\n", inode->i_ino, fragment, new_fragment))
+ result = NULL;
if (!bh)
- return NULL;
+ goto out;
if (!buffer_uptodate(bh)) {
ll_rw_block (READ, 1, &bh);
wait_on_buffer (bh);
- if (!buffer_uptodate(bh)) {
- brelse (bh);
- return NULL;
- }
+ if (!buffer_uptodate(bh))
+ goto out;
}
p = (u32 *) bh->b_data + block;
@@ -334,24 +338,18 @@ repeat:
if (metadata) {
result = getblk (bh->b_dev, uspi->s_sbbase + tmp + blockoff,
sb->s_blocksize);
- if (tmp == SWAB32(*p)) {
- brelse (bh);
- UFSD(("EXIT, result %u\n", tmp + blockoff))
- return result;
- }
+ if (tmp == SWAB32(*p))
+ goto out;
brelse (result);
goto repeat;
} else {
- *phys_block = tmp;
- brelse (bh);
- return NULL;
+ *phys = tmp;
+ goto out;
}
}
*err = -EFBIG;
- if (!create) {
- brelse (bh);
- return NULL;
- } else {
+
+ {
unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
if (limit < RLIM_INFINITY) {
limit >>= sb->s_blocksize_bits;
@@ -368,12 +366,9 @@ repeat:
goal = bh->b_blocknr + uspi->s_fpb;
tmp = ufs_new_fragments (inode, p, ufs_blknum(new_fragment), goal, uspi->s_fpb, err);
if (!tmp) {
- if (SWAB32(*p)) {
+ if (SWAB32(*p))
goto repeat;
- } else {
- brelse (bh);
- return NULL;
- }
+ goto out;
}
/* The nullification of framgents done in ufs/balloc.c is
@@ -383,10 +378,8 @@ repeat:
if (metadata) {
result = getblk (bh->b_dev, tmp + blockoff, sb->s_blocksize);
} else {
- *phys_block = tmp;
- result = NULL;
- *err = 0;
- *created = 1;
+ *phys = tmp;
+ *new = 1;
}
mark_buffer_dirty(bh, 1);
@@ -396,122 +389,137 @@ repeat:
}
inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(inode);
+out:
brelse (bh);
UFSD(("EXIT, result %u\n", tmp + blockoff))
return result;
}
-int ufs_getfrag_block (struct inode * inode, long fragment,
- int create, int * err, int *created)
+int ufs_getfrag_block (struct inode *inode, long fragment, struct buffer_head *bh_result, int create)
{
struct super_block * sb;
struct ufs_sb_private_info * uspi;
- struct buffer_head * bh, * tmp;
- unsigned f;
- unsigned swab;
- int phys_block;
+ struct buffer_head * bh;
+ unsigned int swab;
+ int ret, err, new;
+ unsigned long ptr, phys;
sb = inode->i_sb;
uspi = sb->u.ufs_sb.s_uspi;
swab = sb->u.ufs_sb.s_swab;
- *err = -EIO;
- UFSD(("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment))
- if (fragment < 0) {
- ufs_warning (sb, "ufs_getblk", "block < 0");
- return 0;
- }
- if (fragment > ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb) << uspi->s_fpbshift)) {
- ufs_warning (sb, "ufs_getblk", "block > big");
+ if (!create) {
+ phys = ufs_frag_map(inode, fragment);
+ if (phys) {
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr = phys;
+ bh_result->b_state |= (1UL << BH_Mapped);
+ }
return 0;
}
- *err = -ENOSPC;
- f = fragment;
- *created = 0;
+ err = -EIO;
+ new = 0;
+ ret = 0;
+ bh = NULL;
+
+ lock_kernel();
+
+ UFSD(("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment))
+ if (fragment < 0)
+ goto abort_negative;
+ if (fragment >
+ ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb)
+ << uspi->s_fpbshift))
+ goto abort_too_big;
+
+ err = 0;
+ ptr = fragment;
/*
- * Direct fragment
- */
- if (fragment < UFS_NDIR_FRAGMENT) {
- tmp = ufs_inode_getfrag (inode, fragment, fragment, create, 1,
- err, 0, &phys_block, created);
- goto out;
- }
- /*
- * Indirect fragment
- */
- fragment -= UFS_NDIR_FRAGMENT;
- if (fragment < (1 << (uspi->s_apbshift + uspi->s_fpbshift))) {
- bh = ufs_inode_getfrag (inode,
- UFS_IND_FRAGMENT + (fragment >> uspi->s_apbshift),
- f, create, uspi->s_fpb, err, 1, NULL, NULL);
- tmp = ufs_block_getfrag (inode, bh,
- fragment & uspi->s_apbmask,
- f, create, sb->s_blocksize,
- err, 0, &phys_block, created);
- goto out;
- }
- /*
- * Dindirect fragment
+ * ok, these macros clean the logic up a bit and make
+ * it much more readable:
*/
- fragment -= 1 << (uspi->s_apbshift + uspi->s_fpbshift);
- if ( fragment < (1 << (uspi->s_2apbshift + uspi->s_fpbshift))) {
- bh = ufs_inode_getfrag (inode,
- UFS_DIND_FRAGMENT + (fragment >> uspi->s_2apbshift),
- f, create, uspi->s_fpb, err,
- 1, NULL, NULL);
- bh = ufs_block_getfrag (inode, bh,
- (fragment >> uspi->s_apbshift) & uspi->s_apbmask,
- f, create, sb->s_blocksize, err,
- 1, NULL, NULL);
- tmp = ufs_block_getfrag (inode, bh,
- fragment & uspi->s_apbmask,
- f, create, sb->s_blocksize, err,
- 0, &phys_block, created);
+#define GET_INODE_DATABLOCK(x) \
+ ufs_inode_getfrag(inode, x, fragment, 1, &err, 0, &phys, &new)
+#define GET_INODE_PTR(x) \
+ ufs_inode_getfrag(inode, x, fragment, uspi->s_fpb, &err, 1, NULL, NULL)
+#define GET_INDIRECT_DATABLOCK(x) \
+ ufs_block_getfrag(inode, bh, x, fragment, sb->s_blocksize, \
+ &err, 0, &phys, &new);
+#define GET_INDIRECT_PTR(x) \
+ ufs_block_getfrag(inode, bh, x, fragment, sb->s_blocksize, \
+ &err, 1, NULL, NULL);
+
+ if (ptr < UFS_NDIR_FRAGMENT) {
+ bh = GET_INODE_DATABLOCK(ptr);
goto out;
}
- /*
- * Tindirect fragment
- */
- fragment -= 1 << (uspi->s_2apbshift + uspi->s_fpbshift);
- bh = ufs_inode_getfrag (inode,
- UFS_TIND_FRAGMENT + (fragment >> uspi->s_3apbshift),
- f, create, uspi->s_fpb, err, 1, NULL, NULL);
- bh = ufs_block_getfrag (inode, bh,
- (fragment >> uspi->s_2apbshift) & uspi->s_apbmask,
- f, create, sb->s_blocksize, err, 1, NULL, NULL);
- bh = ufs_block_getfrag (inode, bh,
- (fragment >> uspi->s_apbshift) & uspi->s_apbmask,
- f, create, sb->s_blocksize, err, 1, NULL, NULL);
- tmp = ufs_block_getfrag (inode, bh,
- fragment & uspi->s_apbmask,
- f, create, sb->s_blocksize, err, 0, &phys_block, created);
+ ptr -= UFS_NDIR_FRAGMENT;
+ if (ptr < (1 << (uspi->s_apbshift + uspi->s_fpbshift))) {
+ bh = GET_INODE_PTR(UFS_IND_FRAGMENT + (ptr >> uspi->s_apbshift));
+ goto get_indirect;
+ }
+ ptr -= 1 << (uspi->s_apbshift + uspi->s_fpbshift);
+ if (ptr < (1 << (uspi->s_2apbshift + uspi->s_fpbshift))) {
+ bh = GET_INODE_PTR(UFS_DIND_FRAGMENT + (ptr >> uspi->s_2apbshift));
+ goto get_double;
+ }
+ ptr -= 1 << (uspi->s_2apbshift + uspi->s_fpbshift);
+ bh = GET_INODE_PTR(UFS_TIND_FRAGMENT + (ptr >> uspi->s_3apbshift));
+ bh = GET_INDIRECT_PTR((ptr >> uspi->s_2apbshift) & uspi->s_apbmask);
+get_double:
+ bh = GET_INDIRECT_PTR((ptr >> uspi->s_apbshift) & uspi->s_apbmask);
+get_indirect:
+ bh = GET_INDIRECT_DATABLOCK(ptr & uspi->s_apbmask);
+
+#undef GET_INODE_DATABLOCK
+#undef GET_INODE_PTR
+#undef GET_INDIRECT_DATABLOCK
+#undef GET_INDIRECT_PTR
out:
- if (!phys_block)
- return 0;
- if (*err)
- return 0;
- return phys_block;
+ if (err)
+ goto abort;
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr = phys;
+ bh_result->b_state |= (1UL << BH_Mapped);
+ if (new)
+ bh_result->b_state |= (1UL << BH_New);
+abort:
+ unlock_kernel();
+ return err;
+
+abort_negative:
+ ufs_warning(sb, "ufs_get_block", "block < 0");
+ goto abort;
+
+abort_too_big:
+ ufs_warning(sb, "ufs_get_block", "block > big");
+ goto abort;
}
struct buffer_head *ufs_getfrag(struct inode *inode, unsigned int fragment,
int create, int *err)
{
- struct buffer_head *tmp = NULL;
- int phys_block, created;
-
- phys_block = ufs_getfrag_block(inode, fragment, create, err, &created);
- if (phys_block) {
- tmp = getblk(inode->i_dev, phys_block, inode->i_sb->s_blocksize);
- if (created) {
- memset(tmp->b_data, 0, inode->i_sb->s_blocksize);
- mark_buffer_uptodate(tmp, 1);
- mark_buffer_dirty(tmp, 1);
+ struct buffer_head dummy;
+ int error;
+
+ dummy.b_state = 0;
+ dummy.b_blocknr = -1000;
+ error = ufs_getfrag_block(inode, fragment, &dummy, create);
+ *err = error;
+ if (!error && buffer_mapped(&dummy)) {
+ struct buffer_head *bh;
+ bh = getblk(dummy.b_dev, dummy.b_blocknr, inode->i_sb->s_blocksize);
+ if (buffer_new(&dummy)) {
+ memset(bh->b_data, 0, inode->i_sb->s_blocksize);
+ mark_buffer_uptodate(bh, 1);
+ mark_buffer_dirty(bh, 1);
}
+ return bh;
}
- return tmp;
+ return NULL;
}
struct buffer_head * ufs_bread (struct inode * inode, unsigned fragment,