home *** CD-ROM | disk | FTP | other *** search
- /*
- * linux/fs/minix/bitmap.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file README.legal in the main directory of this archive
- * for more details.
- */
-
- /*
- * Modified for 680x0 by Hamish Macdonald
- */
-
- /* bitmap.c contains the code that handles the inode and block bitmaps */
-
- #include <linux/sched.h>
- #include <linux/minix_fs.h>
- #include <linux/stat.h>
- #include <linux/kernel.h>
- #include <linux/string.h>
-
- #include <asm/bitops.h>
-
- #define clear_block(addr) (memset(addr,0,BLOCK_SIZE))
-
- static inline int
- find_first_zero (char *addr)
- {
- unsigned long res;
- char *p = addr;
- __asm__ __volatile__
- (" moveq #-1,d0\n\t"
- "1:"
- " cmpw %1@+,d0\n\t"
- " bne 2f\n\t"
- " subql #1,%0\n\t"
- " bne 1b\n\t"
- " bra 5f\n\t"
- "2:"
- " movew %1@-,d0\n\t"
- " notw d0\n\t"
- " movew d0,%0\n\t"
- " negw d0\n\t"
- " andw %0,d0\n\t"
- " bfffo d0{#16,#16},%0\n\t"
- "5:"
- : "=d" (res), "=a" (p)
- : "0" (8192 >> 4), "1" (addr)
- : "d0");
- return (p - addr) * 8 + 31 - res;
- }
-
- #ifdef __mc68000__
- #define BIT(bit) ((bit) ^ 15)
- #else
- #define BIT(bit) (bit)
- #endif
-
- static int nibblemap[] = { 4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0 };
-
- static unsigned long count_free(struct buffer_head *map[], unsigned numblocks)
- {
- unsigned i, j, sum = 0;
- struct buffer_head *bh;
-
- for (i=0; i < numblocks; i++) {
- if (!(bh=map[i]))
- return(0);
- for (j=0; j < BLOCK_SIZE; j++)
- sum += nibblemap[bh->b_data[j] & 0xf]
- + nibblemap[(bh->b_data[j]>>4)&0xf];
- }
- return(sum);
- }
-
- void minix_free_block(struct super_block * sb, int block)
- {
- struct buffer_head * bh;
- unsigned int bit,zone;
-
- if (!sb) {
- printk("trying to free block on nonexistent device\n");
- return;
- }
- if ((ulong)block < sb->u.minix_sb.s_firstdatazone ||
- (ulong)block >= sb->u.minix_sb.s_nzones) {
- printk("trying to free block not in datazone\n");
- return;
- }
- bh = get_hash_table(sb->s_dev,block,BLOCK_SIZE);
- if (bh)
- bh->b_dirt=0;
- brelse(bh);
- zone = block - sb->u.minix_sb.s_firstdatazone + 1;
- bit = zone & 8191;
- zone >>= 13;
- bh = sb->u.minix_sb.s_zmap[zone];
- if (!bh) {
- printk("minix_free_block: nonexistent bitmap buffer\n");
- return;
- }
- if (!clear_bit(BIT(bit),bh->b_data))
- printk("free_block (%04x:%d): bit already cleared\n",sb->s_dev,block);
- bh->b_dirt = 1;
- return;
- }
-
- int minix_new_block(struct super_block * sb)
- {
- struct buffer_head * bh;
- int i,j;
-
- if (!sb) {
- printk("trying to get new block from nonexistent device\n");
- return 0;
- }
- repeat:
- j = 8192;
- for (i=0 ; i<8 ; i++)
- if ((bh=sb->u.minix_sb.s_zmap[i]) != NULL)
- if ((j=find_first_zero(bh->b_data))<8192)
- break;
- if (i>=8 || !bh || j>=8192)
- return 0;
- if (set_bit(BIT(j),bh->b_data)) {
- printk("new_block: bit already set (%d)\n", j);
- goto repeat;
- }
- bh->b_dirt = 1;
- j += i*8192 + sb->u.minix_sb.s_firstdatazone-1;
- if ((ulong)j < sb->u.minix_sb.s_firstdatazone ||
- (ulong)j >= sb->u.minix_sb.s_nzones)
- return 0;
- if (!(bh = getblk(sb->s_dev,j,BLOCK_SIZE))) {
- printk("new_block: cannot get block\n");
- return 0;
- }
- clear_block(bh->b_data);
- bh->b_uptodate = 1;
- bh->b_dirt = 1;
- brelse(bh);
- return j;
- }
-
- unsigned long minix_count_free_blocks(struct super_block *sb)
- {
- return (count_free(sb->u.minix_sb.s_zmap,sb->u.minix_sb.s_zmap_blocks)
- << sb->u.minix_sb.s_log_zone_size);
- }
-
- void minix_free_inode(struct inode * inode)
- {
- struct buffer_head * bh;
- unsigned long ino;
-
- if (!inode)
- return;
- if (!inode->i_dev) {
- printk("free_inode: inode has no device\n");
- return;
- }
- if (inode->i_count != 1) {
- printk("free_inode: inode has count=%d\n",inode->i_count);
- return;
- }
- if (inode->i_nlink) {
- printk("free_inode: inode has nlink=%d\n",inode->i_nlink);
- return;
- }
- if (!inode->i_sb) {
- printk("free_inode: inode on nonexistent device\n");
- return;
- }
- if (inode->i_ino < 1 || inode->i_ino >= inode->i_sb->u.minix_sb.s_ninodes) {
- printk("free_inode: inode 0 or nonexistent inode\n");
- return;
- }
- ino = inode->i_ino;
- if (!(bh=inode->i_sb->u.minix_sb.s_imap[ino >> 13])) {
- printk("free_inode: nonexistent imap in superblock\n");
- return;
- }
- minix_clear_inode (inode);
- clear_inode(inode);
- if (!clear_bit(BIT(ino & 8191), bh->b_data))
- printk("free_inode: bit %lu already cleared.\n",ino);
- bh->b_dirt = 1;
- }
-
- struct inode * minix_new_inode(const struct inode * dir)
- {
- struct super_block * sb;
- struct inode * inode;
- struct buffer_head * bh;
- int i,j;
-
- if (!dir || !(inode = get_empty_inode()))
- return NULL;
- sb = dir->i_sb;
- inode->i_sb = sb;
- inode->i_flags = inode->i_sb->s_flags;
- j = 8192;
- for (i=0 ; i<8 ; i++)
- if ((bh = inode->i_sb->u.minix_sb.s_imap[i]) != NULL)
- if ((j=find_first_zero(bh->b_data))<8192)
- break;
- if (!bh || j >= 8192) {
- iput(inode);
- return NULL;
- }
- if (set_bit(BIT(j),bh->b_data)) { /* shouldn't happen */
- printk("new_inode: bit %u already set\n", j);
- iput(inode);
- return NULL;
- }
- bh->b_dirt = 1;
- j += i*8192;
- if (!j || (ulong)j >= inode->i_sb->u.minix_sb.s_ninodes) {
- iput(inode);
- return NULL;
- }
- inode->i_count = 1;
- inode->i_nlink = 1;
- inode->i_dev = sb->s_dev;
- inode->i_uid = current->euid;
- inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->egid;
- inode->i_dirt = 1;
- inode->i_ino = j;
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
- inode->i_op = NULL;
- inode->i_blocks = inode->i_blksize = 0;
- insert_inode_hash(inode);
- return inode;
- }
-
- unsigned long minix_count_free_inodes(struct super_block *sb)
- {
- return count_free(sb->u.minix_sb.s_imap,sb->u.minix_sb.s_imap_blocks);
- }
-