summaryrefslogtreecommitdiffstats
path: root/fs/minix
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /fs/minix
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!
Diffstat (limited to 'fs/minix')
-rw-r--r--fs/minix/Makefile7
-rw-r--r--fs/minix/bitmap.c269
-rw-r--r--fs/minix/dir.c409
-rw-r--r--fs/minix/file.c45
-rw-r--r--fs/minix/inode.c598
-rw-r--r--fs/minix/itree_common.c362
-rw-r--r--fs/minix/itree_v1.c61
-rw-r--r--fs/minix/itree_v2.c66
-rw-r--r--fs/minix/minix.h96
-rw-r--r--fs/minix/namei.c317
10 files changed, 2230 insertions, 0 deletions
diff --git a/fs/minix/Makefile b/fs/minix/Makefile
new file mode 100644
index 000000000000..3063015abfd0
--- /dev/null
+++ b/fs/minix/Makefile
@@ -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
diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c
new file mode 100644
index 000000000000..dc6a4e4abcdc
--- /dev/null
+++ b/fs/minix/bitmap.c
@@ -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);
+}
diff --git a/fs/minix/dir.c b/fs/minix/dir.c
new file mode 100644
index 000000000000..732502aabc05
--- /dev/null
+++ b/fs/minix/dir.c
@@ -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;
+}
diff --git a/fs/minix/file.c b/fs/minix/file.c
new file mode 100644
index 000000000000..f1d77acb3f01
--- /dev/null
+++ b/fs/minix/file.c
@@ -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;
+}
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
new file mode 100644
index 000000000000..3f18c21198d7
--- /dev/null
+++ b/fs/minix/inode.c
@@ -0,0 +1,598 @@
+/*
+ * linux/fs/minix/inode.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * Copyright (C) 1996 Gertjan van Wingerde (gertjan@cs.vu.nl)
+ * Minix V2 fs support.
+ *
+ * Modified for 680x0 by Andreas Schwab
+ */
+
+#include <linux/module.h>
+#include "minix.h"
+#include <linux/buffer_head.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/highuid.h>
+#include <linux/vfs.h>
+
+static void minix_read_inode(struct inode * inode);
+static int minix_write_inode(struct inode * inode, int wait);
+static int minix_statfs(struct super_block *sb, struct kstatfs *buf);
+static int minix_remount (struct super_block * sb, int * flags, char * data);
+
+static void minix_delete_inode(struct inode *inode)
+{
+ inode->i_size = 0;
+ minix_truncate(inode);
+ minix_free_inode(inode);
+}
+
+static void minix_put_super(struct super_block *sb)
+{
+ int i;
+ struct minix_sb_info *sbi = minix_sb(sb);
+
+ if (!(sb->s_flags & MS_RDONLY)) {
+ sbi->s_ms->s_state = sbi->s_mount_state;
+ mark_buffer_dirty(sbi->s_sbh);
+ }
+ for (i = 0; i < sbi->s_imap_blocks; i++)
+ brelse(sbi->s_imap[i]);
+ for (i = 0; i < sbi->s_zmap_blocks; i++)
+ brelse(sbi->s_zmap[i]);
+ brelse (sbi->s_sbh);
+ kfree(sbi->s_imap);
+ sb->s_fs_info = NULL;
+ kfree(sbi);
+
+ return;
+}
+
+static kmem_cache_t * minix_inode_cachep;
+
+static struct inode *minix_alloc_inode(struct super_block *sb)
+{
+ struct minix_inode_info *ei;
+ ei = (struct minix_inode_info *)kmem_cache_alloc(minix_inode_cachep, SLAB_KERNEL);
+ if (!ei)
+ return NULL;
+ return &ei->vfs_inode;
+}
+
+static void minix_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(minix_inode_cachep, minix_i(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct minix_inode_info *ei = (struct minix_inode_info *) foo;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR)
+ inode_init_once(&ei->vfs_inode);
+}
+
+static int init_inodecache(void)
+{
+ minix_inode_cachep = kmem_cache_create("minix_inode_cache",
+ sizeof(struct minix_inode_info),
+ 0, SLAB_RECLAIM_ACCOUNT,
+ init_once, NULL);
+ if (minix_inode_cachep == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+static void destroy_inodecache(void)
+{
+ if (kmem_cache_destroy(minix_inode_cachep))
+ printk(KERN_INFO "minix_inode_cache: not all structures were freed\n");
+}
+
+static struct super_operations minix_sops = {
+ .alloc_inode = minix_alloc_inode,
+ .destroy_inode = minix_destroy_inode,
+ .read_inode = minix_read_inode,
+ .write_inode = minix_write_inode,
+ .delete_inode = minix_delete_inode,
+ .put_super = minix_put_super,
+ .statfs = minix_statfs,
+ .remount_fs = minix_remount,
+};
+
+static int minix_remount (struct super_block * sb, int * flags, char * data)
+{
+ struct minix_sb_info * sbi = minix_sb(sb);
+ struct minix_super_block * ms;
+
+ ms = sbi->s_ms;
+ if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
+ return 0;
+ if (*flags & MS_RDONLY) {
+ if (ms->s_state & MINIX_VALID_FS ||
+ !(sbi->s_mount_state & MINIX_VALID_FS))
+ return 0;
+ /* Mounting a rw partition read-only. */
+ ms->s_state = sbi->s_mount_state;
+ mark_buffer_dirty(sbi->s_sbh);
+ } else {
+ /* Mount a partition which is read-only, read-write. */
+ sbi->s_mount_state = ms->s_state;
+ ms->s_state &= ~MINIX_VALID_FS;
+ mark_buffer_dirty(sbi->s_sbh);
+
+ if (!(sbi->s_mount_state & MINIX_VALID_FS))
+ printk ("MINIX-fs warning: remounting unchecked fs, "
+ "running fsck is recommended.\n");
+ else if ((sbi->s_mount_state & MINIX_ERROR_FS))
+ printk ("MINIX-fs warning: remounting fs with errors, "
+ "running fsck is recommended.\n");
+ }
+ return 0;
+}
+
+static int minix_fill_super(struct super_block *s, void *data, int silent)
+{
+ struct buffer_head *bh;
+ struct buffer_head **map;
+ struct minix_super_block *ms;
+ int i, block;
+ struct inode *root_inode;
+ struct minix_sb_info *sbi;
+
+ sbi = kmalloc(sizeof(struct minix_sb_info), GFP_KERNEL);
+ if (!sbi)
+ return -ENOMEM;
+ s->s_fs_info = sbi;
+ memset(sbi, 0, sizeof(struct minix_sb_info));
+
+ /* N.B. These should be compile-time tests.
+ Unfortunately that is impossible. */
+ if (32 != sizeof (struct minix_inode))
+ panic("bad V1 i-node size");
+ if (64 != sizeof(struct minix2_inode))
+ panic("bad V2 i-node size");
+
+ if (!sb_set_blocksize(s, BLOCK_SIZE))
+ goto out_bad_hblock;
+
+ if (!(bh = sb_bread(s, 1)))
+ goto out_bad_sb;
+
+ ms = (struct minix_super_block *) bh->b_data;
+ sbi->s_ms = ms;
+ sbi->s_sbh = bh;
+ sbi->s_mount_state = ms->s_state;
+ sbi->s_ninodes = ms->s_ninodes;
+ sbi->s_nzones = ms->s_nzones;
+ sbi->s_imap_blocks = ms->s_imap_blocks;
+ sbi->s_zmap_blocks = ms->s_zmap_blocks;
+ sbi->s_firstdatazone = ms->s_firstdatazone;
+ sbi->s_log_zone_size = ms->s_log_zone_size;
+ sbi->s_max_size = ms->s_max_size;
+ s->s_magic = ms->s_magic;
+ if (s->s_magic == MINIX_SUPER_MAGIC) {
+ sbi->s_version = MINIX_V1;
+ sbi->s_dirsize = 16;
+ sbi->s_namelen = 14;
+ sbi->s_link_max = MINIX_LINK_MAX;
+ } else if (s->s_magic == MINIX_SUPER_MAGIC2) {
+ sbi->s_version = MINIX_V1;
+ sbi->s_dirsize = 32;
+ sbi->s_namelen = 30;
+ sbi->s_link_max = MINIX_LINK_MAX;
+ } else if (s->s_magic == MINIX2_SUPER_MAGIC) {
+ sbi->s_version = MINIX_V2;
+ sbi->s_nzones = ms->s_zones;
+ sbi->s_dirsize = 16;
+ sbi->s_namelen = 14;
+ sbi->s_link_max = MINIX2_LINK_MAX;
+ } else if (s->s_magic == MINIX2_SUPER_MAGIC2) {
+ sbi->s_version = MINIX_V2;
+ sbi->s_nzones = ms->s_zones;
+ sbi->s_dirsize = 32;
+ sbi->s_namelen = 30;
+ sbi->s_link_max = MINIX2_LINK_MAX;
+ } else
+ goto out_no_fs;
+
+ /*
+ * Allocate the buffer map to keep the superblock small.
+ */
+ i = (sbi->s_imap_blocks + sbi->s_zmap_blocks) * sizeof(bh);
+ map = kmalloc(i, GFP_KERNEL);
+ if (!map)
+ goto out_no_map;
+ memset(map, 0, i);
+ sbi->s_imap = &map[0];
+ sbi->s_zmap = &map[sbi->s_imap_blocks];
+
+ block=2;
+ for (i=0 ; i < sbi->s_imap_blocks ; i++) {
+ if (!(sbi->s_imap[i]=sb_bread(s, block)))
+ goto out_no_bitmap;
+ block++;
+ }
+ for (i=0 ; i < sbi->s_zmap_blocks ; i++) {
+ if (!(sbi->s_zmap[i]=sb_bread(s, block)))
+ goto out_no_bitmap;
+ block++;
+ }
+
+ minix_set_bit(0,sbi->s_imap[0]->b_data);
+ minix_set_bit(0,sbi->s_zmap[0]->b_data);
+
+ /* set up enough so that it can read an inode */
+ s->s_op = &minix_sops;
+ root_inode = iget(s, MINIX_ROOT_INO);
+ if (!root_inode || is_bad_inode(root_inode))
+ goto out_no_root;
+
+ s->s_root = d_alloc_root(root_inode);
+ if (!s->s_root)
+ goto out_iput;
+
+ if (!NO_TRUNCATE)
+ s->s_root->d_op = &minix_dentry_operations;
+
+ if (!(s->s_flags & MS_RDONLY)) {
+ ms->s_state &= ~MINIX_VALID_FS;
+ mark_buffer_dirty(bh);
+ }
+ if (!(sbi->s_mount_state & MINIX_VALID_FS))
+ printk ("MINIX-fs: mounting unchecked file system, "
+ "running fsck is recommended.\n");
+ else if (sbi->s_mount_state & MINIX_ERROR_FS)
+ printk ("MINIX-fs: mounting file system with errors, "
+ "running fsck is recommended.\n");
+ return 0;
+
+out_iput:
+ iput(root_inode);
+ goto out_freemap;
+
+out_no_root:
+ if (!silent)
+ printk("MINIX-fs: get root inode failed\n");
+ goto out_freemap;
+
+out_no_bitmap:
+ printk("MINIX-fs: bad superblock or unable to read bitmaps\n");
+ out_freemap:
+ for (i = 0; i < sbi->s_imap_blocks; i++)
+ brelse(sbi->s_imap[i]);
+ for (i = 0; i < sbi->s_zmap_blocks; i++)
+ brelse(sbi->s_zmap[i]);
+ kfree(sbi->s_imap);
+ goto out_release;
+
+out_no_map:
+ if (!silent)
+ printk ("MINIX-fs: can't allocate map\n");
+ goto out_release;
+
+out_no_fs:
+ if (!silent)
+ printk("VFS: Can't find a Minix or Minix V2 filesystem on device "
+ "%s.\n", s->s_id);
+ out_release:
+ brelse(bh);
+ goto out;
+
+out_bad_hblock:
+ printk("MINIX-fs: blocksize too small for device.\n");
+ goto out;
+
+out_bad_sb:
+ printk("MINIX-fs: unable to read superblock\n");
+ out:
+ s->s_fs_info = NULL;
+ kfree(sbi);
+ return -EINVAL;
+}
+
+static int minix_statfs(struct super_block *sb, struct kstatfs *buf)
+{
+ struct minix_sb_info *sbi = minix_sb(sb);
+ buf->f_type = sb->s_magic;
+ buf->f_bsize = sb->s_blocksize;
+ buf->f_blocks = (sbi->s_nzones - sbi->s_firstdatazone) << sbi->s_log_zone_size;
+ buf->f_bfree = minix_count_free_blocks(sbi);
+ buf->f_bavail = buf->f_bfree;
+ buf->f_files = sbi->s_ninodes;
+ buf->f_ffree = minix_count_free_inodes(sbi);
+ buf->f_namelen = sbi->s_namelen;
+ return 0;
+}
+
+static int minix_get_block(struct inode *inode, sector_t block,
+ struct buffer_head *bh_result, int create)
+{
+ if (INODE_VERSION(inode) == MINIX_V1)
+ return V1_minix_get_block(inode, block, bh_result, create);
+ else
+ return V2_minix_get_block(inode, block, bh_result, create);
+}
+
+static int minix_writepage(struct page *page, struct writeback_control *wbc)
+{
+ return block_write_full_page(page, minix_get_block, wbc);
+}
+static int minix_readpage(struct file *file, struct page *page)
+{
+ return block_read_full_page(page,minix_get_block);
+}
+static int minix_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
+{
+ return block_prepare_write(page,from,to,minix_get_block);
+}
+static sector_t minix_bmap(struct address_space *mapping, sector_t block)
+{
+ return generic_block_bmap(mapping,block,minix_get_block);
+}
+static struct address_space_operations minix_aops = {
+ .readpage = minix_readpage,
+ .writepage = minix_writepage,
+ .sync_page = block_sync_page,
+ .prepare_write = minix_prepare_write,
+ .commit_write = generic_commit_write,
+ .bmap = minix_bmap
+};
+
+static struct inode_operations minix_symlink_inode_operations = {
+ .readlink = generic_readlink,
+ .follow_link = page_follow_link_light,
+ .put_link = page_put_link,
+ .getattr = minix_getattr,
+};
+
+void minix_set_inode(struct inode *inode, dev_t rdev)
+{
+ if (S_ISREG(inode->i_mode)) {
+ inode->i_op = &minix_file_inode_operations;