Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
This commit is contained in:
Linus Torvalds
2005-04-16 15:20:36 -07:00
commit 1da177e4c3
17291 changed files with 6718755 additions and 0 deletions
+7
View File
@@ -0,0 +1,7 @@
#
# Makefile for the Linux minix filesystem routines.
#
obj-$(CONFIG_MINIX_FS) += minix.o
minix-objs := bitmap.o itree_v1.o itree_v2.o namei.o inode.o file.o dir.o
+269
View File
@@ -0,0 +1,269 @@
/*
* linux/fs/minix/bitmap.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
* Modified for 680x0 by Hamish Macdonald
* Fixed for 680x0 by Andreas Schwab
*/
/* bitmap.c contains the code that handles the inode and block bitmaps */
#include "minix.h"
#include <linux/smp_lock.h>
#include <linux/buffer_head.h>
#include <linux/bitops.h>
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, __u32 numbits)
{
unsigned i, j, sum = 0;
struct buffer_head *bh;
for (i=0; i<numblocks-1; 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];
}
if (numblocks==0 || !(bh=map[numblocks-1]))
return(0);
i = ((numbits-(numblocks-1)*BLOCK_SIZE*8)/16)*2;
for (j=0; j<i; j++) {
sum += nibblemap[bh->b_data[j] & 0xf]
+ nibblemap[(bh->b_data[j]>>4) & 0xf];
}
i = numbits%16;
if (i!=0) {
i = *(__u16 *)(&bh->b_data[j]) | ~((1<<i) - 1);
sum += nibblemap[i & 0xf] + nibblemap[(i>>4) & 0xf];
sum += nibblemap[(i>>8) & 0xf] + nibblemap[(i>>12) & 0xf];
}
return(sum);
}
void minix_free_block(struct inode * inode, int block)
{
struct super_block * sb = inode->i_sb;
struct minix_sb_info * sbi = minix_sb(sb);
struct buffer_head * bh;
unsigned int bit,zone;
if (block < sbi->s_firstdatazone || block >= sbi->s_nzones) {
printk("trying to free block not in datazone\n");
return;
}
zone = block - sbi->s_firstdatazone + 1;
bit = zone & 8191;
zone >>= 13;
if (zone >= sbi->s_zmap_blocks) {
printk("minix_free_block: nonexistent bitmap buffer\n");
return;
}
bh = sbi->s_zmap[zone];
lock_kernel();
if (!minix_test_and_clear_bit(bit,bh->b_data))
printk("free_block (%s:%d): bit already cleared\n",
sb->s_id, block);
unlock_kernel();
mark_buffer_dirty(bh);
return;
}
int minix_new_block(struct inode * inode)
{
struct minix_sb_info *sbi = minix_sb(inode->i_sb);
int i;
for (i = 0; i < sbi->s_zmap_blocks; i++) {
struct buffer_head *bh = sbi->s_zmap[i];
int j;
lock_kernel();
if ((j = minix_find_first_zero_bit(bh->b_data, 8192)) < 8192) {
minix_set_bit(j,bh->b_data);
unlock_kernel();
mark_buffer_dirty(bh);
j += i*8192 + sbi->s_firstdatazone-1;
if (j < sbi->s_firstdatazone || j >= sbi->s_nzones)
break;
return j;
}
unlock_kernel();
}
return 0;
}
unsigned long minix_count_free_blocks(struct minix_sb_info *sbi)
{
return (count_free(sbi->s_zmap, sbi->s_zmap_blocks,
sbi->s_nzones - sbi->s_firstdatazone + 1)
<< sbi->s_log_zone_size);
}
struct minix_inode *
minix_V1_raw_inode(struct super_block *sb, ino_t ino, struct buffer_head **bh)
{
int block;
struct minix_sb_info *sbi = minix_sb(sb);
struct minix_inode *p;
if (!ino || ino > sbi->s_ninodes) {
printk("Bad inode number on dev %s: %ld is out of range\n",
sb->s_id, (long)ino);
return NULL;
}
ino--;
block = 2 + sbi->s_imap_blocks + sbi->s_zmap_blocks +
ino / MINIX_INODES_PER_BLOCK;
*bh = sb_bread(sb, block);
if (!*bh) {
printk("unable to read i-node block\n");
return NULL;
}
p = (void *)(*bh)->b_data;
return p + ino % MINIX_INODES_PER_BLOCK;
}
struct minix2_inode *
minix_V2_raw_inode(struct super_block *sb, ino_t ino, struct buffer_head **bh)
{
int block;
struct minix_sb_info *sbi = minix_sb(sb);
struct minix2_inode *p;
*bh = NULL;
if (!ino || ino > sbi->s_ninodes) {
printk("Bad inode number on dev %s: %ld is out of range\n",
sb->s_id, (long)ino);
return NULL;
}
ino--;
block = 2 + sbi->s_imap_blocks + sbi->s_zmap_blocks +
ino / MINIX2_INODES_PER_BLOCK;
*bh = sb_bread(sb, block);
if (!*bh) {
printk("unable to read i-node block\n");
return NULL;
}
p = (void *)(*bh)->b_data;
return p + ino % MINIX2_INODES_PER_BLOCK;
}
/* Clear the link count and mode of a deleted inode on disk. */
static void minix_clear_inode(struct inode *inode)
{
struct buffer_head *bh = NULL;
if (INODE_VERSION(inode) == MINIX_V1) {
struct minix_inode *raw_inode;
raw_inode = minix_V1_raw_inode(inode->i_sb, inode->i_ino, &bh);
if (raw_inode) {
raw_inode->i_nlinks = 0;
raw_inode->i_mode = 0;
}
} else {
struct minix2_inode *raw_inode;
raw_inode = minix_V2_raw_inode(inode->i_sb, inode->i_ino, &bh);
if (raw_inode) {
raw_inode->i_nlinks = 0;
raw_inode->i_mode = 0;
}
}
if (bh) {
mark_buffer_dirty(bh);
brelse (bh);
}
}
void minix_free_inode(struct inode * inode)
{
struct minix_sb_info *sbi = minix_sb(inode->i_sb);
struct buffer_head * bh;
unsigned long ino;
ino = inode->i_ino;
if (ino < 1 || ino > sbi->s_ninodes) {
printk("minix_free_inode: inode 0 or nonexistent inode\n");
goto out;
}
if ((ino >> 13) >= sbi->s_imap_blocks) {
printk("minix_free_inode: nonexistent imap in superblock\n");
goto out;
}
minix_clear_inode(inode); /* clear on-disk copy */
bh = sbi->s_imap[ino >> 13];
lock_kernel();
if (!minix_test_and_clear_bit(ino & 8191, bh->b_data))
printk("minix_free_inode: bit %lu already cleared.\n", ino);
unlock_kernel();
mark_buffer_dirty(bh);
out:
clear_inode(inode); /* clear in-memory copy */
}
struct inode * minix_new_inode(const struct inode * dir, int * error)
{
struct super_block *sb = dir->i_sb;
struct minix_sb_info *sbi = minix_sb(sb);
struct inode *inode = new_inode(sb);
struct buffer_head * bh;
int i,j;
if (!inode) {
*error = -ENOMEM;
return NULL;
}
j = 8192;
bh = NULL;
*error = -ENOSPC;
lock_kernel();
for (i = 0; i < sbi->s_imap_blocks; i++) {
bh = sbi->s_imap[i];
if ((j = minix_find_first_zero_bit(bh->b_data, 8192)) < 8192)
break;
}
if (!bh || j >= 8192) {
unlock_kernel();
iput(inode);
return NULL;
}
if (minix_test_and_set_bit(j,bh->b_data)) { /* shouldn't happen */
printk("new_inode: bit already set");
unlock_kernel();
iput(inode);
return NULL;
}
unlock_kernel();
mark_buffer_dirty(bh);
j += i*8192;
if (!j || j > sbi->s_ninodes) {
iput(inode);
return NULL;
}
inode->i_uid = current->fsuid;
inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
inode->i_ino = j;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
inode->i_blocks = inode->i_blksize = 0;
memset(&minix_i(inode)->u, 0, sizeof(minix_i(inode)->u));
insert_inode_hash(inode);
mark_inode_dirty(inode);
*error = 0;
return inode;
}
unsigned long minix_count_free_inodes(struct minix_sb_info *sbi)
{
return count_free(sbi->s_imap, sbi->s_imap_blocks, sbi->s_ninodes + 1);
}
+409
View File
@@ -0,0 +1,409 @@
/*
* linux/fs/minix/dir.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* minix directory handling functions
*/
#include "minix.h"
#include <linux/highmem.h>
#include <linux/smp_lock.h>
typedef struct minix_dir_entry minix_dirent;
static int minix_readdir(struct file *, void *, filldir_t);
struct file_operations minix_dir_operations = {
.read = generic_read_dir,
.readdir = minix_readdir,
.fsync = minix_sync_file,
};
static inline void dir_put_page(struct page *page)
{
kunmap(page);
page_cache_release(page);
}
/*
* Return the offset into page `page_nr' of the last valid
* byte in that page, plus one.
*/
static unsigned
minix_last_byte(struct inode *inode, unsigned long page_nr)
{
unsigned last_byte = PAGE_CACHE_SIZE;
if (page_nr == (inode->i_size >> PAGE_CACHE_SHIFT))
last_byte = inode->i_size & (PAGE_CACHE_SIZE - 1);
return last_byte;
}
static inline unsigned long dir_pages(struct inode *inode)
{
return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT;
}
static int dir_commit_chunk(struct page *page, unsigned from, unsigned to)
{
struct inode *dir = (struct inode *)page->mapping->host;
int err = 0;
page->mapping->a_ops->commit_write(NULL, page, from, to);
if (IS_DIRSYNC(dir))
err = write_one_page(page, 1);
else
unlock_page(page);
return err;
}
static struct page * dir_get_page(struct inode *dir, unsigned long n)
{
struct address_space *mapping = dir->i_mapping;
struct page *page = read_cache_page(mapping, n,
(filler_t*)mapping->a_ops->readpage, NULL);
if (!IS_ERR(page)) {
wait_on_page_locked(page);
kmap(page);
if (!PageUptodate(page))
goto fail;
}
return page;
fail:
dir_put_page(page);
return ERR_PTR(-EIO);
}
static inline void *minix_next_entry(void *de, struct minix_sb_info *sbi)
{
return (void*)((char*)de + sbi->s_dirsize);
}
static int minix_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
unsigned long pos = filp->f_pos;
struct inode *inode = filp->f_dentry->d_inode;
struct super_block *sb = inode->i_sb;
unsigned offset = pos & ~PAGE_CACHE_MASK;
unsigned long n = pos >> PAGE_CACHE_SHIFT;
unsigned long npages = dir_pages(inode);
struct minix_sb_info *sbi = minix_sb(sb);
unsigned chunk_size = sbi->s_dirsize;
lock_kernel();
pos = (pos + chunk_size-1) & ~(chunk_size-1);
if (pos >= inode->i_size)
goto done;
for ( ; n < npages; n++, offset = 0) {
char *p, *kaddr, *limit;
struct page *page = dir_get_page(inode, n);
if (IS_ERR(page))
continue;
kaddr = (char *)page_address(page);
p = kaddr+offset;
limit = kaddr + minix_last_byte(inode, n) - chunk_size;
for ( ; p <= limit ; p = minix_next_entry(p, sbi)) {
minix_dirent *de = (minix_dirent *)p;
if (de->inode) {
int over;
unsigned l = strnlen(de->name,sbi->s_namelen);
offset = p - kaddr;
over = filldir(dirent, de->name, l,
(n<<PAGE_CACHE_SHIFT) | offset,
de->inode, DT_UNKNOWN);
if (over) {
dir_put_page(page);
goto done;
}
}
}
dir_put_page(page);
}
done:
filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset;
unlock_kernel();
return 0;
}
static inline int namecompare(int len, int maxlen,
const char * name, const char * buffer)
{
if (len < maxlen && buffer[len])
return 0;
return !memcmp(name, buffer, len);
}
/*
* minix_find_entry()
*
* finds an entry in the specified directory with the wanted name. It
* returns the cache buffer in which the entry was found, and the entry
* itself (as a parameter - res_dir). It does NOT read the inode of the
* entry - you'll have to do that yourself if you want to.
*/
minix_dirent *minix_find_entry(struct dentry *dentry, struct page **res_page)
{
const char * name = dentry->d_name.name;
int namelen = dentry->d_name.len;
struct inode * dir = dentry->d_parent->d_inode;
struct super_block * sb = dir->i_sb;
struct minix_sb_info * sbi = minix_sb(sb);
unsigned long n;
unsigned long npages = dir_pages(dir);
struct page *page = NULL;
struct minix_dir_entry *de;
*res_page = NULL;
for (n = 0; n < npages; n++) {
char *kaddr;
page = dir_get_page(dir, n);
if (IS_ERR(page))
continue;
kaddr = (char*)page_address(page);
de = (struct minix_dir_entry *) kaddr;
kaddr += minix_last_byte(dir, n) - sbi->s_dirsize;
for ( ; (char *) de <= kaddr ; de = minix_next_entry(de,sbi)) {
if (!de->inode)
continue;
if (namecompare(namelen,sbi->s_namelen,name,de->name))
goto found;
}
dir_put_page(page);
}
return NULL;
found:
*res_page = page;
return de;
}
int minix_add_link(struct dentry *dentry, struct inode *inode)
{
struct inode *dir = dentry->d_parent->d_inode;
const char * name = dentry->d_name.name;
int namelen = dentry->d_name.len;
struct super_block * sb = dir->i_sb;
struct minix_sb_info * sbi = minix_sb(sb);
struct page *page = NULL;
struct minix_dir_entry * de;
unsigned long npages = dir_pages(dir);
unsigned long n;
char *kaddr;
unsigned from, to;
int err;
/*
* We take care of directory expansion in the same loop
* This code plays outside i_size, so it locks the page
* to protect that region.
*/
for (n = 0; n <= npages; n++) {
char *dir_end;
page = dir_get_page(dir, n);
err = PTR_ERR(page);
if (IS_ERR(page))
goto out;
lock_page(page);
kaddr = (char*)page_address(page);
dir_end = kaddr + minix_last_byte(dir, n);
de = (minix_dirent *)kaddr;
kaddr += PAGE_CACHE_SIZE - sbi->s_dirsize;
while ((char *)de <= kaddr) {
if ((char *)de == dir_end) {
/* We hit i_size */
de->inode = 0;
goto got_it;
}
if (!de->inode)
goto got_it;
err = -EEXIST;
if (namecompare(namelen,sbi->s_namelen,name,de->name))
goto out_unlock;
de = minix_next_entry(de, sbi);
}
unlock_page(page);
dir_put_page(page);
}
BUG();
return -EINVAL;
got_it:
from = (char*)de - (char*)page_address(page);
to = from + sbi->s_dirsize;
err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
if (err)
goto out_unlock;
memcpy (de->name, name, namelen);
memset (de->name + namelen, 0, sbi->s_dirsize - namelen - 2);
de->inode = inode->i_ino;
err = dir_commit_chunk(page, from, to);
dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
mark_inode_dirty(dir);
out_put:
dir_put_page(page);
out:
return err;
out_unlock:
unlock_page(page);
goto out_put;
}
int minix_delete_entry(struct minix_dir_entry *de, struct page *page)
{
struct address_space *mapping = page->mapping;
struct inode *inode = (struct inode*)mapping->host;
char *kaddr = page_address(page);
unsigned from = (char*)de - kaddr;
unsigned to = from + minix_sb(inode->i_sb)->s_dirsize;
int err;
lock_page(page);
err = mapping->a_ops->prepare_write(NULL, page, from, to);
if (err == 0) {
de->inode = 0;
err = dir_commit_chunk(page, from, to);
} else {
unlock_page(page);
}
dir_put_page(page);
inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
mark_inode_dirty(inode);
return err;
}
int minix_make_empty(struct inode *inode, struct inode *dir)
{
struct address_space *mapping = inode->i_mapping;
struct page *page = grab_cache_page(mapping, 0);
struct minix_sb_info * sbi = minix_sb(inode->i_sb);
struct minix_dir_entry * de;
char *kaddr;
int err;
if (!page)
return -ENOMEM;
err = mapping->a_ops->prepare_write(NULL, page, 0, 2 * sbi->s_dirsize);
if (err) {
unlock_page(page);
goto fail;
}
kaddr = kmap_atomic(page, KM_USER0);
memset(kaddr, 0, PAGE_CACHE_SIZE);
de = (struct minix_dir_entry *)kaddr;
de->inode = inode->i_ino;
strcpy(de->name,".");
de = minix_next_entry(de, sbi);
de->inode = dir->i_ino;
strcpy(de->name,"..");
kunmap_atomic(kaddr, KM_USER0);
err = dir_commit_chunk(page, 0, 2 * sbi->s_dirsize);
fail:
page_cache_release(page);
return err;
}
/*
* routine to check that the specified directory is empty (for rmdir)
*/
int minix_empty_dir(struct inode * inode)
{
struct page *page = NULL;
unsigned long i, npages = dir_pages(inode);
struct minix_sb_info *sbi = minix_sb(inode->i_sb);
for (i = 0; i < npages; i++) {
char *kaddr;
minix_dirent * de;
page = dir_get_page(inode, i);
if (IS_ERR(page))
continue;
kaddr = (char *)page_address(page);
de = (minix_dirent *)kaddr;
kaddr += minix_last_byte(inode, i) - sbi->s_dirsize;
while ((char *)de <= kaddr) {
if (de->inode != 0) {
/* check for . and .. */
if (de->name[0] != '.')
goto not_empty;
if (!de->name[1]) {
if (de->inode != inode->i_ino)
goto not_empty;
} else if (de->name[1] != '.')
goto not_empty;
else if (de->name[2])
goto not_empty;
}
de = minix_next_entry(de, sbi);
}
dir_put_page(page);
}
return 1;
not_empty:
dir_put_page(page);
return 0;
}
/* Releases the page */
void minix_set_link(struct minix_dir_entry *de, struct page *page,
struct inode *inode)
{
struct inode *dir = (struct inode*)page->mapping->host;
struct minix_sb_info *sbi = minix_sb(dir->i_sb);
unsigned from = (char *)de-(char*)page_address(page);
unsigned to = from + sbi->s_dirsize;
int err;
lock_page(page);
err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
if (err == 0) {
de->inode = inode->i_ino;
err = dir_commit_chunk(page, from, to);
} else {
unlock_page(page);
}
dir_put_page(page);
dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
mark_inode_dirty(dir);
}
struct minix_dir_entry * minix_dotdot (struct inode *dir, struct page **p)
{
struct page *page = dir_get_page(dir, 0);
struct minix_sb_info *sbi = minix_sb(dir->i_sb);
struct minix_dir_entry *de = NULL;
if (!IS_ERR(page)) {
de = minix_next_entry(page_address(page), sbi);
*p = page;
}
return de;
}
ino_t minix_inode_by_name(struct dentry *dentry)
{
struct page *page;
struct minix_dir_entry *de = minix_find_entry(dentry, &page);
ino_t res = 0;
if (de) {
res = de->inode;
dir_put_page(page);
}
return res;
}
+45
View File
@@ -0,0 +1,45 @@
/*
* linux/fs/minix/file.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* minix regular file handling primitives
*/
#include <linux/buffer_head.h> /* for fsync_inode_buffers() */
#include "minix.h"
/*
* We have mostly NULLs here: the current defaults are OK for
* the minix filesystem.
*/
int minix_sync_file(struct file *, struct dentry *, int);
struct file_operations minix_file_operations = {
.llseek = generic_file_llseek,
.read = generic_file_read,
.write = generic_file_write,
.mmap = generic_file_mmap,
.fsync = minix_sync_file,
.sendfile = generic_file_sendfile,
};
struct inode_operations minix_file_inode_operations = {
.truncate = minix_truncate,
.getattr = minix_getattr,
};
int minix_sync_file(struct file * file, struct dentry *dentry, int datasync)
{
struct inode *inode = dentry->d_inode;
int err;
err = sync_mapping_buffers(inode->i_mapping);
if (!(inode->i_state & I_DIRTY))
return err;
if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
return err;
err |= minix_sync_inode(inode);
return err ? -EIO : 0;
}
+598
View File
File diff suppressed because it is too large Load Diff
+362
View File
@@ -0,0 +1,362 @@
/* Generic part */
typedef struct {
block_t *p;
block_t key;
struct buffer_head *bh;
} Indirect;
static DEFINE_RWLOCK(pointers_lock);
static inline void add_chain(Indirect *p, struct buffer_head *bh, block_t *v)
{
p->key = *(p->p = v);
p->bh = bh;
}
static inline int verify_chain(Indirect *from, Indirect *to)
{
while (from <= to && from->key == *from->p)
from++;
return (from > to);
}
static inline block_t *block_end(struct buffer_head *bh)
{
return (block_t *)((char*)bh->b_data + BLOCK_SIZE);
}
static inline Indirect *get_branch(struct inode *inode,
int depth,
int *offsets,
Indirect chain[DEPTH],
int *err)
{
struct super_block *sb = inode->i_sb;
Indirect *p = chain;
struct buffer_head *bh;
*err = 0;
/* i_data is not going away, no lock needed */
add_chain (chain, NULL, i_data(inode) + *offsets);
if (!p->key)
goto no_block;
while (--depth) {
bh = sb_bread(sb, block_to_cpu(p->key));
if (!bh)
goto failure;
read_lock(&pointers_lock);
if (!verify_chain(chain, p))
goto changed;
add_chain(++p, bh, (block_t *)bh->b_data + *++offsets);
read_unlock(&pointers_lock);
if (!p->key)
goto no_block;
}
return NULL;
changed:
read_unlock(&pointers_lock);
brelse(bh);
*err = -EAGAIN;
goto no_block;
failure:
*err = -EIO;
no_block:
return p;
}
static int alloc_branch(struct inode *inode,
int num,
int *offsets,
Indirect *branch)
{
int n = 0;
int i;
int parent = minix_new_block(inode);
branch[0].key = cpu_to_block(parent);
if (parent) for (n = 1; n < num; n++) {
struct buffer_head *bh;
/* Allocate the next block */
int nr = minix_new_block(inode);
if (!nr)
break;
branch[n].key = cpu_to_block(nr);
bh = sb_getblk(inode->i_sb, parent);
lock_buffer(bh);
memset(bh->b_data, 0, BLOCK_SIZE);
branch[n].bh = bh;
branch[n].p = (block_t*) bh->b_data + offsets[n];
*branch[n].p = branch[n].key;
set_buffer_uptodate(bh);
unlock_buffer(bh);
mark_buffer_dirty_inode(bh, inode);
parent = nr;
}
if (n == num)
return 0;
/* Allocation failed, free what we already allocated */
for (i = 1; i < n; i++)
bforget(branch[i].bh);
for (i = 0; i < n; i++)
minix_free_block(inode, block_to_cpu(branch[i].key));
return -ENOSPC;
}
static inline int splice_branch(struct inode *inode,
Indirect chain[DEPTH],
Indirect *where,
int num)
{
int i;
write_lock(&pointers_lock);
/* Verify that place we are splicing to is still there and vacant */
if (!verify_chain(chain, where-1) || *where->p)
goto changed;
*where->p = where->key;
write_unlock(&pointers_lock);
/* We are done with atomic stuff, now do the rest of housekeeping */
inode->i_ctime = CURRENT_TIME_SEC;
/* had we spliced it onto indirect block? */
if (where->bh)
mark_buffer_dirty_inode(where->bh, inode);
mark_inode_dirty(inode);
return 0;
changed:
write_unlock(&pointers_lock);
for (i = 1; i < num; i++)
bforget(where[i].bh);
for (i = 0; i < num; i++)
minix_free_block(inode, block_to_cpu(where[i].key));
return -EAGAIN;
}
static inline int get_block(struct inode * inode, sector_t block,
struct buffer_head *bh, int create)
{
int err = -EIO;
int offsets[DEPTH];
Indirect chain[DEPTH];
Indirect *partial;
int left;
int depth = block_to_path(inode, block, offsets);
if (depth == 0)
goto out;
reread:
partial = get_branch(inode, depth, offsets, chain, &err);
/* Simplest case - block found, no allocation needed */
if (!partial) {
got_it:
map_bh(bh, inode->i_sb, block_to_cpu(chain[depth-1].key));
/* Clean up and exit */
partial = chain+depth-1; /* the whole chain */
goto cleanup;
}
/* Next simple case - plain lookup or failed read of indirect block */
if (!create || err == -EIO) {
cleanup:
while (partial > chain) {
brelse(partial->bh);
partial--;
}
out:
return err;
}
/*
* Indirect block might be removed by truncate while we were
* reading it. Handling of that case (forget what we've got and
* reread) is taken out of the main path.
*/
if (err == -EAGAIN)
goto changed;
left = (chain + depth) - partial;
err = alloc_branch(inode, left, offsets+(partial-chain), partial);
if (err)
goto cleanup;
if (splice_branch(inode, chain, partial, left) < 0)
goto changed;
set_buffer_new(bh);
goto got_it;
changed:
while (partial > chain) {
brelse(partial->bh);
partial--;
}
goto reread;
}
static inline int all_zeroes(block_t *p, block_t *q)
{
while (p < q)
if (*p++)
return 0;
return 1;
}
static Indirect *find_shared(struct inode *inode,
int depth,
int offsets[DEPTH],
Indirect chain[DEPTH],
block_t *top)
{
Indirect *partial, *p;
int k, err;
*top = 0;
for (k = depth; k > 1 && !offsets[k-1]; k--)
;
partial = get_branch(inode, k, offsets, chain, &err);
write_lock(&pointers_lock);
if (!partial)
partial = chain + k-1;
if (!partial->key && *partial->p) {
write_unlock(&pointers_lock);
goto no_top;
}
for (p=partial;p>chain && all_zeroes((block_t*)p->bh->b_data,p->p);p--)
;
if (p == chain + k - 1 && p > chain) {
p->p--;
} else {
*top = *p->p;
*p->p = 0;
}
write_unlock(&pointers_lock);
while(partial > p)
{
brelse(partial->bh);
partial--;
}
no_top:
return partial;
}
static inline void free_data(struct inode *inode, block_t *p, block_t *q)
{
unsigned long nr;
for ( ; p < q ; p++) {
nr = block_to_cpu(*p);
if (nr) {
*p = 0;
minix_free_block(inode, nr);
}
}
}
static void free_branches(struct inode *inode, block_t *p, block_t *q, int depth)
{
struct buffer_head * bh;
unsigned long nr;
if (depth--) {
for ( ; p < q ; p++) {
nr = block_to_cpu(*p);
if (!nr)
continue;
*p = 0;
bh = sb_bread(inode->i_sb, nr);
if (!bh)
continue;
free_branches(inode, (block_t*)bh->b_data,
block_end(bh), depth);
bforget(bh);
minix_free_block(inode, nr);
mark_inode_dirty(inode);
}
} else
free_data(inode, p, q);
}
static inline void truncate (struct inode * inode)
{
block_t *idata = i_data(inode);
int offsets[DEPTH];
Indirect chain[DEPTH];
Indirect *partial;
block_t nr = 0;
int n;
int first_whole;
long iblock;
iblock = (inode->i_size + BLOCK_SIZE-1) >> 10;
block_truncate_page(inode->i_mapping, inode->i_size, get_block);
n = block_to_path(inode, iblock, offsets);
if (!n)
return;
if (n == 1) {
free_data(inode, idata+offsets[0], idata + DIRECT);
first_whole = 0;
goto do_indirects;
}
first_whole = offsets[0] + 1 - DIRECT;
partial = find_shared(inode, n, offsets, chain, &nr);
if (nr) {
if (partial == chain)
mark_inode_dirty(inode);
else
mark_buffer_dirty_inode(partial->bh, inode);
free_branches(inode, &nr, &nr+1, (chain+n-1) - partial);
}
/* Clear the ends of indirect blocks on the shared branch */
while (partial > chain) {
free_branches(inode, partial->p + 1, block_end(partial->bh),
(chain+n-1) - partial);
mark_buffer_dirty_inode(partial->bh, inode);
brelse (partial->bh);
partial--;
}
do_indirects:
/* Kill the remaining (whole) subtrees */
while (first_whole < DEPTH-1) {
nr = idata[DIRECT+first_whole];
if (nr) {
idata[DIRECT+first_whole] = 0;
mark_inode_dirty(inode);
free_branches(inode, &nr, &nr+1, first_whole+1);
}
first_whole++;
}
inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
mark_inode_dirty(inode);
}
static inline unsigned nblocks(loff_t size)
{
unsigned blocks, res, direct = DIRECT, i = DEPTH;
blocks = (size + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS;
res = blocks;
while (--i && blocks > direct) {
blocks -= direct;
blocks += BLOCK_SIZE/sizeof(block_t) - 1;
blocks /= BLOCK_SIZE/sizeof(block_t);
res += blocks;
direct = 1;
}
return res;
}
+61
View File
@@ -0,0 +1,61 @@
#include <linux/buffer_head.h>
#include "minix.h"
enum {DEPTH = 3, DIRECT = 7}; /* Only double indirect */
typedef u16 block_t; /* 16 bit, host order */
static inline unsigned long block_to_cpu(block_t n)
{
return n;
}
static inline block_t cpu_to_block(unsigned long n)
{
return n;
}
static inline block_t *i_data(struct inode *inode)
{
return (block_t *)minix_i(inode)->u.i1_data;
}
static int block_to_path(struct inode * inode, long block, int offsets[DEPTH])
{
int n = 0;
if (block < 0) {
printk("minix_bmap: block<0");
} else if (block >= (minix_sb(inode->i_sb)->s_max_size/BLOCK_SIZE)) {
printk("minix_bmap: block>big");
} else if (block < 7) {
offsets[n++] = block;
} else if ((block -= 7) < 512) {
offsets[n++] = 7;
offsets[n++] = block;
} else {
block -= 512;
offsets[n++] = 8;
offsets[n++] = block>>9;
offsets[n++] = block & 511;
}
return n;
}
#include "itree_common.c"
int V1_minix_get_block(struct inode * inode, long block,
struct buffer_head *bh_result, int create)
{
return get_block(inode, block, bh_result, create);
}
void V1_minix_truncate(struct inode * inode)
{
truncate(inode);
}
unsigned V1_minix_blocks(loff_t size)
{
return nblocks(size);
}
+66
View File
@@ -0,0 +1,66 @@
#include <linux/buffer_head.h>
#include "minix.h"
enum {DIRECT = 7, DEPTH = 4}; /* Have triple indirect */
typedef u32 block_t; /* 32 bit, host order */
static inline unsigned long block_to_cpu(block_t n)
{
return n;
}
static inline block_t cpu_to_block(unsigned long n)
{
return n;
}
static inline block_t *i_data(struct inode *inode)
{
return (block_t *)minix_i(inode)->u.i2_data;
}
static int block_to_path(struct inode * inode, long block, int offsets[DEPTH])
{
int n = 0;
if (block < 0) {
printk("minix_bmap: block<0");
} else if (block >= (minix_sb(inode->i_sb)->s_max_size/BLOCK_SIZE)) {
printk("minix_bmap: block>big");
} else if (block < 7) {
offsets[n++] = block;
} else if ((block -= 7) < 256) {
offsets[n++] = 7;
offsets[n++] = block;
} else if ((block -= 256) < 256*256) {
offsets[n++] = 8;
offsets[n++] = block>>8;
offsets[n++] = block & 255;
} else {
block -= 256*256;
offsets[n++] = 9;
offsets[n++] = block>>16;
offsets[n++] = (block>>8) & 255;
offsets[n++] = block & 255;
}
return n;
}
#include "itree_common.c"
int V2_minix_get_block(struct inode * inode, long block,
struct buffer_head *bh_result, int create)
{
return get_block(inode, block, bh_result, create);
}
void V2_minix_truncate(struct inode * inode)
{
truncate(inode);
}
unsigned V2_minix_blocks(loff_t size)
{
return nblocks(size);
}
+96
View File
@@ -0,0 +1,96 @@
#include <linux/fs.h>
#include <linux/pagemap.h>
#include <linux/minix_fs.h>
/*
* change the define below to 0 if you want names > info->s_namelen chars to be
* truncated. Else they will be disallowed (ENAMETOOLONG).
*/
#define NO_TRUNCATE 1
#define INODE_VERSION(inode) minix_sb(inode->i_sb)->s_version
#define MINIX_V1 0x0001 /* original minix fs */
#define MINIX_V2 0x0002 /* minix V2 fs */
/*
* minix fs inode data in memory
*/
struct minix_inode_info {
union {
__u16 i1_data[16];
__u32 i2_data[16];
} u;
struct inode vfs_inode;
};
/*
* minix super-block data in memory
*/
struct minix_sb_info {
unsigned long s_ninodes;
unsigned long s_nzones;
unsigned long s_imap_blocks;
unsigned long s_zmap_blocks;
unsigned long s_firstdatazone;
unsigned long s_log_zone_size;
unsigned long s_max_size;
int s_dirsize;
int s_namelen;
int s_link_max;
struct buffer_head ** s_imap;
struct buffer_head ** s_zmap;
struct buffer_head * s_sbh;
struct minix_super_block * s_ms;
unsigned short s_mount_state;
unsigned short s_version;
};
extern struct minix_inode * minix_V1_raw_inode(struct super_block *, ino_t, struct buffer_head **);
extern struct minix2_inode * minix_V2_raw_inode(struct super_block *, ino_t, struct buffer_head **);
extern struct inode * minix_new_inode(const struct inode * dir, int * error);
extern void minix_free_inode(struct inode * inode);
extern unsigned long minix_count_free_inodes(struct minix_sb_info *sbi);
extern int minix_new_block(struct inode * inode);
extern void minix_free_block(struct inode * inode, int block);
extern unsigned long minix_count_free_blocks(struct minix_sb_info *sbi);
extern int minix_getattr(struct vfsmount *, struct dentry *, struct kstat *);
extern void V2_minix_truncate(struct inode *);
extern void V1_minix_truncate(struct inode *);
extern void V2_minix_truncate(struct inode *);
extern void minix_truncate(struct inode *);
extern int minix_sync_inode(struct inode *);
extern void minix_set_inode(struct inode *, dev_t);
extern int V1_minix_get_block(struct inode *, long, struct buffer_head *, int);
extern int V2_minix_get_block(struct inode *, long, struct buffer_head *, int);
extern unsigned V1_minix_blocks(loff_t);
extern unsigned V2_minix_blocks(loff_t);
extern struct minix_dir_entry *minix_find_entry(struct dentry*, struct page**);
extern int minix_add_link(struct dentry*, struct inode*);
extern int minix_delete_entry(struct minix_dir_entry*, struct page*);
extern int minix_make_empty(struct inode*, struct inode*);
extern int minix_empty_dir(struct inode*);
extern void minix_set_link(struct minix_dir_entry*, struct page*, struct inode*);
extern struct minix_dir_entry *minix_dotdot(struct inode*, struct page**);
extern ino_t minix_inode_by_name(struct dentry*);
extern int minix_sync_file(struct file *, struct dentry *, int);
extern struct inode_operations minix_file_inode_operations;
extern struct inode_operations minix_dir_inode_operations;
extern struct file_operations minix_file_operations;
extern struct file_operations minix_dir_operations;
extern struct dentry_operations minix_dentry_operations;
static inline struct minix_sb_info *minix_sb(struct super_block *sb)
{
return sb->s_fs_info;
}
static inline struct minix_inode_info *minix_i(struct inode *inode)
{
return list_entry(inode, struct minix_inode_info, vfs_inode);
}
+317
View File
@@ -0,0 +1,317 @@
/*
* linux/fs/minix/namei.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
#include "minix.h"
static inline void inc_count(struct inode *inode)
{
inode->i_nlink++;
mark_inode_dirty(inode);
}
static inline void dec_count(struct inode *inode)
{
inode->i_nlink--;
mark_inode_dirty(inode);
}
static int add_nondir(struct dentry *dentry, struct inode *inode)
{
int err = minix_add_link(dentry, inode);
if (!err) {
d_instantiate(dentry, inode);
return 0;
}
dec_count(inode);
iput(inode);
return err;
}
static int minix_hash(struct dentry *dentry, struct qstr *qstr)
{
unsigned long hash;
int i;
const unsigned char *name;
i = minix_sb(dentry->d_inode->i_sb)->s_namelen;
if (i >= qstr->len)
return 0;
/* Truncate the name in place, avoids having to define a compare
function. */
qstr->len = i;
name = qstr->name;
hash = init_name_hash();
while (i--)
hash = partial_name_hash(*name++, hash);
qstr->hash = end_name_hash(hash);
return 0;
}
struct dentry_operations minix_dentry_operations = {
.d_hash = minix_hash,
};
static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
{
struct inode * inode = NULL;
ino_t ino;
dentry->d_op = dir->i_sb->s_root->d_op;
if (dentry->d_name.len > minix_sb(dir->i_sb)->s_namelen)
return ERR_PTR(-ENAMETOOLONG);
ino = minix_inode_by_name(dentry);
if (ino) {
inode = iget(dir->i_sb, ino);
if (!inode)
return ERR_PTR(-EACCES);
}
d_add(dentry, inode);
return NULL;
}
static int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, dev_t rdev)
{
int error;
struct inode *inode;
if (!old_valid_dev(rdev))
return -EINVAL;
inode = minix_new_inode(dir, &error);
if (inode) {
inode->i_mode = mode;
minix_set_inode(inode, rdev);
mark_inode_dirty(inode);
error = add_nondir(dentry, inode);
}
return error;
}
static int minix_create(struct inode * dir, struct dentry *dentry, int mode,
struct nameidata *nd)
{
return minix_mknod(dir, dentry, mode, 0);
}
static int minix_symlink(struct inode * dir, struct dentry *dentry,
const char * symname)
{
int err = -ENAMETOOLONG;
int i = strlen(symname)+1;
struct inode * inode;
if (i > dir->i_sb->s_blocksize)
goto out;
inode = minix_new_inode(dir, &err);
if (!inode)
goto out;
inode->i_mode = S_IFLNK | 0777;
minix_set_inode(inode, 0);
err = page_symlink(inode, symname, i);
if (err)
goto out_fail;
err = add_nondir(dentry, inode);
out:
return err;
out_fail:
dec_count(inode);
iput(inode);
goto out;
}
static int minix_link(struct dentry * old_dentry, struct inode * dir,
struct dentry *dentry)
{
struct inode *inode = old_dentry->d_inode;
if (inode->i_nlink >= minix_sb(inode->i_sb)->s_link_max)
return -EMLINK;
inode->i_ctime = CURRENT_TIME_SEC;
inc_count(inode);
atomic_inc(&inode->i_count);
return add_nondir(dentry, inode);
}
static int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode)
{
struct inode * inode;
int err = -EMLINK;
if (dir->i_nlink >= minix_sb(dir->i_sb)->s_link_max)
goto out;
inc_count(dir);
inode = minix_new_inode(dir, &err);
if (!inode)
goto out_dir;
inode->i_mode = S_IFDIR | mode;
if (dir->i_mode & S_ISGID)
inode->i_mode |= S_ISGID;
minix_set_inode(inode, 0);
inc_count(inode);
err = minix_make_empty(inode, dir);
if (err)
goto out_fail;
err = minix_add_link(dentry, inode);
if (err)
goto out_fail;
d_instantiate(dentry, inode);
out:
return err;
out_fail:
dec_count(inode);
dec_count(inode);
iput(inode);
out_dir:
dec_count(dir);
goto out;
}
static int minix_unlink(struct inode * dir, struct dentry *dentry)
{
int err = -ENOENT;
struct inode * inode = dentry->d_inode;
struct page * page;
struct minix_dir_entry * de;
de = minix_find_entry(dentry, &page);
if (!de)
goto end_unlink;
err = minix_delete_entry(de, page);
if (err)
goto end_unlink;
inode->i_ctime = dir->i_ctime;
dec_count(inode);
end_unlink:
return err;
}
static int minix_rmdir(struct inode * dir, struct dentry *dentry)
{
struct inode * inode = dentry->d_inode;
int err = -ENOTEMPTY;
if (minix_empty_dir(inode)) {
err = minix_unlink(dir, dentry);
if (!err) {
dec_count(dir);
dec_count(inode);
}
}
return err;
}
static int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
struct inode * new_dir, struct dentry *new_dentry)
{
struct minix_sb_info * info = minix_sb(old_dir->i_sb);
struct inode * old_inode = old_dentry->d_inode;
struct inode * new_inode = new_dentry->d_inode;
struct page * dir_page = NULL;
struct minix_dir_entry * dir_de = NULL;
struct page * old_page;
struct minix_dir_entry * old_de;
int err = -ENOENT;
old_de = minix_find_entry(old_dentry, &old_page);
if (!old_de)
goto out;
if (S_ISDIR(old_inode->i_mode)) {
err = -EIO;
dir_de = minix_dotdot(old_inode, &dir_page);
if (!dir_de)
goto out_old;
}
if (new_inode) {
struct page * new_page;
struct minix_dir_entry * new_de;
err = -ENOTEMPTY;
if (dir_de && !minix_empty_dir(new_inode))
goto out_dir;
err = -ENOENT;
new_de = minix_find_entry(new_dentry, &new_page);
if (!new_de)
goto out_dir;
inc_count(old_inode);
minix_set_link(new_de, new_page, old_inode);
new_inode->i_ctime = CURRENT_TIME_SEC;
if (dir_de)
new_inode->i_nlink--;
dec_count(new_inode);
} else {
if (dir_de) {
err = -EMLINK;
if (new_dir->i_nlink >= info->s_link_max)
goto out_dir;
}
inc_count(old_inode);
err = minix_add_link(new_dentry, old_inode);
if (err) {
dec_count(old_inode);
goto out_dir;
}
if (dir_de)
inc_count(new_dir);
}
minix_delete_entry(old_de, old_page);
dec_count(old_inode);
if (dir_de) {
minix_set_link(dir_de, dir_page, new_dir);
dec_count(old_dir);
}
return 0;
out_dir:
if (dir_de) {
kunmap(dir_page);
page_cache_release(dir_page);
}
out_old:
kunmap(old_page);
page_cache_release(old_page);
out:
return err;
}
/*
* directories can handle most operations...
*/
struct inode_operations minix_dir_inode_operations = {
.create = minix_create,
.lookup = minix_lookup,
.link = minix_link,
.unlink = minix_unlink,
.symlink = minix_symlink,
.mkdir = minix_mkdir,
.rmdir = minix_rmdir,
.mknod = minix_mknod,
.rename = minix_rename,
.getattr = minix_getattr,
};