patch-2.1.9 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: 727
- Date:
Sun Nov 10 14:05:48 1996
- Orig file:
v2.1.8/linux/fs/affs/file.c
- Orig date:
Tue Oct 29 19:58:19 1996
diff -u --recursive --new-file v2.1.8/linux/fs/affs/file.c linux/fs/affs/file.c
@@ -19,6 +19,7 @@
#include <linux/fcntl.h>
#include <linux/kernel.h>
#include <linux/errno.h>
+#include <linux/malloc.h>
#include <linux/stat.h>
#include <linux/locks.h>
#include <linux/dirent.h>
@@ -30,9 +31,17 @@
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
-static int affs_file_read_ofs(struct inode *inode, struct file *filp, char *buf, int count);
-static int affs_file_write(struct inode *inode, struct file *filp, const char *buf, int count);
-static int affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf, int count);
+#if PAGE_SIZE < 4096
+#error PAGE_SIZE must be at least 4096
+#endif
+
+static long affs_file_read_ofs(struct inode *inode, struct file *filp, char *buf,
+ unsigned long count);
+static long affs_file_write(struct inode *inode, struct file *filp, const char *buf,
+ unsigned long count);
+static long affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf,
+ unsigned long count);
+static int affs_open_file(struct inode *inode, struct file *filp);
static void affs_release_file(struct inode *inode, struct file *filp);
static struct file_operations affs_file_operations = {
@@ -43,7 +52,7 @@
NULL, /* select - default */
NULL, /* ioctl - default */
generic_file_mmap, /* mmap */
- NULL, /* no special open is needed */
+ affs_open_file, /* special open is needed */
affs_release_file, /* release */
file_fsync /* brute force, but works */
};
@@ -77,7 +86,7 @@
NULL, /* select - default */
NULL, /* ioctl - default */
NULL, /* mmap */
- NULL, /* no special open is needed */
+ affs_open_file, /* special open is needed */
affs_release_file, /* release */
file_fsync /* brute force, but works */
};
@@ -103,12 +112,133 @@
NULL /* smap */
};
+#define AFFS_ISINDEX(x) ((x < 129) || \
+ (x < 512 && (x & 1) == 0) || \
+ (x < 1024 && (x & 3) == 0) || \
+ (x < 2048 && (x & 15) == 0) || \
+ (x < 4096 && (x & 63) == 0) || \
+ (x < 20480 && (x & 255) == 0) || \
+ (x < 36864 && (x & 511) == 0))
+
+/* The keys of the extension blocks are stored in a 512-entry
+ * deep cache. In order to save memory, not every key of later
+ * extension blocks is stored - the larger the file gets, the
+ * bigger the holes inbetween.
+ */
+
+static int
+seqnum_to_index(int seqnum)
+{
+ /* All of the first 127 keys are stored */
+ if (seqnum < 128)
+ return seqnum;
+ seqnum -= 128;
+
+ /* Of the next 384 keys, every 2nd is kept */
+ if (seqnum < (192 * 2))
+ return 128 + (seqnum >> 1);
+ seqnum -= 192 * 2;
+
+ /* Every 4th of the next 512 */
+ if (seqnum < (128 * 4))
+ return 128 + 192 + (seqnum >> 2);
+ seqnum -= 128 * 4;
+
+ /* Every 16th of the next 1024 */
+ if (seqnum < (64 * 16))
+ return 128 + 192 + 128 + (seqnum >> 4);
+ seqnum -= 64 * 16;
+
+ /* Every 64th of the next 2048 */
+ if (seqnum < (32 * 64))
+ return 128 + 192 + 128 + 64 + (seqnum >> 6);
+ seqnum -= 32 * 64;
+
+ /* Every 256th of the next 16384 */
+ if (seqnum < (64 * 256))
+ return 128 + 192 + 128 + 64 + 32 + (seqnum >> 8);
+ seqnum -= 64 * 256;
+
+ /* Every 512th upto 36479 (1.3 GB with 512 byte blocks).
+ * Seeking to positions behind this will get slower
+ * than dead snails nailed to the ground. But if
+ * someone uses files that large with 512-byte blocks,
+ * he or she deserves no better.
+ */
+
+ if (seqnum > (31 * 512))
+ seqnum = 31 * 512;
+ return 128 + 192 + 128 + 64 + 32 + 64 + (seqnum >> 9);
+}
+
+/* Now the other way round: Calculate the sequence
+ * number of a extension block of a key at the
+ * given index in the cache.
+ */
+
+static int
+index_to_seqnum(int index)
+{
+ if (index < 128)
+ return index;
+ index -= 128;
+ if (index < 192)
+ return 128 + (index << 1);
+ index -= 192;
+ if (index < 128)
+ return 128 + 192 * 2 + (index << 2);
+ index -= 128;
+ if (index < 64)
+ return 128 + 192 * 2 + 128 * 4 + (index << 4);
+ index -= 64;
+ if (index < 32)
+ return 128 + 192 * 2 + 128 * 4 + 64 * 16 + (index << 6);
+ index -= 32;
+ if (index < 64)
+ return 128 + 192 * 2 + 128 * 4 + 64 * 16 + 32 * 64 + (index << 8);
+ index -= 64;
+ return 128 + 192 * 2 + 128 * 4 + 64 * 16 + 32 * 64 + 64 * 256 + (index << 9);
+}
+
+static int __inline__
+calc_key(struct inode *inode, int *ext)
+{
+ int index;
+ struct key_cache *kc;
+
+ for (index = 0; index < 4; index++) {
+ kc = &inode->u.affs_i.i_ec->kc[index];
+ if (*ext == kc->kc_this_seq) {
+ return kc->kc_this_key;
+ } else if (*ext == kc->kc_this_seq + 1) {
+ if (kc->kc_next_key)
+ return kc->kc_next_key;
+ else {
+ (*ext)--;
+ return kc->kc_this_key;
+ }
+ }
+ }
+ index = seqnum_to_index(*ext);
+ if (index > inode->u.affs_i.i_ec->max_ext)
+ index = inode->u.affs_i.i_ec->max_ext;
+ *ext = index_to_seqnum(index);
+ return inode->u.affs_i.i_ec->ec[index];
+}
+
int
affs_bmap(struct inode *inode, int block)
{
struct buffer_head *bh;
- int ext, key;
+ int ext, key, nkey;
int ptype, stype;
+ int index;
+ int keycount;
+ struct key_cache *kc;
+ struct key_cache *tkc;
+ struct timeval tv;
+ __s32 *keyp;
+ int i;
pr_debug("AFFS: bmap(%lu,%d)\n",inode->i_ino,block);
@@ -116,246 +246,197 @@
printk("affs_bmap: block < 0\n");
return 0;
}
-
- /* If this is a hard link, quietly exchange the inode with the original */
-
- key = inode->u.affs_i.i_original ? inode->u.affs_i.i_original : inode->i_ino;
-
- ext = block / AFFS_I2HSIZE(inode);
- 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);
+ if (!inode->u.affs_i.i_ec) {
+ printk("affs_bmap(): No ext_cache!?\n");
+ return 0;
}
+ /* Try to find the requested key in the cache.
+ * In order to speed this up as much as possible,
+ * the cache line lookup is done in a seperate
+ * step.
+ */
+
+ for (i = 0; i < 4; i++) {
+ tkc = &inode->u.affs_i.i_ec->kc[i];
+ /* Look in any cache if the key is there */
+ if (block <= tkc->kc_last && block >= tkc->kc_first) {
+ return tkc->kc_keys[block - tkc->kc_first];
+ }
+ }
+ kc = NULL;
+ tv = xtime;
+ for (i = 0; i < 4; i++) {
+ tkc = &inode->u.affs_i.i_ec->kc[i];
+ if (tkc->kc_lru_time.tv_sec > tv.tv_sec)
+ continue;
+ if (tkc->kc_lru_time.tv_sec < tv.tv_sec ||
+ tkc->kc_lru_time.tv_usec < tv.tv_usec) {
+ kc = tkc;
+ tv = tkc->kc_lru_time;
+ }
+ }
+ if (!kc) /* Really shouldn't happen */
+ kc = tkc;
+ kc->kc_lru_time = xtime;
+ keyp = kc->kc_keys;
+ kc->kc_first = block;
+ kc->kc_last = -1;
+ keycount = AFFS_KCSIZE;
+
+ /* Calculate sequence number of the extension block where the
+ * number of the requested block is stored. 0 means it's in
+ * the file header.
+ */
+
+ ext = block / AFFS_I2HSIZE(inode);
+ key = calc_key(inode,&ext);
+ block -= ext * AFFS_I2HSIZE(inode);
+
for (;;) {
bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
if (!bh)
return 0;
- if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype) ||
- (ptype != T_SHORT && ptype != T_LIST) || stype != ST_FILE) {
+ index = seqnum_to_index(ext);
+ if (index > inode->u.affs_i.i_ec->max_ext &&
+ (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype) ||
+ (ptype != T_SHORT && ptype != T_LIST) || stype != ST_FILE)) {
affs_brelse(bh);
return 0;
}
- if (block < AFFS_I2HSIZE(inode))
- break;
- block -= AFFS_I2HSIZE(inode);
- key = htonl(FILE_END(bh->b_data,inode)->extension);
- affs_brelse(bh);
- if (ext < EXT_CACHE_SIZE - 1) {
- inode->u.affs_i.i_ext[ext] = key;
- inode->u.affs_i.i_max_ext = ++ext;
- }
- }
- key = AFFS_GET_HASHENTRY(bh->b_data,(AFFS_I2HSIZE(inode) - 1) - block);
- affs_brelse(bh);
- return key;
-}
-
-struct buffer_head *
-affs_getblock(struct inode *inode, int block)
-{
- struct buffer_head *bh;
- struct buffer_head *ebh;
- int key;
- int ext;
- int 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);
- 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;
- }
- }
-
- 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) {
- 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;
+ nkey = htonl(FILE_END(bh->b_data,inode)->extension);
+ if (block < AFFS_I2HSIZE(inode)) {
+ /* Fill cache as much as possible */
+ if (keycount) {
+ kc->kc_first = ext * AFFS_I2HSIZE(inode) + block;
+ keycount = keycount < AFFS_I2HSIZE(inode) - block ? keycount :
+ AFFS_I2HSIZE(inode) - block;
+ for (i = 0; i < keycount; i++)
+ kc->kc_keys[i] = htonl(AFFS_BLOCK(bh->b_data,inode,block + i));
+ kc->kc_last = kc->kc_first + i - 1;
}
- unlock_super(inode->i_sb);
- AFFS_BLOCK(bh->b_data,inode,j) = ntohl(key);
- 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)
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;
- }
- }
+ ext++;
+ if (index > inode->u.affs_i.i_ec->max_ext && AFFS_ISINDEX(ext)) {
+ inode->u.affs_i.i_ec->ec[index] = nkey;
+ inode->u.affs_i.i_ec->max_ext = index;
+ }
+ key = nkey;
+ }
+ kc->kc_this_key = key;
+ kc->kc_this_seq = ext;
+ kc->kc_next_key = nkey;
key = htonl(AFFS_BLOCK(bh->b_data,inode,block));
affs_brelse(bh);
- if (!key)
- return NULL;
-
- return affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
+ return key;
}
struct buffer_head *
-affs_getblock_ofs(struct inode *inode, int block, int *blk_key)
+affs_getblock(struct inode *inode, int block)
{
struct buffer_head *bh;
- struct buffer_head *pbh;
struct buffer_head *ebh;
- int key;
+ struct buffer_head *pbh;
+ struct key_cache *kc;
+ int key, nkey;
int ext;
- int cnt, j, pt;
+ int cf, j, pt;
+ int index;
+ int ofs;
- pr_debug("AFFS: getblock_ofs(%lu,%d)\n",inode->i_ino,block);
+ 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);
- 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;
- }
- }
+ /* Writers always use cache line 3. In almost all cases, files
+ * will be written by only one process at the same time, and
+ * they also will be written in strict sequential order. Thus
+ * there is not much sense in looking whether the key of the
+ * requested block is available - it won't be there.
+ */
+ kc = &inode->u.affs_i.i_ec->kc[3];
+ ofs = inode->i_sb->u.affs_sb.s_flags & SF_OFS;
+ ext = block / AFFS_I2HSIZE(inode);
+ key = calc_key(inode,&ext);
+ block -= ext * AFFS_I2HSIZE(inode);
+ pt = ext ? T_LIST : T_SHORT;
+ pbh = NULL;
- 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) {
+ if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&cf,&j) ||
+ cf != 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);
+ j = htonl(((struct file_front *)bh->b_data)->block_count);
+ cf = 0;
while (j < AFFS_I2HSIZE(inode) && j <= block) {
- if (!pbh && inode->u.affs_i.i_lastblock >= 0) {
+ if (ofs && !pbh && inode->u.affs_i.i_lastblock >= 0) {
if (j > 0)
pbh = affs_bread(inode->i_dev,ntohl(AFFS_BLOCK(bh->b_data,inode,j - 1)),
AFFS_I2BSIZE(inode));
else
- pbh = affs_getblock_ofs(inode,inode->u.affs_i.i_lastblock,&key);
+ pbh = affs_getblock(inode,inode->u.affs_i.i_lastblock);
if (!pbh) {
printk("AFFS: getblock(): cannot get last block in file\n");
break;
}
}
- key = affs_new_data(inode);
- if (!key)
+ nkey = affs_new_data(inode);
+ if (!nkey)
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);
+ affs_free_block(inode->i_sb,nkey);
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);
- if (pbh) {
- DATA_FRONT(pbh)->data_size = ntohl(AFFS_I2BSIZE(inode) - 24);
- DATA_FRONT(pbh)->next_data = ntohl(key);
- affs_fix_checksum(AFFS_I2BSIZE(inode),pbh->b_data,5);
- mark_buffer_dirty(pbh,0);
- mark_buffer_dirty(ebh,0);
- affs_brelse(pbh);
+ AFFS_BLOCK(bh->b_data,inode,j) = ntohl(nkey);
+ if (ofs) {
+ ebh = affs_bread(inode->i_dev,nkey,AFFS_I2BSIZE(inode));
+ if (!ebh) {
+ printk("AFFS: getblock(): cannot get block %d\n",nkey);
+ affs_free_block(inode->i_sb,nkey);
+ 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);
+ if (pbh) {
+ DATA_FRONT(pbh)->data_size = ntohl(AFFS_I2BSIZE(inode) - 24);
+ DATA_FRONT(pbh)->next_data = ntohl(nkey);
+ affs_fix_checksum(AFFS_I2BSIZE(inode),pbh->b_data,5);
+ mark_buffer_dirty(pbh,0);
+ mark_buffer_dirty(ebh,0);
+ affs_brelse(pbh);
+ }
+ pbh = ebh;
}
- pbh = ebh;
j++;
+ cf = 1;
}
- if (pt == T_SHORT)
- ((struct file_front *)bh->b_data)->first_data =
+ if (cf) {
+ 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);
+ ((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)
@@ -393,17 +474,21 @@
}
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;
+ ext++;
+ if ((index = seqnum_to_index(ext)) > inode->u.affs_i.i_ec->max_ext &&
+ AFFS_ISINDEX(ext) && inode->u.affs_i.i_ec) {
+ inode->u.affs_i.i_ec->ec[index] = key;
+ inode->u.affs_i.i_ec->max_ext = index;
}
}
+ kc->kc_this_key = key;
+ kc->kc_this_seq = ext;
+ kc->kc_next_key = htonl(FILE_END(bh->b_data,inode)->extension);
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));
}
@@ -411,8 +496,8 @@
* You cannot directly read affs directories.
*/
-static int
-affs_file_read_ofs(struct inode *inode, struct file *filp, char *buf, int count)
+static long
+affs_file_read_ofs(struct inode *inode, struct file *filp, char *buf, unsigned long count)
{
char *start;
int left, offset, size, sector;
@@ -458,8 +543,8 @@
return buf - start;
}
-static int
-affs_file_write(struct inode *inode, struct file *filp, const char *buf, int count)
+static long
+affs_file_write(struct inode *inode, struct file *filp, const char *buf, unsigned long count)
{
off_t pos;
int written;
@@ -537,13 +622,12 @@
return written;
}
-static int
-affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf, int count)
+static long
+affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf, unsigned long count)
{
off_t pos;
int written;
int c;
- int key;
int blocksize;
struct buffer_head *bh;
struct inode *ino;
@@ -580,7 +664,7 @@
blocksize = AFFS_I2BSIZE(inode) - 24;
written = 0;
while (written < count) {
- bh = affs_getblock_ofs(inode,pos / blocksize,&key);
+ bh = affs_getblock(inode,pos / blocksize);
if (!bh) {
if (!written)
written = -ENOSPC;
@@ -654,15 +738,12 @@
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) {
- if (inode->i_sb->u.affs_sb.s_flags & SF_OFS)
- bh = affs_getblock_ofs(inode,first - 1,&ekey);
- else
bh = affs_getblock(inode,first - 1);
while (inode->u.affs_i.i_pa_cnt) { /* Free any preallocated blocks */
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_next &= AFFS_MAX_PREALLOC - 1;
inode->u.affs_i.i_pa_cnt--;
}
if (inode->u.affs_i.i_zone) {
@@ -755,10 +836,53 @@
ekey = key;
}
inode->u.affs_i.i_lastblock = ((inode->i_size + blocksize - 1) / blocksize) - 1;
- inode->u.affs_i.i_max_ext = 0;
+
+ /* Invalidate cache */
+ if (inode->u.affs_i.i_ec) {
+ inode->u.affs_i.i_ec->max_ext = 0;
+ for (key = 0; key < 3; key++) {
+ inode->u.affs_i.i_ec->kc[key].kc_next_key = 0;
+ inode->u.affs_i.i_ec->kc[key].kc_last = -1;
+ }
+ }
+
iput(ino);
}
+static int
+affs_open_file(struct inode *inode, struct file *filp)
+{
+ int error;
+ int key;
+ int i;
+
+ pr_debug("AFFS: open_file(ino=%lu)\n",inode->i_ino);
+
+ error = 0;
+ inode->u.affs_i.i_cache_users++;
+ lock_super(inode->i_sb);
+ if (!inode->u.affs_i.i_ec) {
+ inode->u.affs_i.i_ec = (struct ext_cache *)get_free_page(GFP_KERNEL);
+ if (!inode->u.affs_i.i_ec) {
+ printk("AFFS: cache allocation failed\n");
+ error = ENOMEM;
+ } else {
+ /* We only have to initialize non-zero values.
+ * get_free_page() zeroed the page already.
+ */
+ key = inode->u.affs_i.i_original ? inode->u.affs_i.i_original : inode->i_ino;
+ inode->u.affs_i.i_ec->ec[0] = key;
+ for (i = 0; i < 4; i++) {
+ inode->u.affs_i.i_ec->kc[i].kc_this_key = key;
+ inode->u.affs_i.i_ec->kc[i].kc_last = -1;
+ }
+ }
+ }
+ unlock_super(inode->i_sb);
+
+ return error;
+}
+
static void
affs_release_file(struct inode *inode, struct file *filp)
{
@@ -770,7 +894,7 @@
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_next &= AFFS_MAX_PREALLOC - 1;
inode->u.affs_i.i_pa_cnt--;
}
if (inode->u.affs_i.i_zone) {
@@ -781,4 +905,12 @@
unlock_super(inode->i_sb);
}
}
+ lock_super(inode->i_sb);
+ if (--inode->u.affs_i.i_cache_users == 0) {
+ if (inode->u.affs_i.i_ec) {
+ free_page((unsigned long)inode->u.affs_i.i_ec);
+ inode->u.affs_i.i_ec = NULL;
+ }
+ }
+ unlock_super(inode->i_sb);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov