aboutsummaryrefslogtreecommitdiffstats
path: root/fs/minix
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /fs/minix
Linux-2.6.12-rc2v2.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 @@
1#
2# Makefile for the Linux minix filesystem routines.
3#
4
5obj-$(CONFIG_MINIX_FS) += minix.o
6
7minix-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 @@
1/*
2 * linux/fs/minix/bitmap.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
6
7/*
8 * Modified for 680x0 by Hamish Macdonald
9 * Fixed for 680x0 by Andreas Schwab
10 */
11
12/* bitmap.c contains the code that handles the inode and block bitmaps */
13
14#include "minix.h"
15#include <linux/smp_lock.h>
16#include <linux/buffer_head.h>
17#include <linux/bitops.h>
18
19static int nibblemap[] = { 4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0 };
20
21static unsigned long count_free(struct buffer_head *map[], unsigned numblocks, __u32 numbits)
22{
23 unsigned i, j, sum = 0;
24 struct buffer_head *bh;
25
26 for (i=0; i<numblocks-1; i++) {
27 if (!(bh=map[i]))
28 return(0);
29 for (j=0; j<BLOCK_SIZE; j++)
30 sum += nibblemap[bh->b_data[j] & 0xf]
31 + nibblemap[(bh->b_data[j]>>4) & 0xf];
32 }
33
34 if (numblocks==0 || !(bh=map[numblocks-1]))
35 return(0);
36 i = ((numbits-(numblocks-1)*BLOCK_SIZE*8)/16)*2;
37 for (j=0; j<i; j++) {
38 sum += nibblemap[bh->b_data[j] & 0xf]
39 + nibblemap[(bh->b_data[j]>>4) & 0xf];
40 }
41
42 i = numbits%16;
43 if (i!=0) {
44 i = *(__u16 *)(&bh->b_data[j]) | ~((1<<i) - 1);
45 sum += nibblemap[i & 0xf] + nibblemap[(i>>4) & 0xf];
46 sum += nibblemap[(i>>8) & 0xf] + nibblemap[(i>>12) & 0xf];
47 }
48 return(sum);
49}
50
51void minix_free_block(struct inode * inode, int block)
52{
53 struct super_block * sb = inode->i_sb;
54 struct minix_sb_info * sbi = minix_sb(sb);
55 struct buffer_head * bh;
56 unsigned int bit,zone;
57
58 if (block < sbi->s_firstdatazone || block >= sbi->s_nzones) {
59 printk("trying to free block not in datazone\n");
60 return;
61 }
62 zone = block - sbi->s_firstdatazone + 1;
63 bit = zone & 8191;
64 zone >>= 13;
65 if (zone >= sbi->s_zmap_blocks) {
66 printk("minix_free_block: nonexistent bitmap buffer\n");
67 return;
68 }
69 bh = sbi->s_zmap[zone];
70 lock_kernel();
71 if (!minix_test_and_clear_bit(bit,bh->b_data))
72 printk("free_block (%s:%d): bit already cleared\n",
73 sb->s_id, block);
74 unlock_kernel();
75 mark_buffer_dirty(bh);
76 return;
77}
78
79int minix_new_block(struct inode * inode)
80{
81 struct minix_sb_info *sbi = minix_sb(inode->i_sb);
82 int i;
83
84 for (i = 0; i < sbi->s_zmap_blocks; i++) {
85 struct buffer_head *bh = sbi->s_zmap[i];
86 int j;
87
88 lock_kernel();
89 if ((j = minix_find_first_zero_bit(bh->b_data, 8192)) < 8192) {
90 minix_set_bit(j,bh->b_data);
91 unlock_kernel();
92 mark_buffer_dirty(bh);
93 j += i*8192 + sbi->s_firstdatazone-1;
94 if (j < sbi->s_firstdatazone || j >= sbi->s_nzones)
95 break;
96 return j;
97 }
98 unlock_kernel();
99 }
100 return 0;
101}
102
103unsigned long minix_count_free_blocks(struct minix_sb_info *sbi)
104{
105 return (count_free(sbi->s_zmap, sbi->s_zmap_blocks,
106 sbi->s_nzones - sbi->s_firstdatazone + 1)
107 << sbi->s_log_zone_size);
108}
109
110struct minix_inode *
111minix_V1_raw_inode(struct super_block *sb, ino_t ino, struct buffer_head **bh)
112{
113 int block;
114 struct minix_sb_info *sbi = minix_sb(sb);
115 struct minix_inode *p;
116
117 if (!ino || ino > sbi->s_ninodes) {
118 printk("Bad inode number on dev %s: %ld is out of range\n",
119 sb->s_id, (long)ino);
120 return NULL;
121 }
122 ino--;
123 block = 2 + sbi->s_imap_blocks + sbi->s_zmap_blocks +
124 ino / MINIX_INODES_PER_BLOCK;
125 *bh = sb_bread(sb, block);
126 if (!*bh) {
127 printk("unable to read i-node block\n");
128 return NULL;
129 }
130 p = (void *)(*bh)->b_data;
131 return p + ino % MINIX_INODES_PER_BLOCK;
132}
133
134struct minix2_inode *
135minix_V2_raw_inode(struct super_block *sb, ino_t ino, struct buffer_head **bh)
136{
137 int block;
138 struct minix_sb_info *sbi = minix_sb(sb);
139 struct minix2_inode *p;
140
141 *bh = NULL;
142 if (!ino || ino > sbi->s_ninodes) {
143 printk("Bad inode number on dev %s: %ld is out of range\n",
144 sb->s_id, (long)ino);
145 return NULL;
146 }
147 ino--;
148 block = 2 + sbi->s_imap_blocks + sbi->s_zmap_blocks +
149 ino / MINIX2_INODES_PER_BLOCK;
150 *bh = sb_bread(sb, block);
151 if (!*bh) {
152 printk("unable to read i-node block\n");
153 return NULL;
154 }
155 p = (void *)(*bh)->b_data;
156 return p + ino % MINIX2_INODES_PER_BLOCK;
157}
158
159/* Clear the link count and mode of a deleted inode on disk. */
160
161static void minix_clear_inode(struct inode *inode)
162{
163 struct buffer_head *bh = NULL;
164
165 if (INODE_VERSION(inode) == MINIX_V1) {
166 struct minix_inode *raw_inode;
167 raw_inode = minix_V1_raw_inode(inode->i_sb, inode->i_ino, &bh);
168 if (raw_inode) {
169 raw_inode->i_nlinks = 0;
170 raw_inode->i_mode = 0;
171 }
172 } else {
173 struct minix2_inode *raw_inode;
174 raw_inode = minix_V2_raw_inode(inode->i_sb, inode->i_ino, &bh);
175 if (raw_inode) {
176 raw_inode->i_nlinks = 0;
177 raw_inode->i_mode = 0;
178 }
179 }
180 if (bh) {
181 mark_buffer_dirty(bh);
182 brelse (bh);
183 }
184}
185
186void minix_free_inode(struct inode * inode)
187{
188 struct minix_sb_info *sbi = minix_sb(inode->i_sb);
189 struct buffer_head * bh;
190 unsigned long ino;
191
192 ino = inode->i_ino;
193 if (ino < 1 || ino > sbi->s_ninodes) {
194 printk("minix_free_inode: inode 0 or nonexistent inode\n");
195 goto out;
196 }
197 if ((ino >> 13) >= sbi->s_imap_blocks) {
198 printk("minix_free_inode: nonexistent imap in superblock\n");
199 goto out;
200 }
201
202 minix_clear_inode(inode); /* clear on-disk copy */
203
204 bh = sbi->s_imap[ino >> 13];
205 lock_kernel();
206 if (!minix_test_and_clear_bit(ino & 8191, bh->b_data))
207 printk("minix_free_inode: bit %lu already cleared.\n", ino);
208 unlock_kernel();
209 mark_buffer_dirty(bh);
210 out:
211 clear_inode(inode); /* clear in-memory copy */
212}
213
214struct inode * minix_new_inode(const struct inode * dir, int * error)
215{
216 struct super_block *sb = dir->i_sb;
217 struct minix_sb_info *sbi = minix_sb(sb);
218 struct inode *inode = new_inode(sb);
219 struct buffer_head * bh;
220 int i,j;
221
222 if (!inode) {
223 *error = -ENOMEM;
224 return NULL;
225 }
226 j = 8192;
227 bh = NULL;
228 *error = -ENOSPC;
229 lock_kernel();
230 for (i = 0; i < sbi->s_imap_blocks; i++) {
231 bh = sbi->s_imap[i];
232 if ((j = minix_find_first_zero_bit(bh->b_data, 8192)) < 8192)
233 break;
234 }
235 if (!bh || j >= 8192) {
236 unlock_kernel();
237 iput(inode);
238 return NULL;
239 }
240 if (minix_test_and_set_bit(j,bh->b_data)) { /* shouldn't happen */
241 printk("new_inode: bit already set");
242 unlock_kernel();
243 iput(inode);
244 return NULL;
245 }
246 unlock_kernel();
247 mark_buffer_dirty(bh);
248 j += i*8192;
249 if (!j || j > sbi->s_ninodes) {
250 iput(inode);
251 return NULL;
252 }
253 inode->i_uid = current->fsuid;
254 inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
255 inode->i_ino = j;
256 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
257 inode->i_blocks = inode->i_blksize = 0;
258 memset(&minix_i(inode)->u, 0, sizeof(minix_i(inode)->u));
259 insert_inode_hash(inode);
260 mark_inode_dirty(inode);
261
262 *error = 0;
263 return inode;
264}
265
266unsigned long minix_count_free_inodes(struct minix_sb_info *sbi)
267{
268 return count_free(sbi->s_imap, sbi->s_imap_blocks, sbi->s_ninodes + 1);
269}
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 @@
1/*
2 * linux/fs/minix/dir.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 *
6 * minix directory handling functions
7 */
8
9#include "minix.h"
10#include <linux/highmem.h>
11#include <linux/smp_lock.h>
12
13typedef struct minix_dir_entry minix_dirent;
14
15static int minix_readdir(struct file *, void *, filldir_t);
16
17struct file_operations minix_dir_operations = {
18 .read = generic_read_dir,
19 .readdir = minix_readdir,
20 .fsync = minix_sync_file,
21};
22
23static inline void dir_put_page(struct page *page)
24{
25 kunmap(page);
26 page_cache_release(page);
27}
28
29/*
30 * Return the offset into page `page_nr' of the last valid
31 * byte in that page, plus one.
32 */
33static unsigned
34minix_last_byte(struct inode *inode, unsigned long page_nr)
35{
36 unsigned last_byte = PAGE_CACHE_SIZE;
37
38 if (page_nr == (inode->i_size >> PAGE_CACHE_SHIFT))
39 last_byte = inode->i_size & (PAGE_CACHE_SIZE - 1);
40 return last_byte;
41}
42
43static inline unsigned long dir_pages(struct inode *inode)
44{
45 return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT;
46}
47
48static int dir_commit_chunk(struct page *page, unsigned from, unsigned to)
49{
50 struct inode *dir = (struct inode *)page->mapping->host;
51 int err = 0;
52 page->mapping->a_ops->commit_write(NULL, page, from, to);
53 if (IS_DIRSYNC(dir))
54 err = write_one_page(page, 1);
55 else
56 unlock_page(page);
57 return err;
58}
59
60static struct page * dir_get_page(struct inode *dir, unsigned long n)
61{
62 struct address_space *mapping = dir->i_mapping;
63 struct page *page = read_cache_page(mapping, n,
64 (filler_t*)mapping->a_ops->readpage, NULL);
65 if (!IS_ERR(page)) {
66 wait_on_page_locked(page);
67 kmap(page);
68 if (!PageUptodate(page))
69 goto fail;
70 }
71 return page;
72
73fail:
74 dir_put_page(page);
75 return ERR_PTR(-EIO);
76}
77
78static inline void *minix_next_entry(void *de, struct minix_sb_info *sbi)
79{
80 return (void*)((char*)de + sbi->s_dirsize);
81}
82
83static int minix_readdir(struct file * filp, void * dirent, filldir_t filldir)
84{
85 unsigned long pos = filp->f_pos;
86 struct inode *inode = filp->f_dentry->d_inode;
87 struct super_block *sb = inode->i_sb;
88 unsigned offset = pos & ~PAGE_CACHE_MASK;
89 unsigned long n = pos >> PAGE_CACHE_SHIFT;
90 unsigned long npages = dir_pages(inode);
91 struct minix_sb_info *sbi = minix_sb(sb);
92 unsigned chunk_size = sbi->s_dirsize;
93
94 lock_kernel();
95
96 pos = (pos + chunk_size-1) & ~(chunk_size-1);
97 if (pos >= inode->i_size)
98 goto done;
99
100 for ( ; n < npages; n++, offset = 0) {
101 char *p, *kaddr, *limit;
102 struct page *page = dir_get_page(inode, n);
103
104 if (IS_ERR(page))
105 continue;
106 kaddr = (char *)page_address(page);
107 p = kaddr+offset;
108 limit = kaddr + minix_last_byte(inode, n) - chunk_size;
109 for ( ; p <= limit ; p = minix_next_entry(p, sbi)) {
110 minix_dirent *de = (minix_dirent *)p;
111 if (de->inode) {
112 int over;
113 unsigned l = strnlen(de->name,sbi->s_namelen);
114
115 offset = p - kaddr;
116 over = filldir(dirent, de->name, l,
117 (n<<PAGE_CACHE_SHIFT) | offset,
118 de->inode, DT_UNKNOWN);
119 if (over) {
120 dir_put_page(page);
121 goto done;
122 }
123 }
124 }
125 dir_put_page(page);
126 }
127
128done:
129 filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset;
130 unlock_kernel();
131 return 0;
132}
133
134static inline int namecompare(int len, int maxlen,
135 const char * name, const char * buffer)
136{
137 if (len < maxlen && buffer[len])
138 return 0;
139 return !memcmp(name, buffer, len);
140}
141
142/*
143 * minix_find_entry()
144 *
145 * finds an entry in the specified directory with the wanted name. It
146 * returns the cache buffer in which the entry was found, and the entry
147 * itself (as a parameter - res_dir). It does NOT read the inode of the
148 * entry - you'll have to do that yourself if you want to.
149 */
150minix_dirent *minix_find_entry(struct dentry *dentry, struct page **res_page)
151{
152 const char * name = dentry->d_name.name;
153 int namelen = dentry->d_name.len;
154 struct inode * dir = dentry->d_parent->d_inode;
155 struct super_block * sb = dir->i_sb;
156 struct minix_sb_info * sbi = minix_sb(sb);
157 unsigned long n;
158 unsigned long npages = dir_pages(dir);
159 struct page *page = NULL;
160 struct minix_dir_entry *de;
161
162 *res_page = NULL;
163
164 for (n = 0; n < npages; n++) {
165 char *kaddr;
166 page = dir_get_page(dir, n);
167 if (IS_ERR(page))
168 continue;
169
170 kaddr = (char*)page_address(page);
171 de = (struct minix_dir_entry *) kaddr;
172 kaddr += minix_last_byte(dir, n) - sbi->s_dirsize;
173 for ( ; (char *) de <= kaddr ; de = minix_next_entry(de,sbi)) {
174 if (!de->inode)
175 continue;
176 if (namecompare(namelen,sbi->s_namelen,name,de->name))
177 goto found;
178 }
179 dir_put_page(page);
180 }
181 return NULL;
182
183found:
184 *res_page = page;
185 return de;
186}
187
188int minix_add_link(struct dentry *dentry, struct inode *inode)
189{
190 struct inode *dir = dentry->d_parent->d_inode;
191 const char * name = dentry->d_name.name;
192 int namelen = dentry->d_name.len;
193 struct super_block * sb = dir->i_sb;
194 struct minix_sb_info * sbi = minix_sb(sb);
195 struct page *page = NULL;
196 struct minix_dir_entry * de;
197 unsigned long npages = dir_pages(dir);
198 unsigned long n;
199 char *kaddr;
200 unsigned from, to;
201 int err;
202
203 /*
204 * We take care of directory expansion in the same loop
205 * This code plays outside i_size, so it locks the page
206 * to protect that region.
207 */
208 for (n = 0; n <= npages; n++) {
209 char *dir_end;
210
211 page = dir_get_page(dir, n);
212 err = PTR_ERR(page);
213 if (IS_ERR(page))
214 goto out;
215 lock_page(page);
216 kaddr = (char*)page_address(page);
217 dir_end = kaddr + minix_last_byte(dir, n);
218 de = (minix_dirent *)kaddr;
219 kaddr += PAGE_CACHE_SIZE - sbi->s_dirsize;
220 while ((char *)de <= kaddr) {
221 if ((char *)de == dir_end) {
222 /* We hit i_size */
223 de->inode = 0;
224 goto got_it;
225 }
226 if (!de->inode)
227 goto got_it;
228 err = -EEXIST;
229 if (namecompare(namelen,sbi->s_namelen,name,de->name))
230 goto out_unlock;
231 de = minix_next_entry(de, sbi);
232 }
233 unlock_page(page);
234 dir_put_page(page);
235 }
236 BUG();
237 return -EINVAL;
238
239got_it:
240 from = (char*)de - (char*)page_address(page);
241 to = from + sbi->s_dirsize;
242 err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
243 if (err)
244 goto out_unlock;
245 memcpy (de->name, name, namelen);
246 memset (de->name + namelen, 0, sbi->s_dirsize - namelen - 2);
247 de->inode = inode->i_ino;
248 err = dir_commit_chunk(page, from, to);
249 dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
250 mark_inode_dirty(dir);
251out_put:
252 dir_put_page(page);
253out:
254 return err;
255out_unlock:
256 unlock_page(page);
257 goto out_put;
258}
259
260int minix_delete_entry(struct minix_dir_entry *de, struct page *page)
261{
262 struct address_space *mapping = page->mapping;
263 struct inode *inode = (struct inode*)mapping->host;
264 char *kaddr = page_address(page);
265 unsigned from = (char*)de - kaddr;
266 unsigned to = from + minix_sb(inode->i_sb)->s_dirsize;
267 int err;
268
269 lock_page(page);
270 err = mapping->a_ops->prepare_write(NULL, page, from, to);
271 if (err == 0) {
272 de->inode = 0;
273 err = dir_commit_chunk(page, from, to);
274 } else {
275 unlock_page(page);
276 }
277 dir_put_page(page);
278 inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
279 mark_inode_dirty(inode);
280 return err;
281}
282
283int minix_make_empty(struct inode *inode, struct inode *dir)
284{
285 struct address_space *mapping = inode->i_mapping;
286 struct page *page = grab_cache_page(mapping, 0);
287 struct minix_sb_info * sbi = minix_sb(inode->i_sb);
288 struct minix_dir_entry * de;
289 char *kaddr;
290 int err;
291
292 if (!page)
293 return -ENOMEM;
294 err = mapping->a_ops->prepare_write(NULL, page, 0, 2 * sbi->s_dirsize);
295 if (err) {
296 unlock_page(page);
297 goto fail;
298 }
299
300 kaddr = kmap_atomic(page, KM_USER0);
301 memset(kaddr, 0, PAGE_CACHE_SIZE);
302
303 de = (struct minix_dir_entry *)kaddr;
304 de->inode = inode->i_ino;
305 strcpy(de->name,".");
306 de = minix_next_entry(de, sbi);
307 de->inode = dir->i_ino;
308 strcpy(de->name,"..");
309 kunmap_atomic(kaddr, KM_USER0);
310
311 err = dir_commit_chunk(page, 0, 2 * sbi->s_dirsize);
312fail:
313 page_cache_release(page);
314 return err;
315}
316
317/*
318 * routine to check that the specified directory is empty (for rmdir)
319 */
320int minix_empty_dir(struct inode * inode)
321{
322 struct page *page = NULL;
323 unsigned long i, npages = dir_pages(inode);
324 struct minix_sb_info *sbi = minix_sb(inode->i_sb);
325
326 for (i = 0; i < npages; i++) {
327 char *kaddr;
328 minix_dirent * de;
329 page = dir_get_page(inode, i);
330
331 if (IS_ERR(page))
332 continue;
333
334 kaddr = (char *)page_address(page);
335 de = (minix_dirent *)kaddr;
336 kaddr += minix_last_byte(inode, i) - sbi->s_dirsize;
337
338 while ((char *)de <= kaddr) {
339 if (de->inode != 0) {
340 /* check for . and .. */
341 if (de->name[0] != '.')
342 goto not_empty;
343 if (!de->name[1]) {
344 if (de->inode != inode->i_ino)
345 goto not_empty;
346 } else if (de->name[1] != '.')
347 goto not_empty;
348 else if (de->name[2])
349 goto not_empty;
350 }
351 de = minix_next_entry(de, sbi);
352 }
353 dir_put_page(page);
354 }
355 return 1;
356
357not_empty:
358 dir_put_page(page);
359 return 0;
360}
361
362/* Releases the page */
363void minix_set_link(struct minix_dir_entry *de, struct page *page,
364 struct inode *inode)
365{
366 struct inode *dir = (struct inode*)page->mapping->host;
367 struct minix_sb_info *sbi = minix_sb(dir->i_sb);
368 unsigned from = (char *)de-(char*)page_address(page);
369 unsigned to = from + sbi->s_dirsize;
370 int err;
371
372 lock_page(page);
373 err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
374 if (err == 0) {
375 de->inode = inode->i_ino;
376 err = dir_commit_chunk(page, from, to);
377 } else {
378 unlock_page(page);
379 }
380 dir_put_page(page);
381 dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
382 mark_inode_dirty(dir);
383}
384
385struct minix_dir_entry * minix_dotdot (struct inode *dir, struct page **p)
386{
387 struct page *page = dir_get_page(dir, 0);
388 struct minix_sb_info *sbi = minix_sb(dir->i_sb);
389 struct minix_dir_entry *de = NULL;
390
391 if (!IS_ERR(page)) {
392 de = minix_next_entry(page_address(page), sbi);
393 *p = page;
394 }
395 return de;
396}
397
398ino_t minix_inode_by_name(struct dentry *dentry)
399{
400 struct page *page;
401 struct minix_dir_entry *de = minix_find_entry(dentry, &page);
402 ino_t res = 0;
403
404 if (de) {
405 res = de->inode;
406 dir_put_page(page);
407 }
408 return res;
409}
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 @@
1/*
2 * linux/fs/minix/file.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 *
6 * minix regular file handling primitives
7 */
8
9#include <linux/buffer_head.h> /* for fsync_inode_buffers() */
10#include "minix.h"
11
12/*
13 * We have mostly NULLs here: the current defaults are OK for
14 * the minix filesystem.
15 */
16int minix_sync_file(struct file *, struct dentry *, int);
17
18struct file_operations minix_file_operations = {
19 .llseek = generic_file_llseek,
20 .read = generic_file_read,
21 .write = generic_file_write,
22 .mmap = generic_file_mmap,
23 .fsync = minix_sync_file,
24 .sendfile = generic_file_sendfile,
25};
26
27struct inode_operations minix_file_inode_operations = {
28 .truncate = minix_truncate,
29 .getattr = minix_getattr,
30};
31
32int minix_sync_file(struct file * file, struct dentry *dentry, int datasync)
33{
34 struct inode *inode = dentry->d_inode;
35 int err;
36
37 err = sync_mapping_buffers(inode->i_mapping);
38 if (!(inode->i_state & I_DIRTY))
39 return err;
40 if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
41 return err;
42
43 err |= minix_sync_inode(inode);
44 return err ? -EIO : 0;
45}
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 @@
1/*
2 * linux/fs/minix/inode.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 *
6 * Copyright (C) 1996 Gertjan van Wingerde (gertjan@cs.vu.nl)
7 * Minix V2 fs support.
8 *
9 * Modified for 680x0 by Andreas Schwab
10 */
11
12#include <linux/module.h>
13#include "minix.h"
14#include <linux/buffer_head.h>
15#include <linux/slab.h>
16#include <linux/init.h>
17#include <linux/highuid.h>
18#include <linux/vfs.h>
19
20static void minix_read_inode(struct inode * inode);
21static int minix_write_inode(struct inode * inode, int wait);
22static int minix_statfs(struct super_block *sb, struct kstatfs *buf);
23static int minix_remount (struct super_block * sb, int * flags, char * data);
24
25static void minix_delete_inode(struct inode *inode)
26{
27 inode->i_size = 0;
28 minix_truncate(inode);
29 minix_free_inode(inode);
30}
31
32static void minix_put_super(struct super_block *sb)
33{
34 int i;
35 struct minix_sb_info *sbi = minix_sb(sb);
36
37 if (!(sb->s_flags & MS_RDONLY)) {
38 sbi->s_ms->s_state = sbi->s_mount_state;
39 mark_buffer_dirty(sbi->s_sbh);
40 }
41 for (i = 0; i < sbi->s_imap_blocks; i++)
42 brelse(sbi->s_imap[i]);
43 for (i = 0; i < sbi->s_zmap_blocks; i++)
44 brelse(sbi->s_zmap[i]);
45 brelse (sbi->s_sbh);
46 kfree(sbi->s_imap);
47 sb->s_fs_info = NULL;
48 kfree(sbi);
49
50 return;
51}
52
53static kmem_cache_t * minix_inode_cachep;
54
55static struct inode *minix_alloc_inode(struct super_block *sb)
56{
57 struct minix_inode_info *ei;
58 ei = (struct minix_inode_info *)kmem_cache_alloc(minix_inode_cachep, SLAB_KERNEL);
59 if (!ei)
60 return NULL;
61 return &ei->vfs_inode;
62}
63
64static void minix_destroy_inode(struct inode *inode)
65{
66 kmem_cache_free(minix_inode_cachep, minix_i(inode));
67}
68
69static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
70{
71 struct minix_inode_info *ei = (struct minix_inode_info *) foo;
72
73 if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
74 SLAB_CTOR_CONSTRUCTOR)
75 inode_init_once(&ei->vfs_inode);
76}
77
78static int init_inodecache(void)
79{
80 minix_inode_cachep = kmem_cache_create("minix_inode_cache",
81 sizeof(struct minix_inode_info),
82 0, SLAB_RECLAIM_ACCOUNT,
83 init_once, NULL);
84 if (minix_inode_cachep == NULL)
85 return -ENOMEM;
86 return 0;
87}
88
89static void destroy_inodecache(void)
90{
91 if (kmem_cache_destroy(minix_inode_cachep))
92 printk(KERN_INFO "minix_inode_cache: not all structures were freed\n");
93}
94
95static struct super_operations minix_sops = {
96 .alloc_inode = minix_alloc_inode,
97 .destroy_inode = minix_destroy_inode,
98 .read_inode = minix_read_inode,
99 .write_inode = minix_write_inode,
100 .delete_inode = minix_delete_inode,
101 .put_super = minix_put_super,
102 .statfs = minix_statfs,
103 .remount_fs = minix_remount,
104};
105
106static int minix_remount (struct super_block * sb, int * flags, char * data)
107{
108 struct minix_sb_info * sbi = minix_sb(sb);
109 struct minix_super_block * ms;
110
111 ms = sbi->s_ms;
112 if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
113 return 0;
114 if (*flags & MS_RDONLY) {
115 if (ms->s_state & MINIX_VALID_FS ||
116 !(sbi->s_mount_state & MINIX_VALID_FS))
117 return 0;
118 /* Mounting a rw partition read-only. */
119 ms->s_state = sbi->s_mount_state;
120 mark_buffer_dirty(sbi->s_sbh);
121 } else {
122 /* Mount a partition which is read-only, read-write. */
123 sbi->s_mount_state = ms->s_state;
124 ms->s_state &= ~MINIX_VALID_FS;
125 mark_buffer_dirty(sbi->s_sbh);
126
127 if (!(sbi->s_mount_state & MINIX_VALID_FS))
128 printk ("MINIX-fs warning: remounting unchecked fs, "
129 "running fsck is recommended.\n");
130 else if ((sbi->s_mount_state & MINIX_ERROR_FS))
131 printk ("MINIX-fs warning: remounting fs with errors, "
132 "running fsck is recommended.\n");
133 }
134 return 0;
135}
136
137static int minix_fill_super(struct super_block *s, void *data, int silent)
138{
139 struct buffer_head *bh;
140 struct buffer_head **map;
141 struct minix_super_block *ms;
142 int i, block;
143 struct inode *root_inode;
144 struct minix_sb_info *sbi;
145
146 sbi = kmalloc(sizeof(struct minix_sb_info), GFP_KERNEL);
147 if (!sbi)
148 return -ENOMEM;
149 s->s_fs_info = sbi;
150 memset(sbi, 0, sizeof(struct minix_sb_info));
151
152 /* N.B. These should be compile-time tests.
153 Unfortunately that is impossible. */
154 if (32 != sizeof (struct minix_inode))
155 panic("bad V1 i-node size");
156 if (64 != sizeof(struct minix2_inode))
157 panic("bad V2 i-node size");
158
159 if (!sb_set_blocksize(s, BLOCK_SIZE))
160 goto out_bad_hblock;
161
162 if (!(bh = sb_bread(s, 1)))
163 goto out_bad_sb;
164
165 ms = (struct minix_super_block *) bh->b_data;
166 sbi->s_ms = ms;
167 sbi->s_sbh = bh;
168 sbi->s_mount_state = ms->s_state;
169 sbi->s_ninodes = ms->s_ninodes;
170 sbi->s_nzones = ms->s_nzones;
171 sbi->s_imap_blocks = ms->s_imap_blocks;
172 sbi->s_zmap_blocks = ms->s_zmap_blocks;
173 sbi->s_firstdatazone = ms->s_firstdatazone;
174 sbi->s_log_zone_size = ms->s_log_zone_size;
175 sbi->s_max_size = ms->s_max_size;
176 s->s_magic = ms->s_magic;
177 if (s->s_magic == MINIX_SUPER_MAGIC) {
178 sbi->s_version = MINIX_V1;
179 sbi->s_dirsize = 16;
180 sbi->s_namelen = 14;
181 sbi->s_link_max = MINIX_LINK_MAX;
182 } else if (s->s_magic == MINIX_SUPER_MAGIC2) {
183 sbi->s_version = MINIX_V1;
184 sbi->s_dirsize = 32;
185 sbi->s_namelen = 30;
186 sbi->s_link_max = MINIX_LINK_MAX;
187 } else if (s->s_magic == MINIX2_SUPER_MAGIC) {
188 sbi->s_version = MINIX_V2;
189 sbi->s_nzones = ms->s_zones;
190 sbi->s_dirsize = 16;
191 sbi->s_namelen = 14;
192 sbi->s_link_max = MINIX2_LINK_MAX;
193 } else if (s->s_magic == MINIX2_SUPER_MAGIC2) {
194 sbi->s_version = MINIX_V2;
195 sbi->s_nzones = ms->s_zones;
196 sbi->s_dirsize = 32;
197 sbi->s_namelen = 30;
198 sbi->s_link_max = MINIX2_LINK_MAX;
199 } else
200 goto out_no_fs;
201
202 /*
203 * Allocate the buffer map to keep the superblock small.
204 */
205 i = (sbi->s_imap_blocks + sbi->s_zmap_blocks) * sizeof(bh);
206 map = kmalloc(i, GFP_KERNEL);
207 if (!map)
208 goto out_no_map;
209 memset(map, 0, i);
210 sbi->s_imap = &map[0];
211 sbi->s_zmap = &map[sbi->s_imap_blocks];
212
213 block=2;
214 for (i=0 ; i < sbi->s_imap_blocks ; i++) {
215 if (!(sbi->s_imap[i]=sb_bread(s, block)))
216 goto out_no_bitmap;
217 block++;
218 }
219 for (i=0 ; i < sbi->s_zmap_blocks ; i++) {
220 if (!(sbi->s_zmap[i]=sb_bread(s, block)))
221 goto out_no_bitmap;
222 block++;
223 }
224
225 minix_set_bit(0,sbi->s_imap[0]->b_data);
226 minix_set_bit(0,sbi->s_zmap[0]->b_data);
227
228 /* set up enough so that it can read an inode */
229 s->s_op = &minix_sops;
230 root_inode = iget(s, MINIX_ROOT_INO);
231 if (!root_inode || is_bad_inode(root_inode))
232 goto out_no_root;
233
234 s->s_root = d_alloc_root(root_inode);
235 if (!s->s_root)
236 goto out_iput;
237
238 if (!NO_TRUNCATE)
239 s->s_root->d_op = &minix_dentry_operations;
240
241 if (!(s->s_flags & MS_RDONLY)) {
242 ms->s_state &= ~MINIX_VALID_FS;
243 mark_buffer_dirty(bh);
244 }
245 if (!(sbi->s_mount_state & MINIX_VALID_FS))
246 printk ("MINIX-fs: mounting unchecked file system, "
247 "running fsck is recommended.\n");
248 else if (sbi->s_mount_state & MINIX_ERROR_FS)
249 printk ("MINIX-fs: mounting file system with errors, "
250 "running fsck is recommended.\n");
251 return 0;
252
253out_iput:
254 iput(root_inode);
255 goto out_freemap;
256
257out_no_root:
258 if (!silent)
259 printk("MINIX-fs: get root inode failed\n");
260 goto out_freemap;
261
262out_no_bitmap:
263 printk("MINIX-fs: bad superblock or unable to read bitmaps\n");
264 out_freemap:
265 for (i = 0; i < sbi->s_imap_blocks; i++)
266 brelse(sbi->s_imap[i]);
267 for (i = 0; i < sbi->s_zmap_blocks; i++)
268 brelse(sbi->s_zmap[i]);
269 kfree(sbi->s_imap);
270 goto out_release;
271
272out_no_map:
273 if (!silent)
274 printk ("MINIX-fs: can't allocate map\n");
275 goto out_release;
276
277out_no_fs:
278 if (!silent)
279 printk("VFS: Can't find a Minix or Minix V2 filesystem on device "
280 "%s.\n", s->s_id);
281 out_release:
282 brelse(bh);
283 goto out;
284
285out_bad_hblock:
286 printk("MINIX-fs: blocksize too small for device.\n");
287 goto out;
288
289out_bad_sb:
290 printk("MINIX-fs: unable to read superblock\n");
291 out:
292 s->s_fs_info = NULL;
293 kfree(sbi);
294 return -EINVAL;
295}
296
297static int minix_statfs(struct super_block *sb, struct kstatfs *buf)
298{
299 struct minix_sb_info *sbi = minix_sb(sb);
300 buf->f_type = sb->s_magic;
301 buf->f_bsize = sb->s_blocksize;
302 buf->f_blocks = (sbi->s_nzones - sbi->s_firstdatazone) << sbi->s_log_zone_size;
303 buf->f_bfree = minix_count_free_blocks(sbi);
304 buf->f_bavail = buf->f_bfree;
305 buf->f_files = sbi->s_ninodes;
306 buf->f_ffree = minix_count_free_inodes(sbi);
307 buf->f_namelen = sbi->s_namelen;
308 return 0;
309}
310
311static int minix_get_block(struct inode *inode, sector_t block,
312 struct buffer_head *bh_result, int create)
313{
314 if (INODE_VERSION(inode) == MINIX_V1)
315 return V1_minix_get_block(inode, block, bh_result, create);
316 else
317 return V2_minix_get_block(inode, block, bh_result, create);
318}
319
320static int minix_writepage(struct page *page, struct writeback_control *wbc)
321{
322 return block_write_full_page(page, minix_get_block, wbc);
323}
324static int minix_readpage(struct file *file, struct page *page)
325{
326 return block_read_full_page(page,minix_get_block);
327}
328static int minix_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
329{
330 return block_prepare_write(page,from,to,minix_get_block);
331}
332static sector_t minix_bmap(struct address_space *mapping, sector_t block)
333{
334 return generic_block_bmap(mapping,block,minix_get_block);
335}
336static struct address_space_operations minix_aops = {
337 .readpage = minix_readpage,
338 .writepage = minix_writepage,
339 .sync_page = block_sync_page,
340 .prepare_write = minix_prepare_write,
341 .commit_write = generic_commit_write,
342 .bmap = minix_bmap
343};
344
345static struct inode_operations minix_symlink_inode_operations = {
346 .readlink = generic_readlink,
347 .follow_link = page_follow_link_light,
348 .put_link = page_put_link,
349 .getattr = minix_getattr,
350};
351
352void minix_set_inode(struct inode *inode, dev_t rdev)
353{
354 if (S_ISREG(inode->i_mode)) {
355 inode->i_op = &minix_file_inode_operations;
356 inode->i_fop = &minix_file_operations;
357 inode->i_mapping->a_ops = &minix_aops;
358 } else if (S_ISDIR(inode->i_mode)) {
359 inode->i_op = &minix_dir_inode_operations;
360 inode->i_fop = &minix_dir_operations;
361 inode->i_mapping->a_ops = &minix_aops;
362 } else if (S_ISLNK(inode->i_mode)) {
363 inode->i_op = &minix_symlink_inode_operations;
364 inode->i_mapping->a_ops = &minix_aops;
365 } else
366 init_special_inode(inode, inode->i_mode, rdev);
367}
368
369/*
370 * The minix V1 function to read an inode.
371 */
372static void V1_minix_read_inode(struct inode * inode)
373{
374 struct buffer_head * bh;
375 struct minix_inode * raw_inode;
376 struct minix_inode_info *minix_inode = minix_i(inode);
377 int i;
378
379 raw_inode = minix_V1_raw_inode(inode->i_sb, inode->i_ino, &bh);
380 if (!raw_inode) {
381 make_bad_inode(inode);
382 return;
383 }
384 inode->i_mode = raw_inode->i_mode;
385 inode->i_uid = (uid_t)raw_inode->i_uid;
386 inode->i_gid = (gid_t)raw_inode->i_gid;
387 inode->i_nlink = raw_inode->i_nlinks;
388 inode->i_size = raw_inode->i_size;
389 inode->i_mtime.tv_sec = inode->i_atime.tv_sec = inode->i_ctime.tv_sec = raw_inode->i_time;
390 inode->i_mtime.tv_nsec = 0;
391 inode->i_atime.tv_nsec = 0;
392 inode->i_ctime.tv_nsec = 0;
393 inode->i_blocks = inode->i_blksize = 0;
394 for (i = 0; i < 9; i++)
395 minix_inode->u.i1_data[i] = raw_inode->i_zone[i];
396 minix_set_inode(inode, old_decode_dev(raw_inode->i_zone[0]));
397 brelse(bh);
398}
399
400/*
401 * The minix V2 function to read an inode.
402 */
403static void V2_minix_read_inode(struct inode * inode)
404{
405 struct buffer_head * bh;
406 struct minix2_inode * raw_inode;
407 struct minix_inode_info *minix_inode = minix_i(inode);
408 int i;
409
410 raw_inode = minix_V2_raw_inode(inode->i_sb, inode->i_ino, &bh);
411 if (!raw_inode) {
412 make_bad_inode(inode);
413 return;
414 }
415 inode->i_mode = raw_inode->i_mode;
416 inode->i_uid = (uid_t)raw_inode->i_uid;
417 inode->i_gid = (gid_t)raw_inode->i_gid;
418 inode->i_nlink = raw_inode->i_nlinks;
419 inode->i_size = raw_inode->i_size;
420 inode->i_mtime.tv_sec = raw_inode->i_mtime;
421 inode->i_atime.tv_sec = raw_inode->i_atime;
422 inode->i_ctime.tv_sec = raw_inode->i_ctime;
423 inode->i_mtime.tv_nsec = 0;
424 inode->i_atime.tv_nsec = 0;
425 inode->i_ctime.tv_nsec = 0;
426 inode->i_blocks = inode->i_blksize = 0;
427 for (i = 0; i < 10; i++)
428 minix_inode->u.i2_data[i] = raw_inode->i_zone[i];
429 minix_set_inode(inode, old_decode_dev(raw_inode->i_zone[0]));
430 brelse(bh);
431}
432
433/*
434 * The global function to read an inode.
435 */
436static void minix_read_inode(struct inode * inode)
437{
438 if (INODE_VERSION(inode) == MINIX_V1)
439 V1_minix_read_inode(inode);
440 else
441 V2_minix_read_inode(inode);
442}
443
444/*
445 * The minix V1 function to synchronize an inode.
446 */
447static struct buffer_head * V1_minix_update_inode(struct inode * inode)
448{
449 struct buffer_head * bh;
450 struct minix_inode * raw_inode;
451 struct minix_inode_info *minix_inode = minix_i(inode);
452 int i;
453
454 raw_inode = minix_V1_raw_inode(inode->i_sb, inode->i_ino, &bh);
455 if (!raw_inode)
456 return NULL;
457 raw_inode->i_mode = inode->i_mode;
458 raw_inode->i_uid = fs_high2lowuid(inode->i_uid);
459 raw_inode->i_gid = fs_high2lowgid(inode->i_gid);
460 raw_inode->i_nlinks = inode->i_nlink;
461 raw_inode->i_size = inode->i_size;
462 raw_inode->i_time = inode->i_mtime.tv_sec;
463 if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
464 raw_inode->i_zone[0] = old_encode_dev(inode->i_rdev);
465 else for (i = 0; i < 9; i++)
466 raw_inode->i_zone[i] = minix_inode->u.i1_data[i];
467 mark_buffer_dirty(bh);
468 return bh;
469}
470
471/*
472 * The minix V2 function to synchronize an inode.
473 */
474static struct buffer_head * V2_minix_update_inode(struct inode * inode)
475{
476 struct buffer_head * bh;
477 struct minix2_inode * raw_inode;
478 struct minix_inode_info *minix_inode = minix_i(inode);
479 int i;
480
481 raw_inode = minix_V2_raw_inode(inode->i_sb, inode->i_ino, &bh);
482 if (!raw_inode)
483 return NULL;
484 raw_inode->i_mode = inode->i_mode;
485 raw_inode->i_uid = fs_high2lowuid(inode->i_uid);
486 raw_inode->i_gid = fs_high2lowgid(inode->i_gid);
487 raw_inode->i_nlinks = inode->i_nlink;
488 raw_inode->i_size = inode->i_size;
489 raw_inode->i_mtime = inode->i_mtime.tv_sec;
490 raw_inode->i_atime = inode->i_atime.tv_sec;
491 raw_inode->i_ctime = inode->i_ctime.tv_sec;
492 if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
493 raw_inode->i_zone[0] = old_encode_dev(inode->i_rdev);
494 else for (i = 0; i < 10; i++)
495 raw_inode->i_zone[i] = minix_inode->u.i2_data[i];
496 mark_buffer_dirty(bh);
497 return bh;
498}
499
500static struct buffer_head *minix_update_inode(struct inode *inode)
501{
502 if (INODE_VERSION(inode) == MINIX_V1)
503 return V1_minix_update_inode(inode);
504 else
505 return V2_minix_update_inode(inode);
506}
507
508static int minix_write_inode(struct inode * inode, int wait)
509{
510 brelse(minix_update_inode(inode));
511 return 0;
512}
513
514int minix_sync_inode(struct inode * inode)
515{
516 int err = 0;
517 struct buffer_head *bh;
518
519 bh = minix_update_inode(inode);
520 if (bh && buffer_dirty(bh))
521 {
522 sync_dirty_buffer(bh);
523 if (buffer_req(bh) && !buffer_uptodate(bh))
524 {
525 printk ("IO error syncing minix inode [%s:%08lx]\n",
526 inode->i_sb->s_id, inode->i_ino);
527 err = -1;
528 }
529 }
530 else if (!bh)
531 err = -1;
532 brelse (bh);
533 return err;
534}
535
536int minix_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
537{
538 generic_fillattr(dentry->d_inode, stat);
539 if (INODE_VERSION(dentry->d_inode) == MINIX_V1)
540 stat->blocks = (BLOCK_SIZE / 512) * V1_minix_blocks(stat->size);
541 else
542 stat->blocks = (BLOCK_SIZE / 512) * V2_minix_blocks(stat->size);
543 stat->blksize = BLOCK_SIZE;
544 return 0;
545}
546
547/*
548 * The function that is called for file truncation.
549 */
550void minix_truncate(struct inode * inode)
551{
552 if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)))
553 return;
554 if (INODE_VERSION(inode) == MINIX_V1)
555 V1_minix_truncate(inode);
556 else
557 V2_minix_truncate(inode);
558}
559
560static struct super_block *minix_get_sb(struct file_system_type *fs_type,
561 int flags, const char *dev_name, void *data)
562{
563 return get_sb_bdev(fs_type, flags, dev_name, data, minix_fill_super);
564}
565
566static struct file_system_type minix_fs_type = {
567 .owner = THIS_MODULE,
568 .name = "minix",
569 .get_sb = minix_get_sb,
570 .kill_sb = kill_block_super,
571 .fs_flags = FS_REQUIRES_DEV,
572};
573
574static int __init init_minix_fs(void)
575{
576 int err = init_inodecache();
577 if (err)
578 goto out1;
579 err = register_filesystem(&minix_fs_type);
580 if (err)
581 goto out;
582 return 0;
583out:
584 destroy_inodecache();
585out1:
586 return err;
587}
588
589static void __exit exit_minix_fs(void)
590{
591 unregister_filesystem(&minix_fs_type);
592 destroy_inodecache();
593}
594
595module_init(init_minix_fs)
596module_exit(exit_minix_fs)
597MODULE_LICENSE("GPL");
598
diff --git a/fs/minix/itree_common.c b/fs/minix/itree_common.c
new file mode 100644
index 000000000000..429baf8de105
--- /dev/null
+++ b/fs/minix/itree_common.c
@@ -0,0 +1,362 @@
1/* Generic part */
2
3typedef struct {
4 block_t *p;
5 block_t key;
6 struct buffer_head *bh;
7} Indirect;
8
9static DEFINE_RWLOCK(pointers_lock);
10
11static inline void add_chain(Indirect *p, struct buffer_head *bh, block_t *v)
12{
13 p->key = *(p->p = v);
14 p->bh = bh;
15}
16
17static inline int verify_chain(Indirect *from, Indirect *to)
18{
19 while (from <= to && from->key == *from->p)
20 from++;
21 return (from > to);
22}
23
24static inline block_t *block_end(struct buffer_head *bh)
25{
26 return (block_t *)((char*)bh->b_data + BLOCK_SIZE);
27}
28
29static inline Indirect *get_branch(struct inode *inode,
30 int depth,
31 int *offsets,
32 Indirect chain[DEPTH],
33 int *err)
34{
35 struct super_block *sb = inode->i_sb;
36 Indirect *p = chain;
37 struct buffer_head *bh;
38
39 *err = 0;
40 /* i_data is not going away, no lock needed */
41 add_chain (chain, NULL, i_data(inode) + *offsets);
42 if (!p->key)
43 goto no_block;
44 while (--depth) {
45 bh = sb_bread(sb, block_to_cpu(p->key));
46 if (!bh)
47 goto failure;
48 read_lock(&pointers_lock);
49 if (!verify_chain(chain, p))
50 goto changed;
51 add_chain(++p, bh, (block_t *)bh->b_data + *++offsets);
52 read_unlock(&pointers_lock);
53 if (!p->key)
54 goto no_block;
55 }
56 return NULL;
57
58changed:
59 read_unlock(&pointers_lock);
60 brelse(bh);
61 *err = -EAGAIN;
62 goto no_block;
63failure:
64 *err = -EIO;
65no_block:
66 return p;
67}
68
69static int alloc_branch(struct inode *inode,
70 int num,
71 int *offsets,
72 Indirect *branch)
73{
74 int n = 0;
75 int i;
76 int parent = minix_new_block(inode);
77
78 branch[0].key = cpu_to_block(parent);
79 if (parent) for (n = 1; n < num; n++) {
80 struct buffer_head *bh;
81 /* Allocate the next block */
82 int nr = minix_new_block(inode);
83 if (!nr)
84 break;
85 branch[n].key = cpu_to_block(nr);
86 bh = sb_getblk(inode->i_sb, parent);
87 lock_buffer(bh);
88 memset(bh->b_data, 0, BLOCK_SIZE);
89 branch[n].bh = bh;
90 branch[n].p = (block_t*) bh->b_data + offsets[n];
91 *branch[n].p = branch[n].key;
92 set_buffer_uptodate(bh);
93 unlock_buffer(bh);
94 mark_buffer_dirty_inode(bh, inode);
95 parent = nr;
96 }
97 if (n == num)
98 return 0;
99
100 /* Allocation failed, free what we already allocated */
101 for (i = 1; i < n; i++)
102 bforget(branch[i].bh);
103 for (i = 0; i < n; i++)
104 minix_free_block(inode, block_to_cpu(branch[i].key));
105 return -ENOSPC;
106}
107
108static inline int splice_branch(struct inode *inode,
109 Indirect chain[DEPTH],
110 Indirect *where,
111 int num)
112{
113 int i;
114
115 write_lock(&pointers_lock);
116
117 /* Verify that place we are splicing to is still there and vacant */
118 if (!verify_chain(chain, where-1) || *where->p)
119 goto changed;
120
121 *where->p = where->key;
122
123 write_unlock(&pointers_lock);
124
125 /* We are done with atomic stuff, now do the rest of housekeeping */
126
127 inode->i_ctime = CURRENT_TIME_SEC;
128
129 /* had we spliced it onto indirect block? */
130 if (where->bh)
131 mark_buffer_dirty_inode(where->bh, inode);
132
133 mark_inode_dirty(inode);
134 return 0;
135
136changed:
137 write_unlock(&pointers_lock);
138 for (i = 1; i < num; i++)
139 bforget(where[i].bh);
140 for (i = 0; i < num; i++)
141 minix_free_block(inode, block_to_cpu(where[i].key));
142 return -EAGAIN;
143}
144
145static inline int get_block(struct inode * inode, sector_t block,
146 struct buffer_head *bh, int create)
147{
148 int err = -EIO;
149 int offsets[DEPTH];
150 Indirect chain[DEPTH];
151 Indirect *partial;
152 int left;
153 int depth = block_to_path(inode, block, offsets);
154
155 if (depth == 0)
156 goto out;
157
158reread:
159 partial = get_branch(inode, depth, offsets, chain, &err);
160
161 /* Simplest case - block found, no allocation needed */
162 if (!partial) {
163got_it:
164 map_bh(bh, inode->i_sb, block_to_cpu(chain[depth-1].key));
165 /* Clean up and exit */
166 partial = chain+depth-1; /* the whole chain */
167 goto cleanup;
168 }
169
170 /* Next simple case - plain lookup or failed read of indirect block */
171 if (!create || err == -EIO) {
172cleanup:
173 while (partial > chain) {
174 brelse(partial->bh);
175 partial--;
176 }
177out:
178 return err;
179 }
180
181 /*
182 * Indirect block might be removed by truncate while we were
183 * reading it. Handling of that case (forget what we've got and
184 * reread) is taken out of the main path.
185 */
186 if (err == -EAGAIN)
187 goto changed;
188
189 left = (chain + depth) - partial;
190 err = alloc_branch(inode, left, offsets+(partial-chain), partial);
191 if (err)
192 goto cleanup;
193
194 if (splice_branch(inode, chain, partial, left) < 0)
195 goto changed;
196
197 set_buffer_new(bh);
198 goto got_it;
199
200changed:
201 while (partial > chain) {
202 brelse(partial->bh);
203 partial--;
204 }
205 goto reread;
206}
207
208static inline int all_zeroes(block_t *p, block_t *q)
209{
210 while (p < q)
211 if (*p++)
212 return 0;
213 return 1;
214}
215
216static Indirect *find_shared(struct inode *inode,
217 int depth,
218 int offsets[DEPTH],
219 Indirect chain[DEPTH],
220 block_t *top)
221{
222 Indirect *partial, *p;
223 int k, err;
224
225 *top = 0;
226 for (k = depth; k > 1 && !offsets[k-1]; k--)
227 ;
228 partial = get_branch(inode, k, offsets, chain, &err);
229
230 write_lock(&pointers_lock);
231 if (!partial)
232 partial = chain + k-1;
233 if (!partial->key && *partial->p) {
234 write_unlock(&pointers_lock);
235 goto no_top;
236 }
237 for (p=partial;p>chain && all_zeroes((block_t*)p->bh->b_data,p->p);p--)
238 ;
239 if (p == chain + k - 1 && p > chain) {
240 p->p--;
241 } else {
242 *top = *p->p;
243 *p->p = 0;
244 }
245 write_unlock(&pointers_lock);
246
247 while(partial > p)
248 {
249 brelse(partial->bh);
250 partial--;
251 }
252no_top:
253 return partial;
254}
255
256static inline void free_data(struct inode *inode, block_t *p, block_t *q)
257{
258 unsigned long nr;
259
260 for ( ; p < q ; p++) {
261 nr = block_to_cpu(*p);
262 if (nr) {
263 *p = 0;
264 minix_free_block(inode, nr);
265 }
266 }
267}
268
269static void free_branches(struct inode *inode, block_t *p, block_t *q, int depth)
270{
271 struct buffer_head * bh;
272 unsigned long nr;
273
274 if (depth--) {
275 for ( ; p < q ; p++) {
276 nr = block_to_cpu(*p);
277 if (!nr)
278 continue;
279 *p = 0;
280 bh = sb_bread(inode->i_sb, nr);
281 if (!bh)
282 continue;
283 free_branches(inode, (block_t*)bh->b_data,
284 block_end(bh), depth);
285 bforget(bh);
286 minix_free_block(inode, nr);
287 mark_inode_dirty(inode);
288 }
289 } else
290 free_data(inode, p, q);
291}
292
293static inline void truncate (struct inode * inode)
294{
295 block_t *idata = i_data(inode);
296 int offsets[DEPTH];
297 Indirect chain[DEPTH];
298 Indirect *partial;
299 block_t nr = 0;
300 int n;
301 int first_whole;
302 long iblock;
303
304 iblock = (inode->i_size + BLOCK_SIZE-1) >> 10;
305 block_truncate_page(inode->i_mapping, inode->i_size, get_block);
306
307 n = block_to_path(inode, iblock, offsets);
308 if (!n)
309 return;
310
311 if (n == 1) {
312 free_data(inode, idata+offsets[0], idata + DIRECT);
313 first_whole = 0;
314 goto do_indirects;
315 }
316
317 first_whole = offsets[0] + 1 - DIRECT;
318 partial = find_shared(inode, n, offsets, chain, &nr);
319 if (nr) {
320 if (partial == chain)
321 mark_inode_dirty(inode);
322 else
323 mark_buffer_dirty_inode(partial->bh, inode);
324 free_branches(inode, &nr, &nr+1, (chain+n-1) - partial);
325 }
326 /* Clear the ends of indirect blocks on the shared branch */
327 while (partial > chain) {
328 free_branches(inode, partial->p + 1, block_end(partial->bh),
329 (chain+n-1) - partial);
330 mark_buffer_dirty_inode(partial->bh, inode);
331 brelse (partial->bh);
332 partial--;
333 }
334do_indirects:
335 /* Kill the remaining (whole) subtrees */
336 while (first_whole < DEPTH-1) {
337 nr = idata[DIRECT+first_whole];
338 if (nr) {
339 idata[DIRECT+first_whole] = 0;
340 mark_inode_dirty(inode);
341 free_branches(inode, &nr, &nr+1, first_whole+1);
342 }
343 first_whole++;
344 }
345 inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
346 mark_inode_dirty(inode);
347}
348
349static inline unsigned nblocks(loff_t size)
350{
351 unsigned blocks, res, direct = DIRECT, i = DEPTH;
352 blocks = (size + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS;
353 res = blocks;
354 while (--i && blocks > direct) {
355 blocks -= direct;
356 blocks += BLOCK_SIZE/sizeof(block_t) - 1;
357 blocks /= BLOCK_SIZE/sizeof(block_t);
358 res += blocks;
359 direct = 1;
360 }
361 return res;
362}
diff --git a/fs/minix/itree_v1.c b/fs/minix/itree_v1.c
new file mode 100644
index 000000000000..ba06aef4aca1
--- /dev/null
+++ b/fs/minix/itree_v1.c
@@ -0,0 +1,61 @@
1#include <linux/buffer_head.h>
2#include "minix.h"
3
4enum {DEPTH = 3, DIRECT = 7}; /* Only double indirect */
5
6typedef u16 block_t; /* 16 bit, host order */
7
8static inline unsigned long block_to_cpu(block_t n)
9{
10 return n;
11}
12
13static inline block_t cpu_to_block(unsigned long n)
14{
15 return n;
16}
17
18static inline block_t *i_data(struct inode *inode)
19{
20 return (block_t *)minix_i(inode)->u.i1_data;
21}
22
23static int block_to_path(struct inode * inode, long block, int offsets[DEPTH])
24{
25 int n = 0;
26
27 if (block < 0) {
28 printk("minix_bmap: block<0");
29 } else if (block >= (minix_sb(inode->i_sb)->s_max_size/BLOCK_SIZE)) {
30 printk("minix_bmap: block>big");
31 } else if (block < 7) {
32 offsets[n++] = block;
33 } else if ((block -= 7) < 512) {
34 offsets[n++] = 7;
35 offsets[n++] = block;
36 } else {
37 block -= 512;
38 offsets[n++] = 8;
39 offsets[n++] = block>>9;
40 offsets[n++] = block & 511;
41 }
42 return n;
43}
44
45#include "itree_common.c"
46
47int V1_minix_get_block(struct inode * inode, long block,
48 struct buffer_head *bh_result, int create)
49{
50 return get_block(inode, block, bh_result, create);
51}
52
53void V1_minix_truncate(struct inode * inode)
54{
55 truncate(inode);
56}
57
58unsigned V1_minix_blocks(loff_t size)
59{
60 return nblocks(size);
61}
diff --git a/fs/minix/itree_v2.c b/fs/minix/itree_v2.c
new file mode 100644
index 000000000000..3adc7675560f
--- /dev/null
+++ b/fs/minix/itree_v2.c
@@ -0,0 +1,66 @@
1#include <linux/buffer_head.h>
2#include "minix.h"
3
4enum {DIRECT = 7, DEPTH = 4}; /* Have triple indirect */
5
6typedef u32 block_t; /* 32 bit, host order */
7
8static inline unsigned long block_to_cpu(block_t n)
9{
10 return n;
11}
12
13static inline block_t cpu_to_block(unsigned long n)
14{
15 return n;
16}
17
18static inline block_t *i_data(struct inode *inode)
19{
20 return (block_t *)minix_i(inode)->u.i2_data;
21}
22
23static int block_to_path(struct inode * inode, long block, int offsets[DEPTH])
24{
25 int n = 0;
26
27 if (block < 0) {
28 printk("minix_bmap: block<0");
29 } else if (block >= (minix_sb(inode->i_sb)->s_max_size/BLOCK_SIZE)) {
30 printk("minix_bmap: block>big");
31 } else if (block < 7) {
32 offsets[n++] = block;
33 } else if ((block -= 7) < 256) {
34 offsets[n++] = 7;
35 offsets[n++] = block;
36 } else if ((block -= 256) < 256*256) {
37 offsets[n++] = 8;
38 offsets[n++] = block>>8;
39 offsets[n++] = block & 255;
40 } else {
41 block -= 256*256;
42 offsets[n++] = 9;
43 offsets[n++] = block>>16;
44 offsets[n++] = (block>>8) & 255;
45 offsets[n++] = block & 255;
46 }
47 return n;
48}
49
50#include "itree_common.c"
51
52int V2_minix_get_block(struct inode * inode, long block,
53 struct buffer_head *bh_result, int create)
54{
55 return get_block(inode, block, bh_result, create);
56}
57
58void V2_minix_truncate(struct inode * inode)
59{
60 truncate(inode);
61}
62
63unsigned V2_minix_blocks(loff_t size)
64{
65 return nblocks(size);
66}
diff --git a/fs/minix/minix.h b/fs/minix/minix.h
new file mode 100644
index 000000000000..e42a8bb89001
--- /dev/null
+++ b/fs/minix/minix.h
@@ -0,0 +1,96 @@
1#include <linux/fs.h>
2#include <linux/pagemap.h>
3#include <linux/minix_fs.h>
4
5/*
6 * change the define below to 0 if you want names > info->s_namelen chars to be
7 * truncated. Else they will be disallowed (ENAMETOOLONG).
8 */
9#define NO_TRUNCATE 1
10
11#define INODE_VERSION(inode) minix_sb(inode->i_sb)->s_version
12
13#define MINIX_V1 0x0001 /* original minix fs */
14#define MINIX_V2 0x0002 /* minix V2 fs */
15
16/*
17 * minix fs inode data in memory
18 */
19struct minix_inode_info {
20 union {
21 __u16 i1_data[16];
22 __u32 i2_data[16];
23 } u;
24 struct inode vfs_inode;
25};
26
27/*
28 * minix super-block data in memory
29 */
30struct minix_sb_info {
31 unsigned long s_ninodes;
32 unsigned long s_nzones;
33 unsigned long s_imap_blocks;
34 unsigned long s_zmap_blocks;
35 unsigned long s_firstdatazone;
36 unsigned long s_log_zone_size;
37 unsigned long s_max_size;
38 int s_dirsize;
39 int s_namelen;
40 int s_link_max;
41 struct buffer_head ** s_imap;
42 struct buffer_head ** s_zmap;
43 struct buffer_head * s_sbh;
44 struct minix_super_block * s_ms;
45 unsigned short s_mount_state;
46 unsigned short s_version;
47};
48
49extern struct minix_inode * minix_V1_raw_inode(struct super_block *, ino_t, struct buffer_head **);
50extern struct minix2_inode * minix_V2_raw_inode(struct super_block *, ino_t, struct buffer_head **);
51extern struct inode * minix_new_inode(const struct inode * dir, int * error);
52extern void minix_free_inode(struct inode * inode);
53extern unsigned long minix_count_free_inodes(struct minix_sb_info *sbi);
54extern int minix_new_block(struct inode * inode);
55extern void minix_free_block(struct inode * inode, int block);
56extern unsigned long minix_count_free_blocks(struct minix_sb_info *sbi);
57
58extern int minix_getattr(struct vfsmount *, struct dentry *, struct kstat *);
59
60extern void V2_minix_truncate(struct inode *);
61extern void V1_minix_truncate(struct inode *);
62extern void V2_minix_truncate(struct inode *);
63extern void minix_truncate(struct inode *);
64extern int minix_sync_inode(struct inode *);
65extern void minix_set_inode(struct inode *, dev_t);
66extern 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);
68extern unsigned V1_minix_blocks(loff_t);
69extern unsigned V2_minix_blocks(loff_t);
70
71extern struct minix_dir_entry *minix_find_entry(struct dentry*, struct page**);
72extern int minix_add_link(struct dentry*, struct inode*);
73extern int minix_delete_entry(struct minix_dir_entry*, struct page*);
74extern int minix_make_empty(struct inode*, struct inode*);
75extern int minix_empty_dir(struct inode*);
76extern void minix_set_link(struct minix_dir_entry*, struct page*, struct inode*);
77extern struct minix_dir_entry *minix_dotdot(struct inode*, struct page**);
78extern ino_t minix_inode_by_name(struct dentry*);
79
80extern int minix_sync_file(struct file *, struct dentry *, int);
81
82extern struct inode_operations minix_file_inode_operations;
83extern struct inode_operations minix_dir_inode_operations;
84extern struct file_operations minix_file_operations;
85extern struct file_operations minix_dir_operations;
86extern struct dentry_operations minix_dentry_operations;
87
88static inline struct minix_sb_info *minix_sb(struct super_block *sb)
89{
90 return sb->s_fs_info;
91}
92
93static inline struct minix_inode_info *minix_i(struct inode *inode)
94{
95 return list_entry(inode, struct minix_inode_info, vfs_inode);
96}
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
new file mode 100644
index 000000000000..b25bca5bdb57
--- /dev/null
+++ b/fs/minix/namei.c
@@ -0,0 +1,317 @@
1/*
2 * linux/fs/minix/namei.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
6
7#include "minix.h"
8
9static inline void inc_count(struct inode *inode)
10{
11 inode->i_nlink++;
12 mark_inode_dirty(inode);
13}
14
15static inline void dec_count(struct inode *inode)
16{
17 inode->i_nlink--;
18 mark_inode_dirty(inode);
19}
20
21static int add_nondir(struct dentry *dentry, struct inode *inode)
22{
23 int err = minix_add_link(dentry, inode);
24 if (!err) {
25 d_instantiate(dentry, inode);
26 return 0;
27 }
28 dec_count(inode);
29 iput(inode);
30 return err;
31}
32
33static int minix_hash(struct dentry *dentry, struct qstr *qstr)
34{
35 unsigned long hash;
36 int i;
37 const unsigned char *name;
38
39 i = minix_sb(dentry->d_inode->i_sb)->s_namelen;
40 if (i >= qstr->len)
41 return 0;
42 /* Truncate the name in place, avoids having to define a compare
43 function. */
44 qstr->len = i;
45 name = qstr->name;
46 hash = init_name_hash();
47 while (i--)
48 hash = partial_name_hash(*name++, hash);
49 qstr->hash = end_name_hash(hash);
50 return 0;
51}
52
53struct dentry_operations minix_dentry_operations = {
54 .d_hash = minix_hash,
55};
56
57static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
58{
59 struct inode * inode = NULL;
60 ino_t ino;
61
62 dentry->d_op = dir->i_sb->s_root->d_op;
63
64 if (dentry->d_name.len > minix_sb(dir->i_sb)->s_namelen)
65 return ERR_PTR(-ENAMETOOLONG);
66
67 ino = minix_inode_by_name(dentry);
68 if (ino) {
69 inode = iget(dir->i_sb, ino);
70
71 if (!inode)
72 return ERR_PTR(-EACCES);
73 }
74 d_add(dentry, inode);
75 return NULL;
76}
77
78static int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, dev_t rdev)
79{
80 int error;
81 struct inode *inode;
82
83 if (!old_valid_dev(rdev))
84 return -EINVAL;
85
86 inode = minix_new_inode(dir, &error);
87
88 if (inode) {
89 inode->i_mode = mode;
90 minix_set_inode(inode, rdev);
91 mark_inode_dirty(inode);
92 error = add_nondir(dentry, inode);
93 }
94 return error;
95}
96
97static int minix_create(struct inode * dir, struct dentry *dentry, int mode,
98 struct nameidata *nd)
99{
100 return minix_mknod(dir, dentry, mode, 0);
101}
102
103static int minix_symlink(struct inode * dir, struct dentry *dentry,
104 const char * symname)
105{
106 int err = -ENAMETOOLONG;
107 int i = strlen(symname)+1;
108 struct inode * inode;
109
110 if (i > dir->i_sb->s_blocksize)
111 goto out;
112
113 inode = minix_new_inode(dir, &err);
114 if (!inode)
115 goto out;
116
117 inode->i_mode = S_IFLNK | 0777;
118 minix_set_inode(inode, 0);
119 err = page_symlink(inode, symname, i);
120 if (err)
121 goto out_fail;
122
123 err = add_nondir(dentry, inode);
124out:
125 return err;
126
127out_fail:
128 dec_count(inode);
129 iput(inode);
130 goto out;
131}
132
133static int minix_link(struct dentry * old_dentry, struct inode * dir,
134 struct dentry *dentry)
135{
136 struct inode *inode = old_dentry->d_inode;
137
138 if (inode->i_nlink >= minix_sb(inode->i_sb)->s_link_max)
139 return -EMLINK;
140
141 inode->i_ctime = CURRENT_TIME_SEC;
142 inc_count(inode);
143 atomic_inc(&inode->i_count);
144 return add_nondir(dentry, inode);
145}
146
147static int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode)
148{
149 struct inode * inode;
150 int err = -EMLINK;
151
152 if (dir->i_nlink >= minix_sb(dir->i_sb)->s_link_max)
153 goto out;
154
155 inc_count(dir);
156
157 inode = minix_new_inode(dir, &err);
158 if (!inode)
159 goto out_dir;
160
161 inode->i_mode = S_IFDIR | mode;
162 if (dir->i_mode & S_ISGID)
163 inode->i_mode |= S_ISGID;
164 minix_set_inode(inode, 0);
165
166 inc_count(inode);
167
168 err = minix_make_empty(inode, dir);
169 if (err)
170 goto out_fail;
171
172 err = minix_add_link(dentry, inode);
173 if (err)
174 goto out_fail;
175
176 d_instantiate(dentry, inode);
177out:
178 return err;
179
180out_fail:
181 dec_count(inode);
182 dec_count(inode);
183 iput(inode);
184out_dir:
185 dec_count(dir);
186 goto out;
187}
188
189static int minix_unlink(struct inode * dir, struct dentry *dentry)
190{
191 int err = -ENOENT;
192 struct inode * inode = dentry->d_inode;
193 struct page * page;
194 struct minix_dir_entry * de;
195
196 de = minix_find_entry(dentry, &page);
197 if (!de)
198 goto end_unlink;
199
200 err = minix_delete_entry(de, page);
201 if (err)
202 goto end_unlink;
203
204 inode->i_ctime = dir->i_ctime;
205 dec_count(inode);
206end_unlink:
207 return err;
208}
209
210static int minix_rmdir(struct inode * dir, struct dentry *dentry)
211{
212 struct inode * inode = dentry->d_inode;
213 int err = -ENOTEMPTY;
214
215 if (minix_empty_dir(inode)) {
216 err = minix_unlink(dir, dentry);
217 if (!err) {
218 dec_count(dir);
219 dec_count(inode);
220 }
221 }
222 return err;
223}
224
225static int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
226 struct inode * new_dir, struct dentry *new_dentry)
227{
228 struct minix_sb_info * info = minix_sb(old_dir->i_sb);
229 struct inode * old_inode = old_dentry->d_inode;
230 struct inode * new_inode = new_dentry->d_inode;
231 struct page * dir_page = NULL;
232 struct minix_dir_entry * dir_de = NULL;
233 struct page * old_page;
234 struct minix_dir_entry * old_de;
235 int err = -ENOENT;
236
237 old_de = minix_find_entry(old_dentry, &old_page);
238 if (!old_de)
239 goto out;
240
241 if (S_ISDIR(old_inode->i_mode)) {
242 err = -EIO;
243 dir_de = minix_dotdot(old_inode, &dir_page);
244 if (!dir_de)
245 goto out_old;
246 }
247
248 if (new_inode) {
249 struct page * new_page;
250 struct minix_dir_entry * new_de;
251
252 err = -ENOTEMPTY;
253 if (dir_de && !minix_empty_dir(new_inode))
254 goto out_dir;
255
256 err = -ENOENT;
257 new_de = minix_find_entry(new_dentry, &new_page);
258 if (!new_de)
259 goto out_dir;
260 inc_count(old_inode);
261 minix_set_link(new_de, new_page, old_inode);
262 new_inode->i_ctime = CURRENT_TIME_SEC;
263 if (dir_de)
264 new_inode->i_nlink--;
265 dec_count(new_inode);
266 } else {
267 if (dir_de) {
268 err = -EMLINK;
269 if (new_dir->i_nlink >= info->s_link_max)
270 goto out_dir;
271 }
272 inc_count(old_inode);
273 err = minix_add_link(new_dentry, old_inode);
274 if (err) {
275 dec_count(old_inode);
276 goto out_dir;
277 }
278 if (dir_de)
279 inc_count(new_dir);
280 }
281
282 minix_delete_entry(old_de, old_page);
283 dec_count(old_inode);
284
285 if (dir_de) {
286 minix_set_link(dir_de, dir_page, new_dir);
287 dec_count(old_dir);
288 }
289 return 0;
290
291out_dir:
292 if (dir_de) {
293 kunmap(dir_page);
294 page_cache_release(dir_page);
295 }
296out_old:
297 kunmap(old_page);
298 page_cache_release(old_page);
299out:
300 return err;
301}
302
303/*
304 * directories can handle most operations...
305 */
306struct inode_operations minix_dir_inode_operations = {
307 .create = minix_create,
308 .lookup = minix_lookup,
309 .link = minix_link,
310 .unlink = minix_unlink,
311 .symlink = minix_symlink,
312 .mkdir = minix_mkdir,
313 .rmdir = minix_rmdir,
314 .mknod = minix_mknod,
315 .rename = minix_rename,
316 .getattr = minix_getattr,
317};