aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndries Brouwer <aeb@cwi.nl>2007-02-12 03:52:49 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-12 12:48:31 -0500
commit939b00df0306bc4b5cd25c3c3c78e89b91e72fc8 (patch)
treec251dca9f3ebbebfa1f40f39716423842b247742
parentb587b13a4f670ebae79ae6259cf44328455e4e69 (diff)
[PATCH] Minix V3 support
This morning I needed to read a Minix V3 filesystem, but unfortunately my 2.6.19 did not support that, and neither did the downloaded 2.6.20rc4. Fortunately, google told me that Daniel Aragones had already done the work, patch found at http://www.terra.es/personal2/danarag/ Unfortunaly, looking at the patch was painful to my eyes, so I polished it a bit before applying. The resulting kernel boots, and reads the filesystem it needed to read. Signed-off-by: Daniel Aragones <danarag@gmail.com> Signed-off-by: Andries Brouwer <aeb@cwi.nl> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/minix/bitmap.c69
-rw-r--r--fs/minix/dir.c162
-rw-r--r--fs/minix/inode.c49
-rw-r--r--fs/minix/itree_common.c16
-rw-r--r--fs/minix/itree_v1.c4
-rw-r--r--fs/minix/itree_v2.c7
-rw-r--r--fs/minix/minix.h12
-rw-r--r--include/linux/magic.h1
-rw-r--r--include/linux/minix_fs.h25
9 files changed, 233 insertions, 112 deletions
diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c
index df6b1075b549..c4a554df7b7e 100644
--- a/fs/minix/bitmap.c
+++ b/fs/minix/bitmap.c
@@ -26,14 +26,14 @@ static unsigned long count_free(struct buffer_head *map[], unsigned numblocks, _
26 for (i=0; i<numblocks-1; i++) { 26 for (i=0; i<numblocks-1; i++) {
27 if (!(bh=map[i])) 27 if (!(bh=map[i]))
28 return(0); 28 return(0);
29 for (j=0; j<BLOCK_SIZE; j++) 29 for (j=0; j<bh->b_size; j++)
30 sum += nibblemap[bh->b_data[j] & 0xf] 30 sum += nibblemap[bh->b_data[j] & 0xf]
31 + nibblemap[(bh->b_data[j]>>4) & 0xf]; 31 + nibblemap[(bh->b_data[j]>>4) & 0xf];
32 } 32 }
33 33
34 if (numblocks==0 || !(bh=map[numblocks-1])) 34 if (numblocks==0 || !(bh=map[numblocks-1]))
35 return(0); 35 return(0);
36 i = ((numbits-(numblocks-1)*BLOCK_SIZE*8)/16)*2; 36 i = ((numbits - (numblocks-1) * bh->b_size * 8) / 16) * 2;
37 for (j=0; j<i; j++) { 37 for (j=0; j<i; j++) {
38 sum += nibblemap[bh->b_data[j] & 0xf] 38 sum += nibblemap[bh->b_data[j] & 0xf]
39 + nibblemap[(bh->b_data[j]>>4) & 0xf]; 39 + nibblemap[(bh->b_data[j]>>4) & 0xf];
@@ -48,28 +48,29 @@ static unsigned long count_free(struct buffer_head *map[], unsigned numblocks, _
48 return(sum); 48 return(sum);
49} 49}
50 50
51void minix_free_block(struct inode * inode, int block) 51void minix_free_block(struct inode *inode, unsigned long block)
52{ 52{
53 struct super_block * sb = inode->i_sb; 53 struct super_block *sb = inode->i_sb;
54 struct minix_sb_info * sbi = minix_sb(sb); 54 struct minix_sb_info *sbi = minix_sb(sb);
55 struct buffer_head * bh; 55 struct buffer_head *bh;
56 unsigned int bit,zone; 56 int k = sb->s_blocksize_bits + 3;
57 unsigned long bit, zone;
57 58
58 if (block < sbi->s_firstdatazone || block >= sbi->s_nzones) { 59 if (block < sbi->s_firstdatazone || block >= sbi->s_nzones) {
59 printk("Trying to free block not in datazone\n"); 60 printk("Trying to free block not in datazone\n");
60 return; 61 return;
61 } 62 }
62 zone = block - sbi->s_firstdatazone + 1; 63 zone = block - sbi->s_firstdatazone + 1;
63 bit = zone & 8191; 64 bit = zone & ((1<<k) - 1);
64 zone >>= 13; 65 zone >>= k;
65 if (zone >= sbi->s_zmap_blocks) { 66 if (zone >= sbi->s_zmap_blocks) {
66 printk("minix_free_block: nonexistent bitmap buffer\n"); 67 printk("minix_free_block: nonexistent bitmap buffer\n");
67 return; 68 return;
68 } 69 }
69 bh = sbi->s_zmap[zone]; 70 bh = sbi->s_zmap[zone];
70 lock_kernel(); 71 lock_kernel();
71 if (!minix_test_and_clear_bit(bit,bh->b_data)) 72 if (!minix_test_and_clear_bit(bit, bh->b_data))
72 printk("free_block (%s:%d): bit already cleared\n", 73 printk("minix_free_block (%s:%lu): bit already cleared\n",
73 sb->s_id, block); 74 sb->s_id, block);
74 unlock_kernel(); 75 unlock_kernel();
75 mark_buffer_dirty(bh); 76 mark_buffer_dirty(bh);
@@ -79,6 +80,7 @@ void minix_free_block(struct inode * inode, int block)
79int minix_new_block(struct inode * inode) 80int minix_new_block(struct inode * inode)
80{ 81{
81 struct minix_sb_info *sbi = minix_sb(inode->i_sb); 82 struct minix_sb_info *sbi = minix_sb(inode->i_sb);
83 int bits_per_zone = 8 * inode->i_sb->s_blocksize;
82 int i; 84 int i;
83 85
84 for (i = 0; i < sbi->s_zmap_blocks; i++) { 86 for (i = 0; i < sbi->s_zmap_blocks; i++) {
@@ -86,11 +88,12 @@ int minix_new_block(struct inode * inode)
86 int j; 88 int j;
87 89
88 lock_kernel(); 90 lock_kernel();
89 if ((j = minix_find_first_zero_bit(bh->b_data, 8192)) < 8192) { 91 j = minix_find_first_zero_bit(bh->b_data, bits_per_zone);
90 minix_set_bit(j,bh->b_data); 92 if (j < bits_per_zone) {
93 minix_set_bit(j, bh->b_data);
91 unlock_kernel(); 94 unlock_kernel();
92 mark_buffer_dirty(bh); 95 mark_buffer_dirty(bh);
93 j += i*8192 + sbi->s_firstdatazone-1; 96 j += i * bits_per_zone + sbi->s_firstdatazone-1;
94 if (j < sbi->s_firstdatazone || j >= sbi->s_nzones) 97 if (j < sbi->s_firstdatazone || j >= sbi->s_nzones)
95 break; 98 break;
96 return j; 99 return j;
@@ -137,6 +140,7 @@ minix_V2_raw_inode(struct super_block *sb, ino_t ino, struct buffer_head **bh)
137 int block; 140 int block;
138 struct minix_sb_info *sbi = minix_sb(sb); 141 struct minix_sb_info *sbi = minix_sb(sb);
139 struct minix2_inode *p; 142 struct minix2_inode *p;
143 int minix2_inodes_per_block = sb->s_blocksize / sizeof(struct minix2_inode);
140 144
141 *bh = NULL; 145 *bh = NULL;
142 if (!ino || ino > sbi->s_ninodes) { 146 if (!ino || ino > sbi->s_ninodes) {
@@ -146,14 +150,14 @@ minix_V2_raw_inode(struct super_block *sb, ino_t ino, struct buffer_head **bh)
146 } 150 }
147 ino--; 151 ino--;
148 block = 2 + sbi->s_imap_blocks + sbi->s_zmap_blocks + 152 block = 2 + sbi->s_imap_blocks + sbi->s_zmap_blocks +
149 ino / MINIX2_INODES_PER_BLOCK; 153 ino / minix2_inodes_per_block;
150 *bh = sb_bread(sb, block); 154 *bh = sb_bread(sb, block);
151 if (!*bh) { 155 if (!*bh) {
152 printk("Unable to read inode block\n"); 156 printk("Unable to read inode block\n");
153 return NULL; 157 return NULL;
154 } 158 }
155 p = (void *)(*bh)->b_data; 159 p = (void *)(*bh)->b_data;
156 return p + ino % MINIX2_INODES_PER_BLOCK; 160 return p + ino % minix2_inodes_per_block;
157} 161}
158 162
159/* Clear the link count and mode of a deleted inode on disk. */ 163/* Clear the link count and mode of a deleted inode on disk. */
@@ -185,26 +189,30 @@ static void minix_clear_inode(struct inode *inode)
185 189
186void minix_free_inode(struct inode * inode) 190void minix_free_inode(struct inode * inode)
187{ 191{
192 struct super_block *sb = inode->i_sb;
188 struct minix_sb_info *sbi = minix_sb(inode->i_sb); 193 struct minix_sb_info *sbi = minix_sb(inode->i_sb);
189 struct buffer_head * bh; 194 struct buffer_head *bh;
190 unsigned long ino; 195 int k = sb->s_blocksize_bits + 3;
196 unsigned long ino, bit;
191 197
192 ino = inode->i_ino; 198 ino = inode->i_ino;
193 if (ino < 1 || ino > sbi->s_ninodes) { 199 if (ino < 1 || ino > sbi->s_ninodes) {
194 printk("minix_free_inode: inode 0 or nonexistent inode\n"); 200 printk("minix_free_inode: inode 0 or nonexistent inode\n");
195 goto out; 201 goto out;
196 } 202 }
197 if ((ino >> 13) >= sbi->s_imap_blocks) { 203 bit = ino & ((1<<k) - 1);
204 ino >>= k;
205 if (ino >= sbi->s_imap_blocks) {
198 printk("minix_free_inode: nonexistent imap in superblock\n"); 206 printk("minix_free_inode: nonexistent imap in superblock\n");
199 goto out; 207 goto out;
200 } 208 }
201 209
202 minix_clear_inode(inode); /* clear on-disk copy */ 210 minix_clear_inode(inode); /* clear on-disk copy */
203 211
204 bh = sbi->s_imap[ino >> 13]; 212 bh = sbi->s_imap[ino];
205 lock_kernel(); 213 lock_kernel();
206 if (!minix_test_and_clear_bit(ino & 8191, bh->b_data)) 214 if (!minix_test_and_clear_bit(bit, bh->b_data))
207 printk("minix_free_inode: bit %lu already cleared\n", ino); 215 printk("minix_free_inode: bit %lu already cleared\n", bit);
208 unlock_kernel(); 216 unlock_kernel();
209 mark_buffer_dirty(bh); 217 mark_buffer_dirty(bh);
210 out: 218 out:
@@ -217,35 +225,38 @@ struct inode * minix_new_inode(const struct inode * dir, int * error)
217 struct minix_sb_info *sbi = minix_sb(sb); 225 struct minix_sb_info *sbi = minix_sb(sb);
218 struct inode *inode = new_inode(sb); 226 struct inode *inode = new_inode(sb);
219 struct buffer_head * bh; 227 struct buffer_head * bh;
220 int i,j; 228 int bits_per_zone = 8 * sb->s_blocksize;
229 unsigned long j;
230 int i;
221 231
222 if (!inode) { 232 if (!inode) {
223 *error = -ENOMEM; 233 *error = -ENOMEM;
224 return NULL; 234 return NULL;
225 } 235 }
226 j = 8192; 236 j = bits_per_zone;
227 bh = NULL; 237 bh = NULL;
228 *error = -ENOSPC; 238 *error = -ENOSPC;
229 lock_kernel(); 239 lock_kernel();
230 for (i = 0; i < sbi->s_imap_blocks; i++) { 240 for (i = 0; i < sbi->s_imap_blocks; i++) {
231 bh = sbi->s_imap[i]; 241 bh = sbi->s_imap[i];
232 if ((j = minix_find_first_zero_bit(bh->b_data, 8192)) < 8192) 242 j = minix_find_first_zero_bit(bh->b_data, bits_per_zone);
243 if (j < bits_per_zone)
233 break; 244 break;
234 } 245 }
235 if (!bh || j >= 8192) { 246 if (!bh || j >= bits_per_zone) {
236 unlock_kernel(); 247 unlock_kernel();
237 iput(inode); 248 iput(inode);
238 return NULL; 249 return NULL;
239 } 250 }
240 if (minix_test_and_set_bit(j,bh->b_data)) { /* shouldn't happen */ 251 if (minix_test_and_set_bit(j, bh->b_data)) { /* shouldn't happen */
241 printk("new_inode: bit already set\n");
242 unlock_kernel(); 252 unlock_kernel();
253 printk("minix_new_inode: bit already set\n");
243 iput(inode); 254 iput(inode);
244 return NULL; 255 return NULL;
245 } 256 }
246 unlock_kernel(); 257 unlock_kernel();
247 mark_buffer_dirty(bh); 258 mark_buffer_dirty(bh);
248 j += i*8192; 259 j += i * bits_per_zone;
249 if (!j || j > sbi->s_ninodes) { 260 if (!j || j > sbi->s_ninodes) {
250 iput(inode); 261 iput(inode);
251 return NULL; 262 return NULL;
diff --git a/fs/minix/dir.c b/fs/minix/dir.c
index ab782c4086f5..cb4cb571fddf 100644
--- a/fs/minix/dir.c
+++ b/fs/minix/dir.c
@@ -4,6 +4,8 @@
4 * Copyright (C) 1991, 1992 Linus Torvalds 4 * Copyright (C) 1991, 1992 Linus Torvalds
5 * 5 *
6 * minix directory handling functions 6 * minix directory handling functions
7 *
8 * Updated to filesystem version 3 by Daniel Aragones
7 */ 9 */
8 10
9#include "minix.h" 11#include "minix.h"
@@ -11,6 +13,7 @@
11#include <linux/smp_lock.h> 13#include <linux/smp_lock.h>
12 14
13typedef struct minix_dir_entry minix_dirent; 15typedef struct minix_dir_entry minix_dirent;
16typedef struct minix3_dir_entry minix3_dirent;
14 17
15static int minix_readdir(struct file *, void *, filldir_t); 18static int minix_readdir(struct file *, void *, filldir_t);
16 19
@@ -89,6 +92,8 @@ static int minix_readdir(struct file * filp, void * dirent, filldir_t filldir)
89 unsigned long npages = dir_pages(inode); 92 unsigned long npages = dir_pages(inode);
90 struct minix_sb_info *sbi = minix_sb(sb); 93 struct minix_sb_info *sbi = minix_sb(sb);
91 unsigned chunk_size = sbi->s_dirsize; 94 unsigned chunk_size = sbi->s_dirsize;
95 char *name;
96 __u32 inumber;
92 97
93 lock_kernel(); 98 lock_kernel();
94 99
@@ -105,16 +110,24 @@ static int minix_readdir(struct file * filp, void * dirent, filldir_t filldir)
105 kaddr = (char *)page_address(page); 110 kaddr = (char *)page_address(page);
106 p = kaddr+offset; 111 p = kaddr+offset;
107 limit = kaddr + minix_last_byte(inode, n) - chunk_size; 112 limit = kaddr + minix_last_byte(inode, n) - chunk_size;
108 for ( ; p <= limit ; p = minix_next_entry(p, sbi)) { 113 for ( ; p <= limit; p = minix_next_entry(p, sbi)) {
109 minix_dirent *de = (minix_dirent *)p; 114 if (sbi->s_version == MINIX_V3) {
110 if (de->inode) { 115 minix3_dirent *de3 = (minix3_dirent *)p;
116 name = de3->name;
117 inumber = de3->inode;
118 } else {
119 minix_dirent *de = (minix_dirent *)p;
120 name = de->name;
121 inumber = de->inode;
122 }
123 if (inumber) {
111 int over; 124 int over;
112 unsigned l = strnlen(de->name,sbi->s_namelen);
113 125
126 unsigned l = strnlen(name, sbi->s_namelen);
114 offset = p - kaddr; 127 offset = p - kaddr;
115 over = filldir(dirent, de->name, l, 128 over = filldir(dirent, name, l,
116 (n<<PAGE_CACHE_SHIFT) | offset, 129 (n << PAGE_CACHE_SHIFT) | offset,
117 de->inode, DT_UNKNOWN); 130 inumber, DT_UNKNOWN);
118 if (over) { 131 if (over) {
119 dir_put_page(page); 132 dir_put_page(page);
120 goto done; 133 goto done;
@@ -156,23 +169,34 @@ minix_dirent *minix_find_entry(struct dentry *dentry, struct page **res_page)
156 unsigned long n; 169 unsigned long n;
157 unsigned long npages = dir_pages(dir); 170 unsigned long npages = dir_pages(dir);
158 struct page *page = NULL; 171 struct page *page = NULL;
159 struct minix_dir_entry *de; 172 char *p;
160 173
174 char *namx;
175 __u32 inumber;
161 *res_page = NULL; 176 *res_page = NULL;
162 177
163 for (n = 0; n < npages; n++) { 178 for (n = 0; n < npages; n++) {
164 char *kaddr; 179 char *kaddr, *limit;
180
165 page = dir_get_page(dir, n); 181 page = dir_get_page(dir, n);
166 if (IS_ERR(page)) 182 if (IS_ERR(page))
167 continue; 183 continue;
168 184
169 kaddr = (char*)page_address(page); 185 kaddr = (char*)page_address(page);
170 de = (struct minix_dir_entry *) kaddr; 186 limit = kaddr + minix_last_byte(dir, n) - sbi->s_dirsize;
171 kaddr += minix_last_byte(dir, n) - sbi->s_dirsize; 187 for (p = kaddr; p <= limit; p = minix_next_entry(p, sbi)) {
172 for ( ; (char *) de <= kaddr ; de = minix_next_entry(de,sbi)) { 188 if (sbi->s_version == MINIX_V3) {
173 if (!de->inode) 189 minix3_dirent *de3 = (minix3_dirent *)p;
190 namx = de3->name;
191 inumber = de3->inode;
192 } else {
193 minix_dirent *de = (minix_dirent *)p;
194 namx = de->name;
195 inumber = de->inode;
196 }
197 if (!inumber)
174 continue; 198 continue;
175 if (namecompare(namelen,sbi->s_namelen,name,de->name)) 199 if (namecompare(namelen, sbi->s_namelen, name, namx))
176 goto found; 200 goto found;
177 } 201 }
178 dir_put_page(page); 202 dir_put_page(page);
@@ -181,7 +205,7 @@ minix_dirent *minix_find_entry(struct dentry *dentry, struct page **res_page)
181 205
182found: 206found:
183 *res_page = page; 207 *res_page = page;
184 return de; 208 return (minix_dirent *)p;
185} 209}
186 210
187int minix_add_link(struct dentry *dentry, struct inode *inode) 211int minix_add_link(struct dentry *dentry, struct inode *inode)
@@ -192,12 +216,15 @@ int minix_add_link(struct dentry *dentry, struct inode *inode)
192 struct super_block * sb = dir->i_sb; 216 struct super_block * sb = dir->i_sb;
193 struct minix_sb_info * sbi = minix_sb(sb); 217 struct minix_sb_info * sbi = minix_sb(sb);
194 struct page *page = NULL; 218 struct page *page = NULL;
195 struct minix_dir_entry * de;
196 unsigned long npages = dir_pages(dir); 219 unsigned long npages = dir_pages(dir);
197 unsigned long n; 220 unsigned long n;
198 char *kaddr; 221 char *kaddr, *p;
222 minix_dirent *de;
223 minix3_dirent *de3;
199 unsigned from, to; 224 unsigned from, to;
200 int err; 225 int err;
226 char *namx = NULL;
227 __u32 inumber;
201 228
202 /* 229 /*
203 * We take care of directory expansion in the same loop 230 * We take care of directory expansion in the same loop
@@ -205,7 +232,7 @@ int minix_add_link(struct dentry *dentry, struct inode *inode)
205 * to protect that region. 232 * to protect that region.
206 */ 233 */
207 for (n = 0; n <= npages; n++) { 234 for (n = 0; n <= npages; n++) {
208 char *dir_end; 235 char *limit, *dir_end;
209 236
210 page = dir_get_page(dir, n); 237 page = dir_get_page(dir, n);
211 err = PTR_ERR(page); 238 err = PTR_ERR(page);
@@ -214,20 +241,30 @@ int minix_add_link(struct dentry *dentry, struct inode *inode)
214 lock_page(page); 241 lock_page(page);
215 kaddr = (char*)page_address(page); 242 kaddr = (char*)page_address(page);
216 dir_end = kaddr + minix_last_byte(dir, n); 243 dir_end = kaddr + minix_last_byte(dir, n);
217 de = (minix_dirent *)kaddr; 244 limit = kaddr + PAGE_CACHE_SIZE - sbi->s_dirsize;
218 kaddr += PAGE_CACHE_SIZE - sbi->s_dirsize; 245 for (p = kaddr; p <= limit; p = minix_next_entry(p, sbi)) {
219 while ((char *)de <= kaddr) { 246 de = (minix_dirent *)p;
220 if ((char *)de == dir_end) { 247 de3 = (minix3_dirent *)p;
248 if (sbi->s_version == MINIX_V3) {
249 namx = de3->name;
250 inumber = de3->inode;
251 } else {
252 namx = de->name;
253 inumber = de->inode;
254 }
255 if (p == dir_end) {
221 /* We hit i_size */ 256 /* We hit i_size */
222 de->inode = 0; 257 if (sbi->s_version == MINIX_V3)
258 de3->inode = 0;
259 else
260 de->inode = 0;
223 goto got_it; 261 goto got_it;
224 } 262 }
225 if (!de->inode) 263 if (!inumber)
226 goto got_it; 264 goto got_it;
227 err = -EEXIST; 265 err = -EEXIST;
228 if (namecompare(namelen,sbi->s_namelen,name,de->name)) 266 if (namecompare(namelen, sbi->s_namelen, name, namx))
229 goto out_unlock; 267 goto out_unlock;
230 de = minix_next_entry(de, sbi);
231 } 268 }
232 unlock_page(page); 269 unlock_page(page);
233 dir_put_page(page); 270 dir_put_page(page);
@@ -236,14 +273,19 @@ int minix_add_link(struct dentry *dentry, struct inode *inode)
236 return -EINVAL; 273 return -EINVAL;
237 274
238got_it: 275got_it:
239 from = (char*)de - (char*)page_address(page); 276 from = p - (char*)page_address(page);
240 to = from + sbi->s_dirsize; 277 to = from + sbi->s_dirsize;
241 err = page->mapping->a_ops->prepare_write(NULL, page, from, to); 278 err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
242 if (err) 279 if (err)
243 goto out_unlock; 280 goto out_unlock;
244 memcpy (de->name, name, namelen); 281 memcpy (namx, name, namelen);
245 memset (de->name + namelen, 0, sbi->s_dirsize - namelen - 2); 282 if (sbi->s_version == MINIX_V3) {
246 de->inode = inode->i_ino; 283 memset (namx + namelen, 0, sbi->s_dirsize - namelen - 4);
284 de3->inode = inode->i_ino;
285 } else {
286 memset (namx + namelen, 0, sbi->s_dirsize - namelen - 2);
287 de->inode = inode->i_ino;
288 }
247 err = dir_commit_chunk(page, from, to); 289 err = dir_commit_chunk(page, from, to);
248 dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; 290 dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
249 mark_inode_dirty(dir); 291 mark_inode_dirty(dir);
@@ -283,8 +325,7 @@ int minix_make_empty(struct inode *inode, struct inode *dir)
283{ 325{
284 struct address_space *mapping = inode->i_mapping; 326 struct address_space *mapping = inode->i_mapping;
285 struct page *page = grab_cache_page(mapping, 0); 327 struct page *page = grab_cache_page(mapping, 0);
286 struct minix_sb_info * sbi = minix_sb(inode->i_sb); 328 struct minix_sb_info *sbi = minix_sb(inode->i_sb);
287 struct minix_dir_entry * de;
288 char *kaddr; 329 char *kaddr;
289 int err; 330 int err;
290 331
@@ -299,12 +340,23 @@ int minix_make_empty(struct inode *inode, struct inode *dir)
299 kaddr = kmap_atomic(page, KM_USER0); 340 kaddr = kmap_atomic(page, KM_USER0);
300 memset(kaddr, 0, PAGE_CACHE_SIZE); 341 memset(kaddr, 0, PAGE_CACHE_SIZE);
301 342
302 de = (struct minix_dir_entry *)kaddr; 343 if (sbi->s_version == MINIX_V3) {
303 de->inode = inode->i_ino; 344 minix3_dirent *de3 = (minix3_dirent *)kaddr;
304 strcpy(de->name,"."); 345
305 de = minix_next_entry(de, sbi); 346 de3->inode = inode->i_ino;
306 de->inode = dir->i_ino; 347 strcpy(de3->name, ".");
307 strcpy(de->name,".."); 348 de3 = minix_next_entry(de3, sbi);
349 de3->inode = dir->i_ino;
350 strcpy(de3->name, "..");
351 } else {
352 minix_dirent *de = (minix_dirent *)kaddr;
353
354 de->inode = inode->i_ino;
355 strcpy(de->name, ".");
356 de = minix_next_entry(de, sbi);
357 de->inode = dir->i_ino;
358 strcpy(de->name, "..");
359 }
308 kunmap_atomic(kaddr, KM_USER0); 360 kunmap_atomic(kaddr, KM_USER0);
309 361
310 err = dir_commit_chunk(page, 0, 2 * sbi->s_dirsize); 362 err = dir_commit_chunk(page, 0, 2 * sbi->s_dirsize);
@@ -321,33 +373,41 @@ int minix_empty_dir(struct inode * inode)
321 struct page *page = NULL; 373 struct page *page = NULL;
322 unsigned long i, npages = dir_pages(inode); 374 unsigned long i, npages = dir_pages(inode);
323 struct minix_sb_info *sbi = minix_sb(inode->i_sb); 375 struct minix_sb_info *sbi = minix_sb(inode->i_sb);
376 char *name;
377 __u32 inumber;
324 378
325 for (i = 0; i < npages; i++) { 379 for (i = 0; i < npages; i++) {
326 char *kaddr; 380 char *p, *kaddr, *limit;
327 minix_dirent * de;
328 page = dir_get_page(inode, i);
329 381
382 page = dir_get_page(inode, i);
330 if (IS_ERR(page)) 383 if (IS_ERR(page))
331 continue; 384 continue;
332 385
333 kaddr = (char *)page_address(page); 386 kaddr = (char *)page_address(page);
334 de = (minix_dirent *)kaddr; 387 limit = kaddr + minix_last_byte(inode, i) - sbi->s_dirsize;
335 kaddr += minix_last_byte(inode, i) - sbi->s_dirsize; 388 for (p = kaddr; p <= limit; p = minix_next_entry(p, sbi)) {
389 if (sbi->s_version == MINIX_V3) {
390 minix3_dirent *de3 = (minix3_dirent *)p;
391 name = de3->name;
392 inumber = de3->inode;
393 } else {
394 minix_dirent *de = (minix_dirent *)p;
395 name = de->name;
396 inumber = de->inode;
397 }
336 398
337 while ((char *)de <= kaddr) { 399 if (inumber != 0) {
338 if (de->inode != 0) {
339 /* check for . and .. */ 400 /* check for . and .. */
340 if (de->name[0] != '.') 401 if (name[0] != '.')
341 goto not_empty; 402 goto not_empty;
342 if (!de->name[1]) { 403 if (!name[1]) {
343 if (de->inode != inode->i_ino) 404 if (inumber != inode->i_ino)
344 goto not_empty; 405 goto not_empty;
345 } else if (de->name[1] != '.') 406 } else if (name[1] != '.')
346 goto not_empty; 407 goto not_empty;
347 else if (de->name[2]) 408 else if (name[2])
348 goto not_empty; 409 goto not_empty;
349 } 410 }
350 de = minix_next_entry(de, sbi);
351 } 411 }
352 dir_put_page(page); 412 dir_put_page(page);
353 } 413 }
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index 629e09b38c5c..9ddfcc148287 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -7,6 +7,7 @@
7 * Minix V2 fs support. 7 * Minix V2 fs support.
8 * 8 *
9 * Modified for 680x0 by Andreas Schwab 9 * Modified for 680x0 by Andreas Schwab
10 * Updated to filesystem version 3 by Daniel Aragones
10 */ 11 */
11 12
12#include <linux/module.h> 13#include <linux/module.h>
@@ -36,7 +37,8 @@ static void minix_put_super(struct super_block *sb)
36 struct minix_sb_info *sbi = minix_sb(sb); 37 struct minix_sb_info *sbi = minix_sb(sb);
37 38
38 if (!(sb->s_flags & MS_RDONLY)) { 39 if (!(sb->s_flags & MS_RDONLY)) {
39 sbi->s_ms->s_state = sbi->s_mount_state; 40 if (sbi->s_version != MINIX_V3) /* s_state is now out from V3 sb */
41 sbi->s_ms->s_state = sbi->s_mount_state;
40 mark_buffer_dirty(sbi->s_sbh); 42 mark_buffer_dirty(sbi->s_sbh);
41 } 43 }
42 for (i = 0; i < sbi->s_imap_blocks; i++) 44 for (i = 0; i < sbi->s_imap_blocks; i++)
@@ -117,12 +119,17 @@ static int minix_remount (struct super_block * sb, int * flags, char * data)
117 !(sbi->s_mount_state & MINIX_VALID_FS)) 119 !(sbi->s_mount_state & MINIX_VALID_FS))
118 return 0; 120 return 0;
119 /* Mounting a rw partition read-only. */ 121 /* Mounting a rw partition read-only. */
120 ms->s_state = sbi->s_mount_state; 122 if (sbi->s_version != MINIX_V3)
123 ms->s_state = sbi->s_mount_state;
121 mark_buffer_dirty(sbi->s_sbh); 124 mark_buffer_dirty(sbi->s_sbh);
122 } else { 125 } else {
123 /* Mount a partition which is read-only, read-write. */ 126 /* Mount a partition which is read-only, read-write. */
124 sbi->s_mount_state = ms->s_state; 127 if (sbi->s_version != MINIX_V3) {
125 ms->s_state &= ~MINIX_VALID_FS; 128 sbi->s_mount_state = ms->s_state;
129 ms->s_state &= ~MINIX_VALID_FS;
130 } else {
131 sbi->s_mount_state = MINIX_VALID_FS;
132 }
126 mark_buffer_dirty(sbi->s_sbh); 133 mark_buffer_dirty(sbi->s_sbh);
127 134
128 if (!(sbi->s_mount_state & MINIX_VALID_FS)) 135 if (!(sbi->s_mount_state & MINIX_VALID_FS))
@@ -140,7 +147,8 @@ static int minix_fill_super(struct super_block *s, void *data, int silent)
140 struct buffer_head *bh; 147 struct buffer_head *bh;
141 struct buffer_head **map; 148 struct buffer_head **map;
142 struct minix_super_block *ms; 149 struct minix_super_block *ms;
143 int i, block; 150 struct minix3_super_block *m3s = NULL;
151 unsigned long i, block;
144 struct inode *root_inode; 152 struct inode *root_inode;
145 struct minix_sb_info *sbi; 153 struct minix_sb_info *sbi;
146 154
@@ -192,6 +200,22 @@ static int minix_fill_super(struct super_block *s, void *data, int silent)
192 sbi->s_dirsize = 32; 200 sbi->s_dirsize = 32;
193 sbi->s_namelen = 30; 201 sbi->s_namelen = 30;
194 sbi->s_link_max = MINIX2_LINK_MAX; 202 sbi->s_link_max = MINIX2_LINK_MAX;
203 } else if ( *(__u16 *)(bh->b_data + 24) == MINIX3_SUPER_MAGIC) {
204 m3s = (struct minix3_super_block *) bh->b_data;
205 s->s_magic = m3s->s_magic;
206 sbi->s_imap_blocks = m3s->s_imap_blocks;
207 sbi->s_zmap_blocks = m3s->s_zmap_blocks;
208 sbi->s_firstdatazone = m3s->s_firstdatazone;
209 sbi->s_log_zone_size = m3s->s_log_zone_size;
210 sbi->s_max_size = m3s->s_max_size;
211 sbi->s_ninodes = m3s->s_ninodes;
212 sbi->s_nzones = m3s->s_zones;
213 sbi->s_dirsize = 64;
214 sbi->s_namelen = 60;
215 sbi->s_version = MINIX_V3;
216 sbi->s_link_max = MINIX2_LINK_MAX;
217 sbi->s_mount_state = MINIX_VALID_FS;
218 sb_set_blocksize(s, m3s->s_blocksize);
195 } else 219 } else
196 goto out_no_fs; 220 goto out_no_fs;
197 221
@@ -236,7 +260,8 @@ static int minix_fill_super(struct super_block *s, void *data, int silent)
236 s->s_root->d_op = &minix_dentry_operations; 260 s->s_root->d_op = &minix_dentry_operations;
237 261
238 if (!(s->s_flags & MS_RDONLY)) { 262 if (!(s->s_flags & MS_RDONLY)) {
239 ms->s_state &= ~MINIX_VALID_FS; 263 if (sbi->s_version != MINIX_V3) /* s_state is now out from V3 sb */
264 ms->s_state &= ~MINIX_VALID_FS;
240 mark_buffer_dirty(bh); 265 mark_buffer_dirty(bh);
241 } 266 }
242 if (!(sbi->s_mount_state & MINIX_VALID_FS)) 267 if (!(sbi->s_mount_state & MINIX_VALID_FS))
@@ -278,8 +303,8 @@ out_illegal_sb:
278 303
279out_no_fs: 304out_no_fs:
280 if (!silent) 305 if (!silent)
281 printk("VFS: Can't find a Minix or Minix V2 filesystem " 306 printk("VFS: Can't find a Minix filesystem V1 | V2 | V3 "
282 "on device %s\n", s->s_id); 307 "on device %s.\n", s->s_id);
283out_release: 308out_release:
284 brelse(bh); 309 brelse(bh);
285 goto out; 310 goto out;
@@ -537,12 +562,14 @@ int minix_sync_inode(struct inode * inode)
537 562
538int minix_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) 563int minix_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
539{ 564{
565 struct inode *dir = dentry->d_parent->d_inode;
566 struct super_block *sb = dir->i_sb;
540 generic_fillattr(dentry->d_inode, stat); 567 generic_fillattr(dentry->d_inode, stat);
541 if (INODE_VERSION(dentry->d_inode) == MINIX_V1) 568 if (INODE_VERSION(dentry->d_inode) == MINIX_V1)
542 stat->blocks = (BLOCK_SIZE / 512) * V1_minix_blocks(stat->size); 569 stat->blocks = (BLOCK_SIZE / 512) * V1_minix_blocks(stat->size, sb);
543 else 570 else
544 stat->blocks = (BLOCK_SIZE / 512) * V2_minix_blocks(stat->size); 571 stat->blocks = (sb->s_blocksize / 512) * V2_minix_blocks(stat->size, sb);
545 stat->blksize = BLOCK_SIZE; 572 stat->blksize = sb->s_blocksize;
546 return 0; 573 return 0;
547} 574}
548 575
diff --git a/fs/minix/itree_common.c b/fs/minix/itree_common.c
index 429baf8de105..a731cabf1540 100644
--- a/fs/minix/itree_common.c
+++ b/fs/minix/itree_common.c
@@ -23,7 +23,7 @@ static inline int verify_chain(Indirect *from, Indirect *to)
23 23
24static inline block_t *block_end(struct buffer_head *bh) 24static inline block_t *block_end(struct buffer_head *bh)
25{ 25{
26 return (block_t *)((char*)bh->b_data + BLOCK_SIZE); 26 return (block_t *)((char*)bh->b_data + bh->b_size);
27} 27}
28 28
29static inline Indirect *get_branch(struct inode *inode, 29static inline Indirect *get_branch(struct inode *inode,
@@ -85,7 +85,7 @@ static int alloc_branch(struct inode *inode,
85 branch[n].key = cpu_to_block(nr); 85 branch[n].key = cpu_to_block(nr);
86 bh = sb_getblk(inode->i_sb, parent); 86 bh = sb_getblk(inode->i_sb, parent);
87 lock_buffer(bh); 87 lock_buffer(bh);
88 memset(bh->b_data, 0, BLOCK_SIZE); 88 memset(bh->b_data, 0, bh->b_size);
89 branch[n].bh = bh; 89 branch[n].bh = bh;
90 branch[n].p = (block_t*) bh->b_data + offsets[n]; 90 branch[n].p = (block_t*) bh->b_data + offsets[n];
91 *branch[n].p = branch[n].key; 91 *branch[n].p = branch[n].key;
@@ -292,6 +292,7 @@ static void free_branches(struct inode *inode, block_t *p, block_t *q, int depth
292 292
293static inline void truncate (struct inode * inode) 293static inline void truncate (struct inode * inode)
294{ 294{
295 struct super_block *sb = inode->i_sb;
295 block_t *idata = i_data(inode); 296 block_t *idata = i_data(inode);
296 int offsets[DEPTH]; 297 int offsets[DEPTH];
297 Indirect chain[DEPTH]; 298 Indirect chain[DEPTH];
@@ -301,7 +302,7 @@ static inline void truncate (struct inode * inode)
301 int first_whole; 302 int first_whole;
302 long iblock; 303 long iblock;
303 304
304 iblock = (inode->i_size + BLOCK_SIZE-1) >> 10; 305 iblock = (inode->i_size + sb->s_blocksize -1) >> sb->s_blocksize_bits;
305 block_truncate_page(inode->i_mapping, inode->i_size, get_block); 306 block_truncate_page(inode->i_mapping, inode->i_size, get_block);
306 307
307 n = block_to_path(inode, iblock, offsets); 308 n = block_to_path(inode, iblock, offsets);
@@ -346,15 +347,16 @@ do_indirects:
346 mark_inode_dirty(inode); 347 mark_inode_dirty(inode);
347} 348}
348 349
349static inline unsigned nblocks(loff_t size) 350static inline unsigned nblocks(loff_t size, struct super_block *sb)
350{ 351{
352 int k = sb->s_blocksize_bits - 10;
351 unsigned blocks, res, direct = DIRECT, i = DEPTH; 353 unsigned blocks, res, direct = DIRECT, i = DEPTH;
352 blocks = (size + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS; 354 blocks = (size + sb->s_blocksize - 1) >> (BLOCK_SIZE_BITS + k);
353 res = blocks; 355 res = blocks;
354 while (--i && blocks > direct) { 356 while (--i && blocks > direct) {
355 blocks -= direct; 357 blocks -= direct;
356 blocks += BLOCK_SIZE/sizeof(block_t) - 1; 358 blocks += sb->s_blocksize/sizeof(block_t) - 1;
357 blocks /= BLOCK_SIZE/sizeof(block_t); 359 blocks /= sb->s_blocksize/sizeof(block_t);
358 res += blocks; 360 res += blocks;
359 direct = 1; 361 direct = 1;
360 } 362 }
diff --git a/fs/minix/itree_v1.c b/fs/minix/itree_v1.c
index 656b1347a25b..1a5f3bf0bcec 100644
--- a/fs/minix/itree_v1.c
+++ b/fs/minix/itree_v1.c
@@ -55,7 +55,7 @@ void V1_minix_truncate(struct inode * inode)
55 truncate(inode); 55 truncate(inode);
56} 56}
57 57
58unsigned V1_minix_blocks(loff_t size) 58unsigned V1_minix_blocks(loff_t size, struct super_block *sb)
59{ 59{
60 return nblocks(size); 60 return nblocks(size, sb);
61} 61}
diff --git a/fs/minix/itree_v2.c b/fs/minix/itree_v2.c
index 9adcdc754e0f..ad8f0dec4ef4 100644
--- a/fs/minix/itree_v2.c
+++ b/fs/minix/itree_v2.c
@@ -23,10 +23,11 @@ static inline block_t *i_data(struct inode *inode)
23static int block_to_path(struct inode * inode, long block, int offsets[DEPTH]) 23static int block_to_path(struct inode * inode, long block, int offsets[DEPTH])
24{ 24{
25 int n = 0; 25 int n = 0;
26 struct super_block *sb = inode->i_sb;
26 27
27 if (block < 0) { 28 if (block < 0) {
28 printk("minix_bmap: block<0\n"); 29 printk("minix_bmap: block<0\n");
29 } else if (block >= (minix_sb(inode->i_sb)->s_max_size/BLOCK_SIZE)) { 30 } else if (block >= (minix_sb(inode->i_sb)->s_max_size/sb->s_blocksize)) {
30 printk("minix_bmap: block>big\n"); 31 printk("minix_bmap: block>big\n");
31 } else if (block < 7) { 32 } else if (block < 7) {
32 offsets[n++] = block; 33 offsets[n++] = block;
@@ -60,7 +61,7 @@ void V2_minix_truncate(struct inode * inode)
60 truncate(inode); 61 truncate(inode);
61} 62}
62 63
63unsigned V2_minix_blocks(loff_t size) 64unsigned V2_minix_blocks(loff_t size, struct super_block *sb)
64{ 65{
65 return nblocks(size); 66 return nblocks(size, sb);
66} 67}
diff --git a/fs/minix/minix.h b/fs/minix/minix.h
index c55b77cdcc8e..e016ee91d936 100644
--- a/fs/minix/minix.h
+++ b/fs/minix/minix.h
@@ -7,11 +7,10 @@
7 * truncated. Else they will be disallowed (ENAMETOOLONG). 7 * truncated. Else they will be disallowed (ENAMETOOLONG).
8 */ 8 */
9#define NO_TRUNCATE 1 9#define NO_TRUNCATE 1
10
11#define INODE_VERSION(inode) minix_sb(inode->i_sb)->s_version 10#define INODE_VERSION(inode) minix_sb(inode->i_sb)->s_version
12
13#define MINIX_V1 0x0001 /* original minix fs */ 11#define MINIX_V1 0x0001 /* original minix fs */
14#define MINIX_V2 0x0002 /* minix V2 fs */ 12#define MINIX_V2 0x0002 /* minix V2 fs */
13#define MINIX_V3 0x0003 /* minix V3 fs */
15 14
16/* 15/*
17 * minix fs inode data in memory 16 * minix fs inode data in memory
@@ -52,12 +51,10 @@ extern struct inode * minix_new_inode(const struct inode * dir, int * error);
52extern void minix_free_inode(struct inode * inode); 51extern void minix_free_inode(struct inode * inode);
53extern unsigned long minix_count_free_inodes(struct minix_sb_info *sbi); 52extern unsigned long minix_count_free_inodes(struct minix_sb_info *sbi);
54extern int minix_new_block(struct inode * inode); 53extern int minix_new_block(struct inode * inode);
55extern void minix_free_block(struct inode * inode, int block); 54extern void minix_free_block(struct inode *inode, unsigned long block);
56extern unsigned long minix_count_free_blocks(struct minix_sb_info *sbi); 55extern unsigned long minix_count_free_blocks(struct minix_sb_info *sbi);
57
58extern int minix_getattr(struct vfsmount *, struct dentry *, struct kstat *); 56extern int minix_getattr(struct vfsmount *, struct dentry *, struct kstat *);
59 57
60extern void V2_minix_truncate(struct inode *);
61extern void V1_minix_truncate(struct inode *); 58extern void V1_minix_truncate(struct inode *);
62extern void V2_minix_truncate(struct inode *); 59extern void V2_minix_truncate(struct inode *);
63extern void minix_truncate(struct inode *); 60extern void minix_truncate(struct inode *);
@@ -65,8 +62,8 @@ extern int minix_sync_inode(struct inode *);
65extern void minix_set_inode(struct inode *, dev_t); 62extern void minix_set_inode(struct inode *, dev_t);
66extern int V1_minix_get_block(struct inode *, long, struct buffer_head *, int); 63extern int V1_minix_get_block(struct inode *, long, struct buffer_head *, int);
67extern int V2_minix_get_block(struct inode *, long, struct buffer_head *, int); 64extern int V2_minix_get_block(struct inode *, long, struct buffer_head *, int);
68extern unsigned V1_minix_blocks(loff_t); 65extern unsigned V1_minix_blocks(loff_t, struct super_block *);
69extern unsigned V2_minix_blocks(loff_t); 66extern unsigned V2_minix_blocks(loff_t, struct super_block *);
70 67
71extern struct minix_dir_entry *minix_find_entry(struct dentry*, struct page**); 68extern struct minix_dir_entry *minix_find_entry(struct dentry*, struct page**);
72extern int minix_add_link(struct dentry*, struct inode*); 69extern int minix_add_link(struct dentry*, struct inode*);
@@ -76,7 +73,6 @@ extern int minix_empty_dir(struct inode*);
76extern void minix_set_link(struct minix_dir_entry*, struct page*, struct inode*); 73extern void minix_set_link(struct minix_dir_entry*, struct page*, struct inode*);
77extern struct minix_dir_entry *minix_dotdot(struct inode*, struct page**); 74extern struct minix_dir_entry *minix_dotdot(struct inode*, struct page**);
78extern ino_t minix_inode_by_name(struct dentry*); 75extern ino_t minix_inode_by_name(struct dentry*);
79
80extern int minix_sync_file(struct file *, struct dentry *, int); 76extern int minix_sync_file(struct file *, struct dentry *, int);
81 77
82extern struct inode_operations minix_file_inode_operations; 78extern struct inode_operations minix_file_inode_operations;
diff --git a/include/linux/magic.h b/include/linux/magic.h
index b78bbf42135a..b32c8a97fcec 100644
--- a/include/linux/magic.h
+++ b/include/linux/magic.h
@@ -18,6 +18,7 @@
18#define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */ 18#define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */
19#define MINIX2_SUPER_MAGIC 0x2468 /* minix V2 fs */ 19#define MINIX2_SUPER_MAGIC 0x2468 /* minix V2 fs */
20#define MINIX2_SUPER_MAGIC2 0x2478 /* minix V2 fs, 30 char names */ 20#define MINIX2_SUPER_MAGIC2 0x2478 /* minix V2 fs, 30 char names */
21#define MINIX3_SUPER_MAGIC 0x4d5a /* minix V3 fs */
21 22
22#define MSDOS_SUPER_MAGIC 0x4d44 /* MD */ 23#define MSDOS_SUPER_MAGIC 0x4d44 /* MD */
23#define NCP_SUPER_MAGIC 0x564c /* Guess, what 0x564c is :-) */ 24#define NCP_SUPER_MAGIC 0x564c /* Guess, what 0x564c is :-) */
diff --git a/include/linux/minix_fs.h b/include/linux/minix_fs.h
index 916e8f72c63d..9850d513ff60 100644
--- a/include/linux/minix_fs.h
+++ b/include/linux/minix_fs.h
@@ -25,7 +25,6 @@
25#define MINIX_ERROR_FS 0x0002 /* fs has errors. */ 25#define MINIX_ERROR_FS 0x0002 /* fs has errors. */
26 26
27#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode))) 27#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
28#define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode)))
29 28
30/* 29/*
31 * This is the original minix inode layout on disk. 30 * This is the original minix inode layout on disk.
@@ -75,9 +74,33 @@ struct minix_super_block {
75 __u32 s_zones; 74 __u32 s_zones;
76}; 75};
77 76
77/*
78 * V3 minix super-block data on disk
79 */
80struct minix3_super_block {
81 __u16 s_ninodes;
82 __u16 s_nzones;
83 __u16 s_pad0;
84 __u16 s_imap_blocks;
85 __u16 s_zmap_blocks;
86 __u16 s_firstdatazone;
87 __u16 s_log_zone_size;
88 __u16 s_pad1;
89 __u32 s_max_size;
90 __u32 s_zones;
91 __u16 s_magic;
92 __u16 s_pad2;
93 __u16 s_blocksize;
94 __u8 s_disk_version;
95};
96
78struct minix_dir_entry { 97struct minix_dir_entry {
79 __u16 inode; 98 __u16 inode;
80 char name[0]; 99 char name[0];
81}; 100};
82 101
102struct minix3_dir_entry {
103 __u32 inode;
104 char name[0];
105};
83#endif 106#endif