patch-2.3.9 linux/fs/sysv/inode.c
Next file: linux/fs/sysv/symlink.c
Previous file: linux/fs/sysv/fsync.c
Back to the patch index
Back to the overall index
- Lines: 540
- Date:
Sun Jun 27 10:10:41 1999
- Orig file:
v2.3.8/linux/fs/sysv/inode.c
- Orig date:
Wed Jun 16 19:26:27 1999
diff -u --recursive --new-file v2.3.8/linux/fs/sysv/inode.c linux/fs/sysv/inode.c
@@ -31,6 +31,7 @@
#include <linux/string.h>
#include <linux/locks.h>
#include <linux/init.h>
+#include <linux/smp_lock.h>
#include <asm/byteorder.h>
#include <asm/uaccess.h>
@@ -62,6 +63,11 @@
sysv_free_inode(inode);
}
+static void sysv_put_super(struct super_block *);
+static void sysv_write_super(struct super_block *);
+static void sysv_read_inode(struct inode *);
+static int sysv_notify_change(struct dentry *, struct iattr *);
+static int sysv_statfs(struct super_block *, struct statfs *, int);
static struct super_operations sysv_sops = {
sysv_read_inode,
@@ -338,8 +344,8 @@
return sb;
}
-struct super_block *sysv_read_super(struct super_block *sb,void *data,
- int silent)
+static struct super_block *sysv_read_super(struct super_block *sb,
+ void *data, int silent)
{
struct buffer_head *bh;
const char *found;
@@ -519,7 +525,7 @@
}
/* This is only called on sync() and umount(), when s_dirt=1. */
-void sysv_write_super (struct super_block *sb)
+static void sysv_write_super(struct super_block *sb)
{
lock_super(sb);
if (buffer_dirty(sb->sv_bh1) || buffer_dirty(sb->sv_bh2)) {
@@ -542,7 +548,7 @@
unlock_super(sb);
}
-void sysv_put_super(struct super_block *sb)
+static void sysv_put_super(struct super_block *sb)
{
/* we can assume sysv_write_super() has already been called,
and that the superblock is locked */
@@ -555,7 +561,7 @@
MOD_DEC_USE_COUNT;
}
-int sysv_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+static int sysv_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
{
struct statfs tmp;
@@ -597,59 +603,72 @@
return tmp + sb->sv_block_base;
}
-int sysv_bmap(struct inode * inode,int block_nr)
+static unsigned int sysv_block_map(struct inode *inode, unsigned int block)
{
- unsigned int block = block_nr;
- struct super_block * sb = inode->i_sb;
- int convert;
- int i;
- struct buffer_head * bh;
+ struct super_block *sb;
+ int i, ret, convert;
- if (block < 10)
- return inode_bmap(sb,inode,block);
+ ret = 0;
+ lock_kernel();
+ sb = inode->i_sb;
+ if (block < 10) {
+ ret = inode_bmap(sb, inode, block);
+ goto out;
+ }
block -= 10;
convert = sb->sv_convert;
if (block < sb->sv_ind_per_block) {
- i = inode_bmap(sb,inode,10);
+ i = inode_bmap(sb, inode, 10);
if (!i)
- return 0;
- bh = bread(inode->i_dev,i,sb->sv_block_size);
- return block_bmap(sb, bh, block, convert);
+ goto out;
+ ret = block_bmap(sb,
+ bread(inode->i_dev, i, sb->sv_block_size),
+ block, convert);
+ goto out;
}
block -= sb->sv_ind_per_block;
if (block < sb->sv_ind_per_block_2) {
- i = inode_bmap(sb,inode,11);
+ i = inode_bmap(sb, inode, 11);
if (!i)
- return 0;
- bh = bread(inode->i_dev,i,sb->sv_block_size);
- i = block_bmap(sb, bh, block >> sb->sv_ind_per_block_bits, convert);
+ goto out;
+ i = block_bmap(sb,
+ bread(inode->i_dev, i, sb->sv_block_size),
+ (block >> sb->sv_ind_per_block_bits), convert);
if (!i)
- return 0;
- bh = bread(inode->i_dev,i,sb->sv_block_size);
- return block_bmap(sb, bh, block & sb->sv_ind_per_block_1, convert);
+ goto out;
+ ret = block_bmap(sb,
+ bread(inode->i_dev, i, sb->sv_block_size),
+ (block & sb->sv_ind_per_block_1), convert);
+ goto out;
}
block -= sb->sv_ind_per_block_2;
if (block < sb->sv_ind_per_block_3) {
- i = inode_bmap(sb,inode,12);
+ i = inode_bmap(sb, inode, 12);
if (!i)
- return 0;
- bh = bread(inode->i_dev,i,sb->sv_block_size);
- i = block_bmap(sb, bh, block >> sb->sv_ind_per_block_2_bits, convert);
+ goto out;
+ i = block_bmap(sb,
+ bread(inode->i_dev, i, sb->sv_block_size),
+ (block >> sb->sv_ind_per_block_2_bits), convert);
if (!i)
- return 0;
- bh = bread(inode->i_dev,i,sb->sv_block_size);
- i = block_bmap(sb, bh, (block >> sb->sv_ind_per_block_bits) & sb->sv_ind_per_block_1,convert);
+ goto out;
+ ret = block_bmap(sb,
+ bread(inode->i_dev, i, sb->sv_block_size),
+ ((block >> sb->sv_ind_per_block_bits) &
+ sb->sv_ind_per_block_1), convert);
if (!i)
- return 0;
- bh = bread(inode->i_dev,i,sb->sv_block_size);
- return block_bmap(sb, bh, block & sb->sv_ind_per_block_1, convert);
- }
- if ((int)block<0) {
- printk("sysv_bmap: block<0");
- return 0;
+ goto out;
+ ret = block_bmap(sb,
+ bread(inode->i_dev, i, sb->sv_block_size),
+ (block & sb->sv_ind_per_block_1), convert);
+ goto out;
}
- printk("sysv_bmap: block>big");
- return 0;
+ if ((int)block < 0)
+ printk("sysv_block_map: block < 0\n");
+ else
+ printk("sysv_block_map: block > big\n");
+out:
+ unlock_kernel();
+ return ret;
}
/* End of bmap support. */
@@ -657,8 +676,8 @@
/* Access selected blocks of regular files (or directories) */
-static struct buffer_head * inode_getblk(struct inode * inode, int nr, int create,
- int metadata, int *phys_block, int *created)
+static struct buffer_head *inode_getblk(struct inode *inode, int nr, int new_block,
+ int *err, int metadata, long *phys, int *new)
{
struct super_block *sb;
u32 tmp;
@@ -677,15 +696,30 @@
brelse(result);
goto repeat;
} else {
- *phys_block = tmp;
+ *phys = tmp;
return NULL;
}
}
- if (!create)
- return NULL;
+ *err = -EFBIG;
+
+ /* Check file limits.. */
+ {
+ unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+ if (limit < RLIM_INFINITY) {
+ limit >>= sb->sv_block_size_bits;
+ if (new_block >= limit) {
+ send_sig(SIGXFSZ, current, 0);
+ *err = -EFBIG;
+ return NULL;
+ }
+ }
+ }
+
tmp = sysv_new_block(sb);
- if (!tmp)
+ if (!tmp) {
+ *err = -ENOSPC;
return NULL;
+ }
if (metadata) {
result = sv_getblk(sb, inode->i_dev, tmp);
if (*p) {
@@ -695,12 +729,18 @@
}
} else {
if (*p) {
+ /*
+ * Nobody is allowed to change block allocation
+ * state from under us:
+ */
+ BUG();
sysv_free_block(sb, tmp);
goto repeat;
}
- *phys_block = tmp;
+ *phys = tmp;
result = NULL;
- *created = 1;
+ *err = 0;
+ *new = 1;
}
*p = tmp;
@@ -709,24 +749,24 @@
return result;
}
-static struct buffer_head * block_getblk(struct inode * inode,
- struct buffer_head * bh, int nr, int create,
- int metadata, int *phys_block, int *created)
+static struct buffer_head *block_getblk(struct inode *inode,
+ struct buffer_head *bh, int nr, int new_block, int *err,
+ int metadata, long *phys, int *new)
{
struct super_block *sb;
u32 tmp, block;
sysv_zone_t *p;
struct buffer_head * result;
+ unsigned long limit;
+ 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;
}
sb = inode->i_sb;
p = nr + (sysv_zone_t *) bh->b_data;
@@ -737,120 +777,175 @@
if (tmp) {
if (metadata) {
result = sv_getblk(sb, bh->b_dev, block);
- if (tmp == *p) {
- brelse(bh);
- return result;
- }
+ if (tmp == *p)
+ goto out;
brelse(result);
goto repeat;
} else {
- *phys_block = tmp;
- brelse(bh);
- return NULL;
+ *phys = tmp;
+ goto out;
}
}
- if (!create) {
- brelse(bh);
- return NULL;
+ *err = -EFBIG;
+
+ limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+ if (limit < RLIM_INFINITY) {
+ limit >>= sb->sv_block_size_bits;
+ if (new_block >= limit) {
+ send_sig(SIGXFSZ, current, 0);
+ goto out;
+ }
}
+
block = sysv_new_block(sb);
- if (!block) {
- brelse(bh);
- return NULL;
- }
+ if (!block)
+ goto out;
if (metadata) {
result = sv_getblk(sb, bh->b_dev, block);
if (*p) {
- sysv_free_block(sb,block);
+ sysv_free_block(sb, block);
brelse(result);
goto repeat;
}
+ memset(result->b_data, 0, sb->sv_block_size);
+ mark_buffer_uptodate(result, 1);
+ mark_buffer_dirty(result, 1);
} else {
- *phys_block = tmp;
- result = NULL;
- *created = 1;
+ *phys = tmp;
+ *new = 1;
+ }
+ if (*p) {
+ sysv_free_block(sb, block);
+ brelse(result);
+ goto repeat;
}
*p = (sb->sv_convert ? to_coh_ulong(block) : block);
mark_buffer_dirty(bh, 1);
+ *err = 0;
+out:
brelse(bh);
return result;
}
-int sysv_getblk_block(struct inode *inode, long block, int create,
- int *err, int *created)
+int sysv_get_block(struct inode *inode, long iblock, struct buffer_head *bh_result, int create)
{
- struct super_block *sb = inode->i_sb;
- struct buffer_head *bh, *tmp;
- int phys_block;
-
- *err = -EIO;
- if (block < 0) {
- printk("sysv_getblk: block<0");
- return 0;
- }
- if (block > sb->sv_ind_per_block_3) {
- printk("sysv_getblk: block>big");
+ struct super_block *sb;
+ int ret, err, new;
+ struct buffer_head *bh;
+ unsigned long ptr, phys;
+
+ if (!create) {
+ phys = sysv_block_map(inode, iblock);
+ if (phys) {
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr = phys;
+ bh_result->b_state |= (1UL << BH_Mapped);
+ }
return 0;
}
- if (block < 10) {
- tmp = inode_getblk(inode, block, create,
- 0, &phys_block, created);
- goto out;
- }
- block -= 10;
- if (block < sb->sv_ind_per_block) {
- bh = inode_getblk(inode, 10, create, 1, NULL, NULL);
- tmp = block_getblk(inode, bh, block, create,
- 0, &phys_block, created);
- goto out;
- }
- block -= sb->sv_ind_per_block;
- if (block < sb->sv_ind_per_block_2) {
- bh = inode_getblk(inode, 11, create, 1, NULL, NULL);
- bh = block_getblk(inode, bh, block >> sb->sv_ind_per_block_bits, create,
- 1, NULL, NULL);
- tmp = block_getblk(inode, bh, block & sb->sv_ind_per_block_1, create,
- 0, &phys_block, created);
+
+ err = -EIO;
+ new = 0;
+ ret = 0;
+ bh = NULL;
+
+ lock_kernel();
+ sb = inode->i_sb;
+ if (iblock < 0)
+ goto abort_negative;
+ if (iblock > sb->sv_ind_per_block_3)
+ goto abort_too_big;
+
+ err = 0;
+ ptr = iblock;
+
+ /*
+ * ok, these macros clean the logic up a bit and make
+ * it much more readable:
+ */
+#define GET_INODE_DATABLOCK(x) \
+ inode_getblk(inode, x, iblock, &err, 0, &phys, &new)
+#define GET_INODE_PTR(x) \
+ inode_getblk(inode, x, iblock, &err, 1, NULL, NULL)
+#define GET_INDIRECT_DATABLOCK(x) \
+ block_getblk (inode, bh, x, iblock, &err, 0, &phys, &new);
+#define GET_INDIRECT_PTR(x) \
+ block_getblk (inode, bh, x, iblock, &err, 1, NULL, NULL);
+
+ if (ptr < 10) {
+ bh = GET_INODE_DATABLOCK(ptr);
goto out;
}
- block -= sb->sv_ind_per_block_2;
- bh = inode_getblk(inode, 12, create, 1, NULL, NULL);
- bh = block_getblk(inode, bh, block >> sb->sv_ind_per_block_2_bits, create,
- 1, NULL, NULL);
- bh = block_getblk(inode, bh,
- (block >> sb->sv_ind_per_block_bits) & sb->sv_ind_per_block_1,
- create, 1, NULL, NULL);
- tmp = block_getblk(inode, bh, block & sb->sv_ind_per_block_1, create,
- 0, &phys_block, created);
+ ptr -= 10;
+ if (ptr < sb->sv_ind_per_block) {
+ bh = GET_INODE_PTR(10);
+ goto get_indirect;
+ }
+ ptr -= sb->sv_ind_per_block;
+ if (ptr < sb->sv_ind_per_block_2) {
+ bh = GET_INODE_PTR(11);
+ goto get_double;
+ }
+ ptr -= sb->sv_ind_per_block_2;
+ bh = GET_INODE_PTR(12);
+ bh = GET_INDIRECT_PTR(ptr >> sb->sv_ind_per_block_2_bits);
+get_double:
+ bh = GET_INDIRECT_PTR((ptr >> sb->sv_ind_per_block_bits) & sb->sv_ind_per_block_1);
+get_indirect:
+ bh = GET_INDIRECT_DATABLOCK(ptr & sb->sv_ind_per_block_1);
+
+#undef GET_INODE_DATABLOCK
+#undef GET_INODE_PTR
+#undef GET_INDIRECT_DATABLOCK
+#undef GET_INDIRECT_PTR
out:
- *err = 0;
- return phys_block;
-}
-
-struct buffer_head *sysv_getblk (struct inode *inode, unsigned int block, int create)
-{
- struct buffer_head *tmp = NULL;
- int phys_block;
- int err, created;
-
- phys_block = sysv_getblk_block(inode, block, create, &err, &created);
- if (phys_block) {
- tmp = getblk(inode->i_dev, phys_block, BLOCK_SIZE);
- if (created) {
- memset(tmp->b_data, 0, BLOCK_SIZE);
- mark_buffer_uptodate(tmp, 1);
- mark_buffer_dirty(tmp, 1);
+ 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:
+ printk("sysv_getblk: block < 0\n");
+ goto abort;
+
+abort_too_big:
+ printk("sysv_getblk: block > big\n");
+ goto abort;
+}
+
+struct buffer_head *sysv_getblk(struct inode *inode, unsigned int block, int create)
+{
+ struct buffer_head dummy;
+ int error;
+
+ dummy.b_state = 0;
+ dummy.b_blocknr = -1000;
+ error = sysv_get_block(inode, block, &dummy, create);
+ if (!error && buffer_mapped(&dummy)) {
+ struct buffer_head *bh;
+ bh = getblk(dummy.b_dev, dummy.b_blocknr, BLOCK_SIZE);
+ if (buffer_new(&dummy)) {
+ memset(bh->b_data, 0, BLOCK_SIZE);
+ mark_buffer_uptodate(bh, 1);
+ mark_buffer_dirty(bh, 1);
}
+ return bh;
}
- return tmp;
+ return NULL;
}
-struct buffer_head * sysv_file_bread(struct inode * inode, int block, int create)
+struct buffer_head *sysv_file_bread(struct inode *inode, int block, int create)
{
- struct buffer_head * bh;
+ struct buffer_head *bh;
- bh = sysv_getblk(inode,block,create);
+ bh = sysv_getblk(inode, block, create);
if (!bh || buffer_uptodate(bh))
return bh;
ll_rw_block(READ, 1, &bh);
@@ -903,7 +998,7 @@
*(unsigned short *)(p+1) = (unsigned short) val;
}
-void sysv_read_inode(struct inode * inode)
+static void sysv_read_inode(struct inode *inode)
{
struct super_block * sb = inode->i_sb;
struct buffer_head * bh;
@@ -971,7 +1066,7 @@
}
/* To avoid inconsistencies between inodes in memory and inodes on disk. */
-int sysv_notify_change(struct dentry *dentry, struct iattr *attr)
+static int sysv_notify_change(struct dentry *dentry, struct iattr *attr)
{
struct inode *inode = dentry->d_inode;
int error;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)