patch-pre2.0.5 linux/fs/affs/file.c
Next file: linux/fs/affs/inode.c
Previous file: linux/fs/affs/dir.c
Back to the patch index
Back to the overall index
- Lines: 441
- Date:
Thu May 16 09:05:11 1996
- Orig file:
pre2.0.4/linux/fs/affs/file.c
- Orig date:
Tue May 7 16:22:35 1996
diff -u --recursive --new-file pre2.0.4/linux/fs/affs/file.c linux/fs/affs/file.c
@@ -1,7 +1,7 @@
/*
* linux/fs/affs/file.c
*
- * (c) 1996 Hans-Joachim Widmaier - Rewritten
+ * (c) 1996 Hans-Joachim Widmaier - rewritten
*
* (C) 1993 Ray Burr - Modified for Amiga FFS filesystem.
*
@@ -78,7 +78,7 @@
NULL, /* ioctl - default */
NULL, /* mmap */
NULL, /* no special open is needed */
- NULL, /* release */
+ affs_release_file, /* release */
file_fsync /* brute force, but works */
};
@@ -98,7 +98,7 @@
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
- affs_truncate_ofs, /* truncate */
+ affs_truncate, /* truncate */
NULL, /* permission */
NULL /* smap */
};
@@ -262,6 +262,145 @@
return affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
}
+struct buffer_head *
+affs_getblock_ofs(struct inode *inode, LONG block, LONG *blk_key)
+{
+ struct buffer_head *bh;
+ struct buffer_head *pbh;
+ struct buffer_head *ebh;
+ LONG key;
+ LONG ext;
+ LONG cnt, j, pt;
+
+ pr_debug("AFFS: getblock(%lu,%d)\n",inode->i_ino,block);
+
+ if (block < 0)
+ return NULL;
+ key = inode->i_ino;
+ pt = T_SHORT;
+
+ ext = block / (AFFS_I2HSIZE(inode) - 24);
+ if (ext) {
+ if (ext > inode->u.affs_i.i_max_ext)
+ ext = inode->u.affs_i.i_max_ext;
+ if (ext) {
+ key = inode->u.affs_i.i_ext[ext - 1];
+ block -= ext * AFFS_I2HSIZE(inode);
+ pt = T_LIST;
+ }
+ }
+
+ pbh = NULL;
+ for (;;) {
+ bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
+ if (!bh)
+ return NULL;
+ if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&cnt,&j) ||
+ cnt != pt || j != ST_FILE) {
+ printk("AFFS: getblock(): inode %d is not a valid %s\n",key,
+ pt == T_SHORT ? "file header" : "extension block");
+ affs_brelse(bh);
+ return NULL;
+ }
+ j = htonl(((struct file_front *)bh->b_data)->block_count);
+ while (j < AFFS_I2HSIZE(inode) && j <= block) {
+ if (!pbh && inode->u.affs_i.i_lastblock >= 0) {
+ pbh = affs_getblock_ofs(inode,inode->u.affs_i.i_lastblock,&key);
+ if (!pbh) {
+ printk("AFFS: getblock(): cannot get last block in file\n");
+ break;
+ }
+ }
+ key = affs_new_data(inode);
+ if (!key)
+ break;
+ lock_super(inode->i_sb);
+ if (AFFS_BLOCK(bh->b_data,inode,j)) {
+ unlock_super(inode->i_sb);
+ printk("AFFS: getblock(): block already allocated\n");
+ affs_free_block(inode->i_sb,key);
+ j++;
+ continue;
+ }
+ AFFS_BLOCK(bh->b_data,inode,j) = ntohl(key);
+ unlock_super(inode->i_sb);
+ ebh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
+ if (!ebh) {
+ printk("AFFS: getblock(): cannot get block %d\n",key);
+ affs_free_block(inode->i_sb,key);
+ AFFS_BLOCK(bh->b_data,inode,j) = 0;
+ break;
+ }
+ inode->u.affs_i.i_lastblock++;
+ DATA_FRONT(ebh)->primary_type = ntohl(T_DATA);
+ DATA_FRONT(ebh)->header_key = ntohl(inode->i_ino);
+ DATA_FRONT(ebh)->sequence_number = ntohl(inode->u.affs_i.i_lastblock + 1);
+ DATA_FRONT(pbh)->data_size = ntohl(AFFS_I2HSIZE(inode) - 24);
+ DATA_FRONT(pbh)->next_data = ntohl(key);
+ affs_fix_checksum(AFFS_I2HSIZE(inode),pbh->b_data,5);
+ mark_buffer_dirty(pbh,0);
+ mark_buffer_dirty(ebh,0);
+ affs_brelse(pbh);
+ pbh = ebh;
+ j++;
+ }
+ if (pt == T_SHORT)
+ ((struct file_front *)bh->b_data)->first_data =
+ AFFS_BLOCK(bh->b_data,inode,0);
+ ((struct file_front *)bh->b_data)->block_count = ntohl(j);
+ affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
+ mark_buffer_dirty(bh,1);
+
+ if (block < j) {
+ if (pbh)
+ affs_brelse(pbh);
+ break;
+ }
+ if (j < AFFS_I2HSIZE(inode)) {
+ affs_brelse(bh);
+ return NULL;
+ }
+
+ block -= AFFS_I2HSIZE(inode);
+ key = htonl(FILE_END(bh->b_data,inode)->extension);
+ if (!key) {
+ key = affs_new_header(inode);
+ if (!key) {
+ affs_brelse(bh);
+ return NULL;
+ }
+ ebh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
+ if (!ebh) {
+ affs_free_block(inode->i_sb,key);
+ return NULL;
+ }
+ ((struct file_front *)ebh->b_data)->primary_type = ntohl(T_LIST);
+ ((struct file_front *)ebh->b_data)->own_key = ntohl(key);
+ FILE_END(ebh->b_data,inode)->secondary_type = ntohl(ST_FILE);
+ FILE_END(ebh->b_data,inode)->parent = ntohl(inode->i_ino);
+ affs_fix_checksum(AFFS_I2BSIZE(inode),ebh->b_data,5);
+ FILE_END(bh->b_data,inode)->extension = ntohl(key);
+ affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
+ mark_buffer_dirty(bh,1);
+ affs_brelse(bh);
+ bh = ebh;
+ }
+ affs_brelse(bh);
+ pt = T_LIST;
+ if (ext < EXT_CACHE_SIZE - 1) {
+ inode->u.affs_i.i_ext[ext] = key;
+ inode->u.affs_i.i_max_ext = ++ext;
+ }
+ }
+ key = htonl(AFFS_BLOCK(bh->b_data,inode,block));
+ affs_brelse(bh);
+ if (!key)
+ return NULL;
+ *blk_key = key;
+
+ return affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
+}
+
/* This could be made static, regardless of what the former comment said.
* You cannot directly read affs directories.
*/
@@ -395,101 +534,91 @@
static int
affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf, int count)
{
- pr_debug("AFFS: file_write_ofs(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino,
- (unsigned long)filp->f_pos,count);
-
- return -ENOSPC;
-}
-
-void
-affs_truncate(struct inode *inode)
-{
+ off_t pos;
+ int written;
+ int c;
+ int blocksize;
struct buffer_head *bh;
struct inode *ino;
- LONG first;
- LONG block;
- LONG key;
- LONG *keyp;
- LONG ekey;
- LONG ptype, stype;
- int freethis;
- int ext;
+ char *p;
- pr_debug("AFFS: file_truncate(inode=%ld,size=%lu)\n",inode->i_ino,inode->i_size);
+ pr_debug("AFFS: file_write_ofs(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino,
+ (unsigned long)filp->f_pos,count);
+ if (!inode) {
+ printk("AFFS: file_write(): inode=NULL\n");
+ return -EINVAL;
+ }
ino = NULL;
if (inode->u.affs_i.i_original) {
ino = iget(inode->i_sb,inode->u.affs_i.i_original);
if (!ino) {
- printk("AFFS: truncate(): cannot follow link from %lu to %u\n",
+ printk("AFFS: could not follow link from inode %lu to %d\n",
inode->i_ino,inode->u.affs_i.i_original);
- return;
+ return -EINVAL;
}
inode = ino;
}
- first = (inode->i_size + AFFS_I2BSIZE(inode) - 1) / AFFS_I2BSIZE(inode);
- ekey = inode->i_ino;
- ext = 0;
+ if (!S_ISREG(inode->i_mode)) {
+ printk("AFFS: file_write(): mode=%07o\n",inode->i_mode);
+ iput(inode);
+ return -EINVAL;
+ }
+ if (filp->f_flags & O_APPEND)
+ pos = inode->i_size;
+ else
+ pos = filp->f_pos;
- while (ekey) {
- if (!(bh = affs_bread(inode->i_dev,ekey,AFFS_I2BSIZE(inode)))) {
- printk("AFFS: truncate(): Can't read block %d\n",ekey);
- break;
- }
- ptype = htonl(((struct file_front *)bh->b_data)->primary_type);
- stype = htonl(FILE_END(bh->b_data,inode)->secondary_type);
- if (ekey == inode->i_ino && ptype == T_SHORT && stype == ST_LINKFILE &&
- LINK_END(bh->b_data,inode)->original == 0) {
- pr_debug("AFFS: truncate(): dumping link\n");
- affs_brelse(bh);
- break;
- }
- if (stype != ST_FILE || (ptype != T_SHORT && ptype != T_LIST)) {
- printk("AFFS: truncate(): bad block (ptype=%d, stype=%d)\n",
- ptype,stype);
- affs_brelse(bh);
+ bh = NULL;
+ blocksize = AFFS_I2BSIZE(inode) - 24;
+ written = 0;
+ while (written < count) {
+ bh = affs_getblock(inode,pos / blocksize);
+ if (!bh) {
+ if (!written)
+ written = -ENOSPC;
break;
}
- /* Do not throw away file header */
- freethis = first == 0 && ekey != inode->i_ino;
- for ( block = first; block < AFFS_I2HSIZE(inode); block++) {
- keyp = &AFFS_BLOCK(bh->b_data,inode,block);
- key = htonl(*keyp);
- if (key) {
- *keyp = 0;
- affs_free_block(inode->i_sb,key);
- } else {
- block = AFFS_I2HSIZE(inode);
+ c = blocksize - (pos % blocksize);
+ if (c > count - written)
+ c = count - written;
+ if (c != blocksize && !buffer_uptodate(bh)) {
+ ll_rw_block(READ,1,&bh);
+ wait_on_buffer(bh);
+ if (!buffer_uptodate(bh)) {
+ affs_brelse(bh);
+ if (!written)
+ written = -EIO;
break;
}
}
- keyp = &GET_END_PTR(struct file_end,bh->b_data,AFFS_I2BSIZE(inode))->extension;
- key = htonl(*keyp);
- if (first <= AFFS_I2HSIZE(inode)) {
- ((struct file_front *)bh->b_data)->block_count = htonl(first);
- first = 0;
- *keyp = 0;
- } else {
- first -= AFFS_I2HSIZE(inode);
- }
- if (freethis) { /* Don't bother fixing checksum */
- affs_brelse(bh);
- affs_free_block(inode->i_sb,ekey);
- } else {
- affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
- mark_buffer_dirty(bh,1);
- affs_brelse(bh);
- }
- ekey = key;
+ p = (pos % blocksize) + bh->b_data + 24;
+ memcpy_fromfs(p,buf,c);
+ update_vm_cache(inode,pos,p,c);
+
+ pos += c;
+ buf += c;
+ written += c;
+ DATA_FRONT(bh)->data_size = ntohl(htonl(DATA_FRONT(bh)->data_size) + c);
+ affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
+ mark_buffer_uptodate(bh,1);
+ mark_buffer_dirty(bh,0);
+ affs_brelse(bh);
}
- inode->u.affs_i.i_max_ext = 0; /* invalidate cache */
+ if (pos > inode->i_size)
+ inode->i_size = pos;
+ filp->f_pos = pos;
+ inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_dirt = 1;
iput(ino);
+ return written;
}
void
-affs_truncate_ofs(struct inode *inode)
+affs_truncate(struct inode *inode)
{
struct buffer_head *bh;
+ struct buffer_head *ebh;
struct inode *ino;
LONG first;
LONG block;
@@ -499,8 +628,10 @@
LONG ptype, stype;
int freethis;
int blocksize;
+ int rem;
+ int ext;
- pr_debug("AFFS: file_truncate_ofs(inode=%ld,size=%lu)\n",inode->i_ino,inode->i_size);
+ pr_debug("AFFS: file_truncate(inode=%ld,size=%lu)\n",inode->i_ino,inode->i_size);
ino = NULL;
if (inode->u.affs_i.i_original) {
@@ -512,9 +643,25 @@
}
inode = ino;
}
- blocksize = AFFS_I2BSIZE(inode) - 24;
+ blocksize = AFFS_I2BSIZE(inode) - ((inode->i_sb->u.affs_sb.s_flags & SF_OFS) ? 24 : 0);
first = (inode->i_size + blocksize - 1) / blocksize;
+ if (inode->u.affs_i.i_lastblock < first - 1) {
+ bh = affs_getblock(inode,first - 1);
+ if (!bh) {
+ printk("AFFS: truncate(): Cannot extend file\n");
+ inode->i_size = blocksize * (inode->u.affs_i.i_lastblock + 1);
+ } else if (inode->i_sb->u.affs_sb.s_flags & SF_OFS) {
+ rem = inode->i_size % blocksize;
+ DATA_FRONT(bh)->data_size = ntohl(rem ? rem : blocksize);
+ affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
+ mark_buffer_dirty(bh,0);
+ }
+ affs_brelse(bh);
+ iput(ino);
+ return;
+ }
ekey = inode->i_ino;
+ ext = 0;
while (ekey) {
if (!(bh = affs_bread(inode->i_dev,ekey,AFFS_I2BSIZE(inode)))) {
@@ -538,9 +685,8 @@
/* Do not throw away file header */
freethis = first == 0 && ekey != inode->i_ino;
for ( block = first; block < AFFS_I2HSIZE(inode); block++) {
- keyp = &((struct file_front *)bh->b_data)->
- blocks[AFFS_I2HSIZE(inode) - 1 - block];
- key = htonl(*keyp);
+ keyp = &AFFS_BLOCK(bh->b_data,inode,block);
+ key = htonl(*keyp);
if (key) {
*keyp = 0;
affs_free_block(inode->i_sb,key);
@@ -555,6 +701,21 @@
((struct file_front *)bh->b_data)->block_count = htonl(first);
first = 0;
*keyp = 0;
+ if ((inode->i_sb->u.affs_sb.s_flags & SF_OFS) && first > 0) {
+ block = htonl(AFFS_BLOCK(bh->b_data,inode,first - 1));
+ if ((ebh = affs_bread(inode->i_dev,block,AFFS_I2BSIZE(inode)))) {
+ if(!(affs_checksum_block(AFFS_I2BSIZE(inode),ebh->b_data,
+ &ptype,NULL))) {
+ rem = inode->i_size % blocksize;
+ rem = ntohl(rem ? blocksize : rem);
+ ((struct data_front *)ebh->b_data)->data_size = rem;
+ ((struct data_front *)ebh->b_data)->next_data = 0;
+ affs_fix_checksum(AFFS_I2BSIZE(inode),ebh->b_data,5);
+ mark_buffer_dirty(ebh,1);
+ }
+ affs_brelse(ebh);
+ }
+ }
} else {
first -= AFFS_I2HSIZE(inode);
}
@@ -568,19 +729,31 @@
}
ekey = key;
}
- inode->u.affs_i.i_max_ext = 0; /* invalidate cache */
+ inode->u.affs_i.i_lastblock = ((inode->i_size + blocksize - 1) / blocksize) - 1;
+ inode->u.affs_i.i_max_ext = 0;
iput(ino);
}
static void
affs_release_file(struct inode *inode, struct file *filp)
{
+ struct affs_zone *zone;
+
+ pr_debug("AFFS: release_file(ino=%lu)\n",inode->i_ino);
+
if (filp->f_mode & 2) { /* Free preallocated blocks */
while (inode->u.affs_i.i_pa_cnt) {
affs_free_block(inode->i_sb,
inode->u.affs_i.i_data[inode->u.affs_i.i_pa_next++]);
inode->u.affs_i.i_pa_next &= MAX_PREALLOC - 1;
inode->u.affs_i.i_pa_cnt--;
+ }
+ if (inode->u.affs_i.i_zone) {
+ lock_super(inode->i_sb);
+ zone = &inode->i_sb->u.affs_sb.s_zones[inode->u.affs_i.i_zone];
+ if (zone->z_ino == inode->i_ino)
+ zone->z_ino = 0;
+ unlock_super(inode->i_sb);
}
}
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this