aboutsummaryrefslogtreecommitdiffstats
path: root/fs/sysv
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/sysv
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/sysv')
-rw-r--r--fs/sysv/CHANGES60
-rw-r--r--fs/sysv/ChangeLog106
-rw-r--r--fs/sysv/INTRO182
-rw-r--r--fs/sysv/Makefile8
-rw-r--r--fs/sysv/balloc.c239
-rw-r--r--fs/sysv/dir.c388
-rw-r--r--fs/sysv/file.c49
-rw-r--r--fs/sysv/ialloc.c240
-rw-r--r--fs/sysv/inode.c354
-rw-r--r--fs/sysv/itree.c475
-rw-r--r--fs/sysv/namei.c318
-rw-r--r--fs/sysv/super.c572
-rw-r--r--fs/sysv/symlink.c20
-rw-r--r--fs/sysv/sysv.h244
14 files changed, 3255 insertions, 0 deletions
diff --git a/fs/sysv/CHANGES b/fs/sysv/CHANGES
new file mode 100644
index 000000000000..66ea6e92be66
--- /dev/null
+++ b/fs/sysv/CHANGES
@@ -0,0 +1,60 @@
1Mon, 15 Dec 1997 Krzysztof G. Baranowski <kgb@manjak.knm.org.pl>
2 * namei.c: struct sysv_dir_inode_operations updated to use dentries.
3
4Fri, 23 Jan 1998 Krzysztof G. Baranowski <kgb@manjak.knm.org.pl>
5 * inode.c: corrected 1 track offset setting (in sb->sv_block_base).
6 Originally it was overridden (by setting to zero)
7 in detected_[xenix,sysv4,sysv2,coherent]. Thanks
8 to Andrzej Krzysztofowicz <ankry@mif.pg.gda.pl>
9 for identifying the problem.
10
11Tue, 27 Jan 1998 Krzysztof G. Baranowski <kgb@manjak.knm.org.pl>
12 * inode.c: added 2048-byte block support to SystemV FS.
13 Merged detected_bs[512,1024,2048]() into one function:
14 void detected_bs (u_char type, struct super_block *sb).
15 Thanks to Andrzej Krzysztofowicz <ankry@mif.pg.gda.pl>
16 for the patch.
17
18Wed, 4 Feb 1998 Krzysztof G. Baranowski <kgb@manjak.knm.org.pl>
19 * namei.c: removed static subdir(); is_subdir() from dcache.c
20 is used instead. Cosmetic changes.
21
22Thu, 3 Dec 1998 Al Viro (viro@parcelfarce.linux.theplanet.co.uk)
23 * namei.c (sysv_rmdir):
24 Bugectomy: old check for victim being busy
25 (inode->i_count) wasn't replaced (with checking
26 dentry->d_count) and escaped Linus in the last round
27 of changes. Shot and buried.
28
29Wed, 9 Dec 1998 AV
30 * namei.c (do_sysv_rename):
31 Fixed incorrect check for other owners + race.
32 Removed checks that went to VFS.
33 * namei.c (sysv_unlink):
34 Removed checks that went to VFS.
35
36Thu, 10 Dec 1998 AV
37 * namei.c (do_mknod):
38 Removed dead code - mknod is never asked to
39 create a symlink or directory. Incidentially,
40 it wouldn't do it right if it would be called.
41
42Sat, 26 Dec 1998 KGB
43 * inode.c (detect_sysv4):
44 Added detection of expanded s_type field (0x10,
45 0x20 and 0x30). Forced read-only access in this case.
46
47Sun, 21 Mar 1999 AV
48 * namei.c (sysv_link):
49 Fixed i_count usage that resulted in dcache corruption.
50 * inode.c:
51 Filled ->delete_inode() method with sysv_delete_inode().
52 sysv_put_inode() is gone, as it tried to do ->delete_
53 _inode()'s job.
54 * ialloc.c: (sysv_free_inode):
55 Fixed race.
56
57Sun, 30 Apr 1999 AV
58 * namei.c (sysv_mknod):
59 Removed dead code (S_IFREG case is now passed to
60 ->create() by VFS).
diff --git a/fs/sysv/ChangeLog b/fs/sysv/ChangeLog
new file mode 100644
index 000000000000..18e3487debdb
--- /dev/null
+++ b/fs/sysv/ChangeLog
@@ -0,0 +1,106 @@
1Thu Feb 14 2002 Andrew Morton <akpm@zip.com.au>
2
3 * dir_commit_chunk(): call writeout_one_page() as well as
4 waitfor_one_page() for IS_SYNC directories, so that we
5 actually do sync the directory. (forward-port from 2.4).
6
7Thu Feb 7 2002 Alexander Viro <viro@parcelfarce.linux.theplanet.co.uk>
8
9 * super.c: switched to ->get_sb()
10 * ChangeLog: fixed dates ;-)
11
122002-01-24 David S. Miller <davem@redhat.com>
13
14 * inode.c: Include linux/init.h
15
16Mon Jan 21 2002 Alexander Viro <viro@parcelfarce.linux.theplanet.co.uk>
17 * ialloc.c (sysv_new_inode): zero SYSV_I(inode)->i_data out.
18 * i_vnode renamed to vfs_inode. Sorry, but let's keep that
19 consistent.
20
21Sat Jan 19 2002 Christoph Hellwig <hch@infradead.org>
22
23 * include/linux/sysv_fs.h (SYSV_I): Get fs-private inode data using
24 list_entry() instead of inode->u.
25 * include/linux/sysv_fs_i.h: Add 'struct inode i_vnode' field to
26 sysv_inode_info structure.
27 * inode.c: Include <linux/slab.h>, implement alloc_inode/destroy_inode
28 sop methods, add infrastructure for per-fs inode slab cache.
29 * super.c (init_sysv_fs): Initialize inode cache, recover properly
30 in the case of failed register_filesystem for V7.
31 (exit_sysv_fs): Destroy inode cache.
32
33Sat Jan 19 2002 Christoph Hellwig <hch@infradead.org>
34
35 * include/linux/sysv_fs.h: Include <linux/sysv_fs_i.h>, declare SYSV_I().
36 * dir.c (sysv_find_entry): Use SYSV_I() instead of ->u.sysv_i to
37 access fs-private inode data.
38 * ialloc.c (sysv_new_inode): Likewise.
39 * inode.c (sysv_read_inode): Likewise.
40 (sysv_update_inode): Likewise.
41 * itree.c (get_branch): Likewise.
42 (sysv_truncate): Likewise.
43 * symlink.c (sysv_readlink): Likewise.
44 (sysv_follow_link): Likewise.
45
46Fri Jan 4 2002 Alexander Viro <viro@parcelfarce.linux.theplanet.co.uk>
47
48 * ialloc.c (sysv_free_inode): Use sb->s_id instead of bdevname().
49 * inode.c (sysv_read_inode): Likewise.
50 (sysv_update_inode): Likewise.
51 (sysv_sync_inode): Likewise.
52 * super.c (detect_sysv): Likewise.
53 (complete_read_super): Likewise.
54 (sysv_read_super): Likewise.
55 (v7_read_super): Likewise.
56
57Sun Dec 30 2001 Manfred Spraul <manfreds@colorfullife.com>
58
59 * dir.c (dir_commit_chunk): Do not set dir->i_version.
60 (sysv_readdir): Likewise.
61
62Thu Dec 27 2001 Alexander Viro <viro@parcelfarce.linux.theplanet.co.uk>
63
64 * itree.c (get_block): Use map_bh() to fill out bh_result.
65
66Tue Dec 25 2001 Alexander Viro <viro@parcelfarce.linux.theplanet.co.uk>
67
68 * super.c (sysv_read_super): Use sb_set_blocksize() to set blocksize.
69 (v7_read_super): Likewise.
70
71Tue Nov 27 2001 Alexander Viro <viro@parcelfarce.linux.theplanet.co.uk>
72
73 * itree.c (get_block): Change type for iblock argument to sector_t.
74 * super.c (sysv_read_super): Set s_blocksize early.
75 (v7_read_super): Likewise.
76 * balloc.c (sysv_new_block): Use sb_bread(). instead of bread().
77 (sysv_count_free_blocks): Likewise.
78 * ialloc.c (sysv_raw_inode): Likewise.
79 * itree.c (get_branch): Likewise.
80 (free_branches): Likewise.
81 * super.c (sysv_read_super): Likewise.
82 (v7_read_super): Likewise.
83
84Sat Dec 15 2001 Christoph Hellwig <hch@infradead.org>
85
86 * inode.c (sysv_read_inode): Mark inode as bad in case of failure.
87 * super.c (complete_read_super): Check for bad root inode.
88
89Wed Nov 21 2001 Andrew Morton <andrewm@uow.edu.au>
90
91 * file.c (sysv_sync_file): Call fsync_inode_data_buffers.
92
93Fri Oct 26 2001 Christoph Hellwig <hch@infradead.org>
94
95 * dir.c, ialloc.c, namei.c, include/linux/sysv_fs_i.h:
96 Implement per-Inode lookup offset cache.
97 Modelled after Ted's ext2 patch.
98
99Fri Oct 26 2001 Christoph Hellwig <hch@infradead.org>
100
101 * inode.c, super.c, include/linux/sysv_fs.h,
102 include/linux/sysv_fs_sb.h:
103 Remove symlink faking. Noone really wants to use these as
104 linux filesystems and native OSes don't support it anyway.
105
106
diff --git a/fs/sysv/INTRO b/fs/sysv/INTRO
new file mode 100644
index 000000000000..de4e4d17cac6
--- /dev/null
+++ b/fs/sysv/INTRO
@@ -0,0 +1,182 @@
1This is the implementation of the SystemV/Coherent filesystem for Linux.
2It grew out of separate filesystem implementations
3
4 Xenix FS Doug Evans <dje@cygnus.com> June 1992
5 SystemV FS Paul B. Monday <pmonday@eecs.wsu.edu> March-June 1993
6 Coherent FS B. Haible <haible@ma2s2.mathematik.uni-karlsruhe.de> June 1993
7
8and was merged together in July 1993.
9
10These filesystems are rather similar. Here is a comparison with Minix FS:
11
12* Linux fdisk reports on partitions
13 - Minix FS 0x81 Linux/Minix
14 - Xenix FS ??
15 - SystemV FS ??
16 - Coherent FS 0x08 AIX bootable
17
18* Size of a block or zone (data allocation unit on disk)
19 - Minix FS 1024
20 - Xenix FS 1024 (also 512 ??)
21 - SystemV FS 1024 (also 512 and 2048)
22 - Coherent FS 512
23
24* General layout: all have one boot block, one super block and
25 separate areas for inodes and for directories/data.
26 On SystemV Release 2 FS (e.g. Microport) the first track is reserved and
27 all the block numbers (including the super block) are offset by one track.
28
29* Byte ordering of "short" (16 bit entities) on disk:
30 - Minix FS little endian 0 1
31 - Xenix FS little endian 0 1
32 - SystemV FS little endian 0 1
33 - Coherent FS little endian 0 1
34 Of course, this affects only the file system, not the data of files on it!
35
36* Byte ordering of "long" (32 bit entities) on disk:
37 - Minix FS little endian 0 1 2 3
38 - Xenix FS little endian 0 1 2 3
39 - SystemV FS little endian 0 1 2 3
40 - Coherent FS PDP-11 2 3 0 1
41 Of course, this affects only the file system, not the data of files on it!
42
43* Inode on disk: "short", 0 means non-existent, the root dir ino is:
44 - Minix FS 1
45 - Xenix FS, SystemV FS, Coherent FS 2
46
47* Maximum number of hard links to a file:
48 - Minix FS 250
49 - Xenix FS ??
50 - SystemV FS ??
51 - Coherent FS >=10000
52
53* Free inode management:
54 - Minix FS a bitmap
55 - Xenix FS, SystemV FS, Coherent FS
56 There is a cache of a certain number of free inodes in the super-block.
57 When it is exhausted, new free inodes are found using a linear search.
58
59* Free block management:
60 - Minix FS a bitmap
61 - Xenix FS, SystemV FS, Coherent FS
62 Free blocks are organized in a "free list". Maybe a misleading term,
63 since it is not true that every free block contains a pointer to
64 the next free block. Rather, the free blocks are organized in chunks
65 of limited size, and every now and then a free block contains pointers
66 to the free blocks pertaining to the next chunk; the first of these
67 contains pointers and so on. The list terminates with a "block number"
68 0 on Xenix FS and SystemV FS, with a block zeroed out on Coherent FS.
69
70* Super-block location:
71 - Minix FS block 1 = bytes 1024..2047
72 - Xenix FS block 1 = bytes 1024..2047
73 - SystemV FS bytes 512..1023
74 - Coherent FS block 1 = bytes 512..1023
75
76* Super-block layout:
77 - Minix FS
78 unsigned short s_ninodes;
79 unsigned short s_nzones;
80 unsigned short s_imap_blocks;
81 unsigned short s_zmap_blocks;
82 unsigned short s_firstdatazone;
83 unsigned short s_log_zone_size;
84 unsigned long s_max_size;
85 unsigned short s_magic;
86 - Xenix FS, SystemV FS, Coherent FS
87 unsigned short s_firstdatazone;
88 unsigned long s_nzones;
89 unsigned short s_fzone_count;
90 unsigned long s_fzones[NICFREE];
91 unsigned short s_finode_count;
92 unsigned short s_finodes[NICINOD];
93 char s_flock;
94 char s_ilock;
95 char s_modified;
96 char s_rdonly;
97 unsigned long s_time;
98 short s_dinfo[4]; -- SystemV FS only
99 unsigned long s_free_zones;
100 unsigned short s_free_inodes;
101 short s_dinfo[4]; -- Xenix FS only
102 unsigned short s_interleave_m,s_interleave_n; -- Coherent FS only
103 char s_fname[6];
104 char s_fpack[6];
105 then they differ considerably:
106 Xenix FS
107 char s_clean;
108 char s_fill[371];
109 long s_magic;
110 long s_type;
111 SystemV FS
112 long s_fill[12 or 14];
113 long s_state;
114 long s_magic;
115 long s_type;
116 Coherent FS
117 unsigned long s_unique;
118 Note that Coherent FS has no magic.
119
120* Inode layout:
121 - Minix FS
122 unsigned short i_mode;
123 unsigned short i_uid;
124 unsigned long i_size;
125 unsigned long i_time;
126 unsigned char i_gid;
127 unsigned char i_nlinks;
128 unsigned short i_zone[7+1+1];
129 - Xenix FS, SystemV FS, Coherent FS
130 unsigned short i_mode;
131 unsigned short i_nlink;
132 unsigned short i_uid;
133 unsigned short i_gid;
134 unsigned long i_size;
135 unsigned char i_zone[3*(10+1+1+1)];
136 unsigned long i_atime;
137 unsigned long i_mtime;
138 unsigned long i_ctime;
139
140* Regular file data blocks are organized as
141 - Minix FS
142 7 direct blocks
143 1 indirect block (pointers to blocks)
144 1 double-indirect block (pointer to pointers to blocks)
145 - Xenix FS, SystemV FS, Coherent FS
146 10 direct blocks
147 1 indirect block (pointers to blocks)
148 1 double-indirect block (pointer to pointers to blocks)
149 1 triple-indirect block (pointer to pointers to pointers to blocks)
150
151* Inode size, inodes per block
152 - Minix FS 32 32
153 - Xenix FS 64 16
154 - SystemV FS 64 16
155 - Coherent FS 64 8
156
157* Directory entry on disk
158 - Minix FS
159 unsigned short inode;
160 char name[14/30];
161 - Xenix FS, SystemV FS, Coherent FS
162 unsigned short inode;
163 char name[14];
164
165* Dir entry size, dir entries per block
166 - Minix FS 16/32 64/32
167 - Xenix FS 16 64
168 - SystemV FS 16 64
169 - Coherent FS 16 32
170
171* How to implement symbolic links such that the host fsck doesn't scream:
172 - Minix FS normal
173 - Xenix FS kludge: as regular files with chmod 1000
174 - SystemV FS ??
175 - Coherent FS kludge: as regular files with chmod 1000
176
177
178Notation: We often speak of a "block" but mean a zone (the allocation unit)
179and not the disk driver's notion of "block".
180
181
182Bruno Haible <haible@ma2s2.mathematik.uni-karlsruhe.de>
diff --git a/fs/sysv/Makefile b/fs/sysv/Makefile
new file mode 100644
index 000000000000..3591f9d7a48a
--- /dev/null
+++ b/fs/sysv/Makefile
@@ -0,0 +1,8 @@
1#
2# Makefile for the Linux SystemV/Coherent filesystem routines.
3#
4
5obj-$(CONFIG_SYSV_FS) += sysv.o
6
7sysv-objs := ialloc.o balloc.o inode.o itree.o file.o dir.o \
8 namei.o super.o symlink.o
diff --git a/fs/sysv/balloc.c b/fs/sysv/balloc.c
new file mode 100644
index 000000000000..9a6ad96acf27
--- /dev/null
+++ b/fs/sysv/balloc.c
@@ -0,0 +1,239 @@
1/*
2 * linux/fs/sysv/balloc.c
3 *
4 * minix/bitmap.c
5 * Copyright (C) 1991, 1992 Linus Torvalds
6 *
7 * ext/freelists.c
8 * Copyright (C) 1992 Remy Card (card@masi.ibp.fr)
9 *
10 * xenix/alloc.c
11 * Copyright (C) 1992 Doug Evans
12 *
13 * coh/alloc.c
14 * Copyright (C) 1993 Pascal Haible, Bruno Haible
15 *
16 * sysv/balloc.c
17 * Copyright (C) 1993 Bruno Haible
18 *
19 * This file contains code for allocating/freeing blocks.
20 */
21
22#include <linux/buffer_head.h>
23#include <linux/string.h>
24#include "sysv.h"
25
26/* We don't trust the value of
27 sb->sv_sbd2->s_tfree = *sb->sv_free_blocks
28 but we nevertheless keep it up to date. */
29
30static inline sysv_zone_t *get_chunk(struct super_block *sb, struct buffer_head *bh)
31{
32 char *bh_data = bh->b_data;
33
34 if (SYSV_SB(sb)->s_type == FSTYPE_SYSV4)
35 return (sysv_zone_t*)(bh_data+4);
36 else
37 return (sysv_zone_t*)(bh_data+2);
38}
39
40/* NOTE NOTE NOTE: nr is a block number _as_ _stored_ _on_ _disk_ */
41
42void sysv_free_block(struct super_block * sb, sysv_zone_t nr)
43{
44 struct sysv_sb_info * sbi = SYSV_SB(sb);
45 struct buffer_head * bh;
46 sysv_zone_t *blocks = sbi->s_bcache;
47 unsigned count;
48 unsigned block = fs32_to_cpu(sbi, nr);
49
50 /*
51 * This code does not work at all for AFS (it has a bitmap
52 * free list). As AFS is supposed to be read-only no one
53 * should call this for an AFS filesystem anyway...
54 */
55 if (sbi->s_type == FSTYPE_AFS)
56 return;
57
58 if (block < sbi->s_firstdatazone || block >= sbi->s_nzones) {
59 printk("sysv_free_block: trying to free block not in datazone\n");
60 return;
61 }
62
63 lock_super(sb);
64 count = fs16_to_cpu(sbi, *sbi->s_bcache_count);
65
66 if (count > sbi->s_flc_size) {
67 printk("sysv_free_block: flc_count > flc_size\n");
68 unlock_super(sb);
69 return;
70 }
71 /* If the free list head in super-block is full, it is copied
72 * into this block being freed, ditto if it's completely empty
73 * (applies only on Coherent).
74 */
75 if (count == sbi->s_flc_size || count == 0) {
76 block += sbi->s_block_base;
77 bh = sb_getblk(sb, block);
78 if (!bh) {
79 printk("sysv_free_block: getblk() failed\n");
80 unlock_super(sb);
81 return;
82 }
83 memset(bh->b_data, 0, sb->s_blocksize);
84 *(__fs16*)bh->b_data = cpu_to_fs16(sbi, count);
85 memcpy(get_chunk(sb,bh), blocks, count * sizeof(sysv_zone_t));
86 mark_buffer_dirty(bh);
87 set_buffer_uptodate(bh);
88 brelse(bh);
89 count = 0;
90 }
91 sbi->s_bcache[count++] = nr;
92
93 *sbi->s_bcache_count = cpu_to_fs16(sbi, count);
94 fs32_add(sbi, sbi->s_free_blocks, 1);
95 dirty_sb(sb);
96 unlock_super(sb);
97}
98
99sysv_zone_t sysv_new_block(struct super_block * sb)
100{
101 struct sysv_sb_info *sbi = SYSV_SB(sb);
102 unsigned int block;
103 sysv_zone_t nr;
104 struct buffer_head * bh;
105 unsigned count;
106
107 lock_super(sb);
108 count = fs16_to_cpu(sbi, *sbi->s_bcache_count);
109
110 if (count == 0) /* Applies only to Coherent FS */
111 goto Enospc;
112 nr = sbi->s_bcache[--count];
113 if (nr == 0) /* Applies only to Xenix FS, SystemV FS */
114 goto Enospc;
115
116 block = fs32_to_cpu(sbi, nr);
117
118 *sbi->s_bcache_count = cpu_to_fs16(sbi, count);
119
120 if (block < sbi->s_firstdatazone || block >= sbi->s_nzones) {
121 printk("sysv_new_block: new block %d is not in data zone\n",
122 block);
123 goto Enospc;
124 }
125
126 if (count == 0) { /* the last block continues the free list */
127 unsigned count;
128
129 block += sbi->s_block_base;
130 if (!(bh = sb_bread(sb, block))) {
131 printk("sysv_new_block: cannot read free-list block\n");
132 /* retry this same block next time */
133 *sbi->s_bcache_count = cpu_to_fs16(sbi, 1);
134 goto Enospc;
135 }
136 count = fs16_to_cpu(sbi, *(__fs16*)bh->b_data);
137 if (count > sbi->s_flc_size) {
138 printk("sysv_new_block: free-list block with >flc_size entries\n");
139 brelse(bh);
140 goto Enospc;
141 }
142 *sbi->s_bcache_count = cpu_to_fs16(sbi, count);
143 memcpy(sbi->s_bcache, get_chunk(sb, bh),
144 count * sizeof(sysv_zone_t));
145 brelse(bh);
146 }
147 /* Now the free list head in the superblock is valid again. */
148 fs32_add(sbi, sbi->s_free_blocks, -1);
149 dirty_sb(sb);
150 unlock_super(sb);
151 return nr;
152
153Enospc:
154 unlock_super(sb);
155 return 0;
156}
157
158unsigned long sysv_count_free_blocks(struct super_block * sb)
159{
160 struct sysv_sb_info * sbi = SYSV_SB(sb);
161 int sb_count;
162 int count;
163 struct buffer_head * bh = NULL;
164 sysv_zone_t *blocks;
165 unsigned block;
166 int n;
167
168 /*
169 * This code does not work at all for AFS (it has a bitmap
170 * free list). As AFS is supposed to be read-only we just
171 * lie and say it has no free block at all.
172 */
173 if (sbi->s_type == FSTYPE_AFS)
174 return 0;
175
176 lock_super(sb);
177 sb_count = fs32_to_cpu(sbi, *sbi->s_free_blocks);
178
179 if (0)
180 goto trust_sb;
181
182 /* this causes a lot of disk traffic ... */
183 count = 0;
184 n = fs16_to_cpu(sbi, *sbi->s_bcache_count);
185 blocks = sbi->s_bcache;
186 while (1) {
187 sysv_zone_t zone;
188 if (n > sbi->s_flc_size)
189 goto E2big;
190 zone = 0;
191 while (n && (zone = blocks[--n]) != 0)
192 count++;
193 if (zone == 0)
194 break;
195
196 block = fs32_to_cpu(sbi, zone);
197 if (bh)
198 brelse(bh);
199
200 if (block < sbi->s_firstdatazone || block >= sbi->s_nzones)
201 goto Einval;
202 block += sbi->s_block_base;
203 bh = sb_bread(sb, block);
204 if (!bh)
205 goto Eio;
206 n = fs16_to_cpu(sbi, *(__fs16*)bh->b_data);
207 blocks = get_chunk(sb, bh);
208 }
209 if (bh)
210 brelse(bh);
211 if (count != sb_count)
212 goto Ecount;
213done:
214 unlock_super(sb);
215 return count;
216
217Einval:
218 printk("sysv_count_free_blocks: new block %d is not in data zone\n",
219 block);
220 goto trust_sb;
221Eio:
222 printk("sysv_count_free_blocks: cannot read free-list block\n");
223 goto trust_sb;
224E2big:
225 printk("sysv_count_free_blocks: >flc_size entries in free-list block\n");
226 if (bh)
227 brelse(bh);
228trust_sb:
229 count = sb_count;
230 goto done;
231Ecount:
232 printk("sysv_count_free_blocks: free block count was %d, "
233 "correcting to %d\n", sb_count, count);
234 if (!(sb->s_flags & MS_RDONLY)) {
235 *sbi->s_free_blocks = cpu_to_fs32(sbi, count);
236 dirty_sb(sb);
237 }
238 goto done;
239}
diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c
new file mode 100644
index 000000000000..69a085abad6f
--- /dev/null
+++ b/fs/sysv/dir.c
@@ -0,0 +1,388 @@
1/*
2 * linux/fs/sysv/dir.c
3 *
4 * minix/dir.c
5 * Copyright (C) 1991, 1992 Linus Torvalds
6 *
7 * coh/dir.c
8 * Copyright (C) 1993 Pascal Haible, Bruno Haible
9 *
10 * sysv/dir.c
11 * Copyright (C) 1993 Bruno Haible
12 *
13 * SystemV/Coherent directory handling functions
14 */
15
16#include <linux/pagemap.h>
17#include <linux/highmem.h>
18#include <linux/smp_lock.h>
19#include "sysv.h"
20
21static int sysv_readdir(struct file *, void *, filldir_t);
22
23struct file_operations sysv_dir_operations = {
24 .read = generic_read_dir,
25 .readdir = sysv_readdir,
26 .fsync = sysv_sync_file,
27};
28
29static inline void dir_put_page(struct page *page)
30{
31 kunmap(page);
32 page_cache_release(page);
33}
34
35static inline unsigned long dir_pages(struct inode *inode)
36{
37 return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT;
38}
39
40static int dir_commit_chunk(struct page *page, unsigned from, unsigned to)
41{
42 struct inode *dir = (struct inode *)page->mapping->host;
43 int err = 0;
44
45 page->mapping->a_ops->commit_write(NULL, page, from, to);
46 if (IS_DIRSYNC(dir))
47 err = write_one_page(page, 1);
48 else
49 unlock_page(page);
50 return err;
51}
52
53static struct page * dir_get_page(struct inode *dir, unsigned long n)
54{
55 struct address_space *mapping = dir->i_mapping;
56 struct page *page = read_cache_page(mapping, n,
57 (filler_t*)mapping->a_ops->readpage, NULL);
58 if (!IS_ERR(page)) {
59 wait_on_page_locked(page);
60 kmap(page);
61 if (!PageUptodate(page))
62 goto fail;
63 }
64 return page;
65
66fail:
67 dir_put_page(page);
68 return ERR_PTR(-EIO);
69}
70
71static int sysv_readdir(struct file * filp, void * dirent, filldir_t filldir)
72{
73 unsigned long pos = filp->f_pos;
74 struct inode *inode = filp->f_dentry->d_inode;
75 struct super_block *sb = inode->i_sb;
76 unsigned offset = pos & ~PAGE_CACHE_MASK;
77 unsigned long n = pos >> PAGE_CACHE_SHIFT;
78 unsigned long npages = dir_pages(inode);
79
80 lock_kernel();
81
82 pos = (pos + SYSV_DIRSIZE-1) & ~(SYSV_DIRSIZE-1);
83 if (pos >= inode->i_size)
84 goto done;
85
86 for ( ; n < npages; n++, offset = 0) {
87 char *kaddr, *limit;
88 struct sysv_dir_entry *de;
89 struct page *page = dir_get_page(inode, n);
90
91 if (IS_ERR(page))
92 continue;
93 kaddr = (char *)page_address(page);
94 de = (struct sysv_dir_entry *)(kaddr+offset);
95 limit = kaddr + PAGE_CACHE_SIZE - SYSV_DIRSIZE;
96 for ( ;(char*)de <= limit; de++) {
97 char *name = de->name;
98 int over;
99
100 if (!de->inode)
101 continue;
102
103 offset = (char *)de - kaddr;
104
105 over = filldir(dirent, name, strnlen(name,SYSV_NAMELEN),
106 (n<<PAGE_CACHE_SHIFT) | offset,
107 fs16_to_cpu(SYSV_SB(sb), de->inode),
108 DT_UNKNOWN);
109 if (over) {
110 dir_put_page(page);
111 goto done;
112 }
113 }
114 dir_put_page(page);
115 }
116
117done:
118 filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset;
119 unlock_kernel();
120 return 0;
121}
122
123/* compare strings: name[0..len-1] (not zero-terminated) and
124 * buffer[0..] (filled with zeroes up to buffer[0..maxlen-1])
125 */
126static inline int namecompare(int len, int maxlen,
127 const char * name, const char * buffer)
128{
129 if (len < maxlen && buffer[len])
130 return 0;
131 return !memcmp(name, buffer, len);
132}
133
134/*
135 * sysv_find_entry()
136 *
137 * finds an entry in the specified directory with the wanted name. It
138 * returns the cache buffer in which the entry was found, and the entry
139 * itself (as a parameter - res_dir). It does NOT read the inode of the
140 * entry - you'll have to do that yourself if you want to.
141 */
142struct sysv_dir_entry *sysv_find_entry(struct dentry *dentry, struct page **res_page)
143{
144 const char * name = dentry->d_name.name;
145 int namelen = dentry->d_name.len;
146 struct inode * dir = dentry->d_parent->d_inode;
147 unsigned long start, n;
148 unsigned long npages = dir_pages(dir);
149 struct page *page = NULL;
150 struct sysv_dir_entry *de;
151
152 *res_page = NULL;
153
154 start = SYSV_I(dir)->i_dir_start_lookup;
155 if (start >= npages)
156 start = 0;
157 n = start;
158
159 do {
160 char *kaddr;
161 page = dir_get_page(dir, n);
162 if (!IS_ERR(page)) {
163 kaddr = (char*)page_address(page);
164 de = (struct sysv_dir_entry *) kaddr;
165 kaddr += PAGE_CACHE_SIZE - SYSV_DIRSIZE;
166 for ( ; (char *) de <= kaddr ; de++) {
167 if (!de->inode)
168 continue;
169 if (namecompare(namelen, SYSV_NAMELEN,
170 name, de->name))
171 goto found;
172 }
173 }
174 dir_put_page(page);
175
176 if (++n >= npages)
177 n = 0;
178 } while (n != start);
179
180 return NULL;
181
182found:
183 SYSV_I(dir)->i_dir_start_lookup = n;
184 *res_page = page;
185 return de;
186}
187
188int sysv_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 page *page = NULL;
194 struct sysv_dir_entry * de;
195 unsigned long npages = dir_pages(dir);
196 unsigned long n;
197 char *kaddr;
198 unsigned from, to;
199 int err;
200
201 /* We take care of directory expansion in the same loop */
202 for (n = 0; n <= npages; n++) {
203 page = dir_get_page(dir, n);
204 err = PTR_ERR(page);
205 if (IS_ERR(page))
206 goto out;
207 kaddr = (char*)page_address(page);
208 de = (struct sysv_dir_entry *)kaddr;
209 kaddr += PAGE_CACHE_SIZE - SYSV_DIRSIZE;
210 while ((char *)de <= kaddr) {
211 if (!de->inode)
212 goto got_it;
213 err = -EEXIST;
214 if (namecompare(namelen, SYSV_NAMELEN, name, de->name))
215 goto out_page;
216 de++;
217 }
218 dir_put_page(page);
219 }
220 BUG();
221 return -EINVAL;
222
223got_it:
224 from = (char*)de - (char*)page_address(page);
225 to = from + SYSV_DIRSIZE;
226 lock_page(page);
227 err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
228 if (err)
229 goto out_unlock;
230 memcpy (de->name, name, namelen);
231 memset (de->name + namelen, 0, SYSV_DIRSIZE - namelen - 2);
232 de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), inode->i_ino);
233 err = dir_commit_chunk(page, from, to);
234 dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
235 mark_inode_dirty(dir);
236out_page:
237 dir_put_page(page);
238out:
239 return err;
240out_unlock:
241 unlock_page(page);
242 goto out_page;
243}
244
245int sysv_delete_entry(struct sysv_dir_entry *de, struct page *page)
246{
247 struct address_space *mapping = page->mapping;
248 struct inode *inode = (struct inode*)mapping->host;
249 char *kaddr = (char*)page_address(page);
250 unsigned from = (char*)de - kaddr;
251 unsigned to = from + SYSV_DIRSIZE;
252 int err;
253
254 lock_page(page);
255 err = mapping->a_ops->prepare_write(NULL, page, from, to);
256 if (err)
257 BUG();
258 de->inode = 0;
259 err = dir_commit_chunk(page, from, to);
260 dir_put_page(page);
261 inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
262 mark_inode_dirty(inode);
263 return err;
264}
265
266int sysv_make_empty(struct inode *inode, struct inode *dir)
267{
268 struct address_space *mapping = inode->i_mapping;
269 struct page *page = grab_cache_page(mapping, 0);
270 struct sysv_dir_entry * de;
271 char *base;
272 int err;
273
274 if (!page)
275 return -ENOMEM;
276 kmap(page);
277 err = mapping->a_ops->prepare_write(NULL, page, 0, 2 * SYSV_DIRSIZE);
278 if (err) {
279 unlock_page(page);
280 goto fail;
281 }
282
283 base = (char*)page_address(page);
284 memset(base, 0, PAGE_CACHE_SIZE);
285
286 de = (struct sysv_dir_entry *) base;
287 de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), inode->i_ino);
288 strcpy(de->name,".");
289 de++;
290 de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), dir->i_ino);
291 strcpy(de->name,"..");
292
293 err = dir_commit_chunk(page, 0, 2 * SYSV_DIRSIZE);
294fail:
295 kunmap(page);
296 page_cache_release(page);
297 return err;
298}
299
300/*
301 * routine to check that the specified directory is empty (for rmdir)
302 */
303int sysv_empty_dir(struct inode * inode)
304{
305 struct super_block *sb = inode->i_sb;
306 struct page *page = NULL;
307 unsigned long i, npages = dir_pages(inode);
308
309 for (i = 0; i < npages; i++) {
310 char *kaddr;
311 struct sysv_dir_entry * de;
312 page = dir_get_page(inode, i);
313
314 if (IS_ERR(page))
315 continue;
316
317 kaddr = (char *)page_address(page);
318 de = (struct sysv_dir_entry *)kaddr;
319 kaddr += PAGE_CACHE_SIZE-SYSV_DIRSIZE;
320
321 for ( ;(char *)de <= kaddr; de++) {
322 if (!de->inode)
323 continue;
324 /* check for . and .. */
325 if (de->name[0] != '.')
326 goto not_empty;
327 if (!de->name[1]) {
328 if (de->inode == cpu_to_fs16(SYSV_SB(sb),
329 inode->i_ino))
330 continue;
331 goto not_empty;
332 }
333 if (de->name[1] != '.' || de->name[2])
334 goto not_empty;
335 }
336 dir_put_page(page);
337 }
338 return 1;
339
340not_empty:
341 dir_put_page(page);
342 return 0;
343}
344
345/* Releases the page */
346void sysv_set_link(struct sysv_dir_entry *de, struct page *page,
347 struct inode *inode)
348{
349 struct inode *dir = (struct inode*)page->mapping->host;
350 unsigned from = (char *)de-(char*)page_address(page);
351 unsigned to = from + SYSV_DIRSIZE;
352 int err;
353
354 lock_page(page);
355 err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
356 if (err)
357 BUG();
358 de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), inode->i_ino);
359 err = dir_commit_chunk(page, from, to);
360 dir_put_page(page);
361 dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
362 mark_inode_dirty(dir);
363}
364
365struct sysv_dir_entry * sysv_dotdot (struct inode *dir, struct page **p)
366{
367 struct page *page = dir_get_page(dir, 0);
368 struct sysv_dir_entry *de = NULL;
369
370 if (!IS_ERR(page)) {
371 de = (struct sysv_dir_entry*) page_address(page) + 1;
372 *p = page;
373 }
374 return de;
375}
376
377ino_t sysv_inode_by_name(struct dentry *dentry)
378{
379 struct page *page;
380 struct sysv_dir_entry *de = sysv_find_entry (dentry, &page);
381 ino_t res = 0;
382
383 if (de) {
384 res = fs16_to_cpu(SYSV_SB(dentry->d_sb), de->inode);
385 dir_put_page(page);
386 }
387 return res;
388}
diff --git a/fs/sysv/file.c b/fs/sysv/file.c
new file mode 100644
index 000000000000..da69abc06240
--- /dev/null
+++ b/fs/sysv/file.c
@@ -0,0 +1,49 @@
1/*
2 * linux/fs/sysv/file.c
3 *
4 * minix/file.c
5 * Copyright (C) 1991, 1992 Linus Torvalds
6 *
7 * coh/file.c
8 * Copyright (C) 1993 Pascal Haible, Bruno Haible
9 *
10 * sysv/file.c
11 * Copyright (C) 1993 Bruno Haible
12 *
13 * SystemV/Coherent regular file handling primitives
14 */
15
16#include "sysv.h"
17
18/*
19 * We have mostly NULLs here: the current defaults are OK for
20 * the coh filesystem.
21 */
22struct file_operations sysv_file_operations = {
23 .llseek = generic_file_llseek,
24 .read = generic_file_read,
25 .write = generic_file_write,
26 .mmap = generic_file_mmap,
27 .fsync = sysv_sync_file,
28 .sendfile = generic_file_sendfile,
29};
30
31struct inode_operations sysv_file_inode_operations = {
32 .truncate = sysv_truncate,
33 .getattr = sysv_getattr,
34};
35
36int sysv_sync_file(struct file * file, struct dentry *dentry, int datasync)
37{
38 struct inode *inode = dentry->d_inode;
39 int err;
40
41 err = sync_mapping_buffers(inode->i_mapping);
42 if (!(inode->i_state & I_DIRTY))
43 return err;
44 if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
45 return err;
46
47 err |= sysv_sync_inode(inode);
48 return err ? -EIO : 0;
49}
diff --git a/fs/sysv/ialloc.c b/fs/sysv/ialloc.c
new file mode 100644
index 000000000000..9b585d1081c0
--- /dev/null
+++ b/fs/sysv/ialloc.c
@@ -0,0 +1,240 @@
1/*
2 * linux/fs/sysv/ialloc.c
3 *
4 * minix/bitmap.c
5 * Copyright (C) 1991, 1992 Linus Torvalds
6 *
7 * ext/freelists.c
8 * Copyright (C) 1992 Remy Card (card@masi.ibp.fr)
9 *
10 * xenix/alloc.c
11 * Copyright (C) 1992 Doug Evans
12 *
13 * coh/alloc.c
14 * Copyright (C) 1993 Pascal Haible, Bruno Haible
15 *
16 * sysv/ialloc.c
17 * Copyright (C) 1993 Bruno Haible
18 *
19 * This file contains code for allocating/freeing inodes.
20 */
21
22#include <linux/kernel.h>
23#include <linux/stddef.h>
24#include <linux/sched.h>
25#include <linux/stat.h>
26#include <linux/string.h>
27#include <linux/buffer_head.h>
28#include "sysv.h"
29
30/* We don't trust the value of
31 sb->sv_sbd2->s_tinode = *sb->sv_sb_total_free_inodes
32 but we nevertheless keep it up to date. */
33
34/* An inode on disk is considered free if both i_mode == 0 and i_nlink == 0. */
35
36/* return &sb->sv_sb_fic_inodes[i] = &sbd->s_inode[i]; */
37static inline sysv_ino_t *
38sv_sb_fic_inode(struct super_block * sb, unsigned int i)
39{
40 struct sysv_sb_info *sbi = SYSV_SB(sb);
41
42 if (sbi->s_bh1 == sbi->s_bh2)
43 return &sbi->s_sb_fic_inodes[i];
44 else {
45 /* 512 byte Xenix FS */
46 unsigned int offset = offsetof(struct xenix_super_block, s_inode[i]);
47 if (offset < 512)
48 return (sysv_ino_t*)(sbi->s_sbd1 + offset);
49 else
50 return (sysv_ino_t*)(sbi->s_sbd2 + offset);
51 }
52}
53
54struct sysv_inode *
55sysv_raw_inode(struct super_block *sb, unsigned ino, struct buffer_head **bh)
56{
57 struct sysv_sb_info *sbi = SYSV_SB(sb);
58 struct sysv_inode *res;
59 int block = sbi->s_firstinodezone + sbi->s_block_base;
60
61 block += (ino-1) >> sbi->s_inodes_per_block_bits;
62 *bh = sb_bread(sb, block);
63 if (!*bh)
64 return NULL;
65 res = (struct sysv_inode *)(*bh)->b_data;
66 return res + ((ino-1) & sbi->s_inodes_per_block_1);
67}
68
69static int refill_free_cache(struct super_block *sb)
70{
71 struct sysv_sb_info *sbi = SYSV_SB(sb);
72 struct buffer_head * bh;
73 struct sysv_inode * raw_inode;
74 int i = 0, ino;
75
76 ino = SYSV_ROOT_INO+1;
77 raw_inode = sysv_raw_inode(sb, ino, &bh);
78 if (!raw_inode)
79 goto out;
80 while (ino <= sbi->s_ninodes) {
81 if (raw_inode->i_mode == 0 && raw_inode->i_nlink == 0) {
82 *sv_sb_fic_inode(sb,i++) = cpu_to_fs16(SYSV_SB(sb), ino);
83 if (i == sbi->s_fic_size)
84 break;
85 }
86 if ((ino++ & sbi->s_inodes_per_block_1) == 0) {
87 brelse(bh);
88 raw_inode = sysv_raw_inode(sb, ino, &bh);
89 if (!raw_inode)
90 goto out;
91 } else
92 raw_inode++;
93 }
94 brelse(bh);
95out:
96 return i;
97}
98
99void sysv_free_inode(struct inode * inode)
100{
101 struct super_block *sb = inode->i_sb;
102 struct sysv_sb_info *sbi = SYSV_SB(sb);
103 unsigned int ino;
104 struct buffer_head * bh;
105 struct sysv_inode * raw_inode;
106 unsigned count;
107
108 sb = inode->i_sb;
109 ino = inode->i_ino;
110 if (ino <= SYSV_ROOT_INO || ino > sbi->s_ninodes) {
111 printk("sysv_free_inode: inode 0,1,2 or nonexistent inode\n");
112 return;
113 }
114 raw_inode = sysv_raw_inode(sb, ino, &bh);
115 clear_inode(inode);
116 if (!raw_inode) {
117 printk("sysv_free_inode: unable to read inode block on device "
118 "%s\n", inode->i_sb->s_id);
119 return;
120 }
121 lock_super(sb);
122 count = fs16_to_cpu(sbi, *sbi->s_sb_fic_count);
123 if (count < sbi->s_fic_size) {
124 *sv_sb_fic_inode(sb,count++) = cpu_to_fs16(sbi, ino);
125 *sbi->s_sb_fic_count = cpu_to_fs16(sbi, count);
126 }
127 fs16_add(sbi, sbi->s_sb_total_free_inodes, 1);
128 dirty_sb(sb);
129 memset(raw_inode, 0, sizeof(struct sysv_inode));
130 mark_buffer_dirty(bh);
131 unlock_super(sb);
132 brelse(bh);
133}
134
135struct inode * sysv_new_inode(const struct inode * dir, mode_t mode)
136{
137 struct super_block *sb = dir->i_sb;
138 struct sysv_sb_info *sbi = SYSV_SB(sb);
139 struct inode *inode;
140 sysv_ino_t ino;
141 unsigned count;
142
143 inode = new_inode(sb);
144 if (!inode)
145 return ERR_PTR(-ENOMEM);
146
147 lock_super(sb);
148 count = fs16_to_cpu(sbi, *sbi->s_sb_fic_count);
149 if (count == 0 || (*sv_sb_fic_inode(sb,count-1) == 0)) {
150 count = refill_free_cache(sb);
151 if (count == 0) {
152 iput(inode);
153 unlock_super(sb);
154 return ERR_PTR(-ENOSPC);
155 }
156 }
157 /* Now count > 0. */
158 ino = *sv_sb_fic_inode(sb,--count);
159 *sbi->s_sb_fic_count = cpu_to_fs16(sbi, count);
160 fs16_add(sbi, sbi->s_sb_total_free_inodes, -1);
161 dirty_sb(sb);
162
163 if (dir->i_mode & S_ISGID) {
164 inode->i_gid = dir->i_gid;
165 if (S_ISDIR(mode))
166 mode |= S_ISGID;
167 } else
168 inode->i_gid = current->fsgid;
169
170 inode->i_uid = current->fsuid;
171 inode->i_ino = fs16_to_cpu(sbi, ino);
172 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
173 inode->i_blocks = inode->i_blksize = 0;
174 memset(SYSV_I(inode)->i_data, 0, sizeof(SYSV_I(inode)->i_data));
175 SYSV_I(inode)->i_dir_start_lookup = 0;
176 insert_inode_hash(inode);
177 mark_inode_dirty(inode);
178
179 inode->i_mode = mode; /* for sysv_write_inode() */
180 sysv_write_inode(inode, 0); /* ensure inode not allocated again */
181 mark_inode_dirty(inode); /* cleared by sysv_write_inode() */
182 /* That's it. */
183 unlock_super(sb);
184 return inode;
185}
186
187unsigned long sysv_count_free_inodes(struct super_block * sb)
188{
189 struct sysv_sb_info *sbi = SYSV_SB(sb);
190 struct buffer_head * bh;
191 struct sysv_inode * raw_inode;
192 int ino, count, sb_count;
193
194 lock_super(sb);
195
196 sb_count = fs16_to_cpu(sbi, *sbi->s_sb_total_free_inodes);
197
198 if (0)
199 goto trust_sb;
200
201 /* this causes a lot of disk traffic ... */
202 count = 0;
203 ino = SYSV_ROOT_INO+1;
204 raw_inode = sysv_raw_inode(sb, ino, &bh);
205 if (!raw_inode)
206 goto Eio;
207 while (ino <= sbi->s_ninodes) {
208 if (raw_inode->i_mode == 0 && raw_inode->i_nlink == 0)
209 count++;
210 if ((ino++ & sbi->s_inodes_per_block_1) == 0) {
211 brelse(bh);
212 raw_inode = sysv_raw_inode(sb, ino, &bh);
213 if (!raw_inode)
214 goto Eio;
215 } else
216 raw_inode++;
217 }
218 brelse(bh);
219 if (count != sb_count)
220 goto Einval;
221out:
222 unlock_super(sb);
223 return count;
224
225Einval:
226 printk("sysv_count_free_inodes: "
227 "free inode count was %d, correcting to %d\n",
228 sb_count, count);
229 if (!(sb->s_flags & MS_RDONLY)) {
230 *sbi->s_sb_total_free_inodes = cpu_to_fs16(SYSV_SB(sb), count);
231 dirty_sb(sb);
232 }
233 goto out;
234
235Eio:
236 printk("sysv_count_free_inodes: unable to read inode table\n");
237trust_sb:
238 count = sb_count;
239 goto out;
240}
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
new file mode 100644
index 000000000000..0530077d9dd8
--- /dev/null
+++ b/fs/sysv/inode.c
@@ -0,0 +1,354 @@
1/*
2 * linux/fs/sysv/inode.c
3 *
4 * minix/inode.c
5 * Copyright (C) 1991, 1992 Linus Torvalds
6 *
7 * xenix/inode.c
8 * Copyright (C) 1992 Doug Evans
9 *
10 * coh/inode.c
11 * Copyright (C) 1993 Pascal Haible, Bruno Haible
12 *
13 * sysv/inode.c
14 * Copyright (C) 1993 Paul B. Monday
15 *
16 * sysv/inode.c
17 * Copyright (C) 1993 Bruno Haible
18 * Copyright (C) 1997, 1998 Krzysztof G. Baranowski
19 *
20 * This file contains code for allocating/freeing inodes and for read/writing
21 * the superblock.
22 */
23
24#include <linux/smp_lock.h>
25#include <linux/highuid.h>
26#include <linux/slab.h>
27#include <linux/init.h>
28#include <linux/buffer_head.h>
29#include <linux/vfs.h>
30#include <asm/byteorder.h>
31#include "sysv.h"
32
33/* This is only called on sync() and umount(), when s_dirt=1. */
34static void sysv_write_super(struct super_block *sb)
35{
36 struct sysv_sb_info *sbi = SYSV_SB(sb);
37 unsigned long time = get_seconds(), old_time;
38
39 lock_kernel();
40 if (sb->s_flags & MS_RDONLY)
41 goto clean;
42
43 /*
44 * If we are going to write out the super block,
45 * then attach current time stamp.
46 * But if the filesystem was marked clean, keep it clean.
47 */
48 old_time = fs32_to_cpu(sbi, *sbi->s_sb_time);
49 if (sbi->s_type == FSTYPE_SYSV4) {
50 if (*sbi->s_sb_state == cpu_to_fs32(sbi, 0x7c269d38 - old_time))
51 *sbi->s_sb_state = cpu_to_fs32(sbi, 0x7c269d38 - time);
52 *sbi->s_sb_time = cpu_to_fs32(sbi, time);
53 mark_buffer_dirty(sbi->s_bh2);
54 }
55clean:
56 sb->s_dirt = 0;
57 unlock_kernel();
58}
59
60static int sysv_remount(struct super_block *sb, int *flags, char *data)
61{
62 struct sysv_sb_info *sbi = SYSV_SB(sb);
63 if (sbi->s_forced_ro)
64 *flags |= MS_RDONLY;
65 if (!(*flags & MS_RDONLY))
66 sb->s_dirt = 1;
67 return 0;
68}
69
70static void sysv_put_super(struct super_block *sb)
71{
72 struct sysv_sb_info *sbi = SYSV_SB(sb);
73
74 if (!(sb->s_flags & MS_RDONLY)) {
75 /* XXX ext2 also updates the state here */
76 mark_buffer_dirty(sbi->s_bh1);
77 if (sbi->s_bh1 != sbi->s_bh2)
78 mark_buffer_dirty(sbi->s_bh2);
79 }
80
81 brelse(sbi->s_bh1);
82 if (sbi->s_bh1 != sbi->s_bh2)
83 brelse(sbi->s_bh2);
84
85 kfree(sbi);
86}
87
88static int sysv_statfs(struct super_block *sb, struct kstatfs *buf)
89{
90 struct sysv_sb_info *sbi = SYSV_SB(sb);
91
92 buf->f_type = sb->s_magic;
93 buf->f_bsize = sb->s_blocksize;
94 buf->f_blocks = sbi->s_ndatazones;
95 buf->f_bavail = buf->f_bfree = sysv_count_free_blocks(sb);
96 buf->f_files = sbi->s_ninodes;
97 buf->f_ffree = sysv_count_free_inodes(sb);
98 buf->f_namelen = SYSV_NAMELEN;
99 return 0;
100}
101
102/*
103 * NXI <-> N0XI for PDP, XIN <-> XIN0 for le32, NIX <-> 0NIX for be32
104 */
105static inline void read3byte(struct sysv_sb_info *sbi,
106 unsigned char * from, unsigned char * to)
107{
108 if (sbi->s_bytesex == BYTESEX_PDP) {
109 to[0] = from[0];
110 to[1] = 0;
111 to[2] = from[1];
112 to[3] = from[2];
113 } else if (sbi->s_bytesex == BYTESEX_LE) {
114 to[0] = from[0];
115 to[1] = from[1];
116 to[2] = from[2];
117 to[3] = 0;
118 } else {
119 to[0] = 0;
120 to[1] = from[0];
121 to[2] = from[1];
122 to[3] = from[2];
123 }
124}
125
126static inline void write3byte(struct sysv_sb_info *sbi,
127 unsigned char * from, unsigned char * to)
128{
129 if (sbi->s_bytesex == BYTESEX_PDP) {
130 to[0] = from[0];
131 to[1] = from[2];
132 to[2] = from[3];
133 } else if (sbi->s_bytesex == BYTESEX_LE) {
134 to[0] = from[0];
135 to[1] = from[1];
136 to[2] = from[2];
137 } else {
138 to[0] = from[1];
139 to[1] = from[2];
140 to[2] = from[3];
141 }
142}
143
144static struct inode_operations sysv_symlink_inode_operations = {
145 .readlink = generic_readlink,
146 .follow_link = page_follow_link_light,
147 .put_link = page_put_link,
148 .getattr = sysv_getattr,
149};
150
151void sysv_set_inode(struct inode *inode, dev_t rdev)
152{
153 if (S_ISREG(inode->i_mode)) {
154 inode->i_op = &sysv_file_inode_operations;
155 inode->i_fop = &sysv_file_operations;
156 inode->i_mapping->a_ops = &sysv_aops;
157 } else if (S_ISDIR(inode->i_mode)) {
158 inode->i_op = &sysv_dir_inode_operations;
159 inode->i_fop = &sysv_dir_operations;
160 inode->i_mapping->a_ops = &sysv_aops;
161 } else if (S_ISLNK(inode->i_mode)) {
162 if (inode->i_blocks) {
163 inode->i_op = &sysv_symlink_inode_operations;
164 inode->i_mapping->a_ops = &sysv_aops;
165 } else
166 inode->i_op = &sysv_fast_symlink_inode_operations;
167 } else
168 init_special_inode(inode, inode->i_mode, rdev);
169}
170
171static void sysv_read_inode(struct inode *inode)
172{
173 struct super_block * sb = inode->i_sb;
174 struct sysv_sb_info * sbi = SYSV_SB(sb);
175 struct buffer_head * bh;
176 struct sysv_inode * raw_inode;
177 struct sysv_inode_info * si;
178 unsigned int block, ino = inode->i_ino;
179
180 if (!ino || ino > sbi->s_ninodes) {
181 printk("Bad inode number on dev %s: %d is out of range\n",
182 inode->i_sb->s_id, ino);
183 goto bad_inode;
184 }
185 raw_inode = sysv_raw_inode(sb, ino, &bh);
186 if (!raw_inode) {
187 printk("Major problem: unable to read inode from dev %s\n",
188 inode->i_sb->s_id);
189 goto bad_inode;
190 }
191 /* SystemV FS: kludge permissions if ino==SYSV_ROOT_INO ?? */
192 inode->i_mode = fs16_to_cpu(sbi, raw_inode->i_mode);
193 inode->i_uid = (uid_t)fs16_to_cpu(sbi, raw_inode->i_uid);
194 inode->i_gid = (gid_t)fs16_to_cpu(sbi, raw_inode->i_gid);
195 inode->i_nlink = fs16_to_cpu(sbi, raw_inode->i_nlink);
196 inode->i_size = fs32_to_cpu(sbi, raw_inode->i_size);
197 inode->i_atime.tv_sec = fs32_to_cpu(sbi, raw_inode->i_atime);
198 inode->i_mtime.tv_sec = fs32_to_cpu(sbi, raw_inode->i_mtime);
199 inode->i_ctime.tv_sec = fs32_to_cpu(sbi, raw_inode->i_ctime);
200 inode->i_ctime.tv_nsec = 0;
201 inode->i_atime.tv_nsec = 0;
202 inode->i_mtime.tv_nsec = 0;
203 inode->i_blocks = inode->i_blksize = 0;
204
205 si = SYSV_I(inode);
206 for (block = 0; block < 10+1+1+1; block++)
207 read3byte(sbi, &raw_inode->i_data[3*block],
208 (u8 *)&si->i_data[block]);
209 brelse(bh);
210 si->i_dir_start_lookup = 0;
211 if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
212 sysv_set_inode(inode,
213 old_decode_dev(fs32_to_cpu(sbi, si->i_data[0])));
214 else
215 sysv_set_inode(inode, 0);
216 return;
217
218bad_inode:
219 make_bad_inode(inode);
220 return;
221}
222
223static struct buffer_head * sysv_update_inode(struct inode * inode)
224{
225 struct super_block * sb = inode->i_sb;
226 struct sysv_sb_info * sbi = SYSV_SB(sb);
227 struct buffer_head * bh;
228 struct sysv_inode * raw_inode;
229 struct sysv_inode_info * si;
230 unsigned int ino, block;
231
232 ino = inode->i_ino;
233 if (!ino || ino > sbi->s_ninodes) {
234 printk("Bad inode number on dev %s: %d is out of range\n",
235 inode->i_sb->s_id, ino);
236 return NULL;
237 }
238 raw_inode = sysv_raw_inode(sb, ino, &bh);
239 if (!raw_inode) {
240 printk("unable to read i-node block\n");
241 return NULL;
242 }
243
244 raw_inode->i_mode = cpu_to_fs16(sbi, inode->i_mode);
245 raw_inode->i_uid = cpu_to_fs16(sbi, fs_high2lowuid(inode->i_uid));
246 raw_inode->i_gid = cpu_to_fs16(sbi, fs_high2lowgid(inode->i_gid));
247 raw_inode->i_nlink = cpu_to_fs16(sbi, inode->i_nlink);
248 raw_inode->i_size = cpu_to_fs32(sbi, inode->i_size);
249 raw_inode->i_atime = cpu_to_fs32(sbi, inode->i_atime.tv_sec);
250 raw_inode->i_mtime = cpu_to_fs32(sbi, inode->i_mtime.tv_sec);
251 raw_inode->i_ctime = cpu_to_fs32(sbi, inode->i_ctime.tv_sec);
252
253 si = SYSV_I(inode);
254 if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
255 si->i_data[0] = cpu_to_fs32(sbi, old_encode_dev(inode->i_rdev));
256 for (block = 0; block < 10+1+1+1; block++)
257 write3byte(sbi, (u8 *)&si->i_data[block],
258 &raw_inode->i_data[3*block]);
259 mark_buffer_dirty(bh);
260 return bh;
261}
262
263int sysv_write_inode(struct inode * inode, int wait)
264{
265 struct buffer_head *bh;
266 lock_kernel();
267 bh = sysv_update_inode(inode);
268 brelse(bh);
269 unlock_kernel();
270 return 0;
271}
272
273int sysv_sync_inode(struct inode * inode)
274{
275 int err = 0;
276 struct buffer_head *bh;
277
278 bh = sysv_update_inode(inode);
279 if (bh && buffer_dirty(bh)) {
280 sync_dirty_buffer(bh);
281 if (buffer_req(bh) && !buffer_uptodate(bh)) {
282 printk ("IO error syncing sysv inode [%s:%08lx]\n",
283 inode->i_sb->s_id, inode->i_ino);
284 err = -1;
285 }
286 }
287 else if (!bh)
288 err = -1;
289 brelse (bh);
290 return err;
291}
292
293static void sysv_delete_inode(struct inode *inode)
294{
295 inode->i_size = 0;
296 sysv_truncate(inode);
297 lock_kernel();
298 sysv_free_inode(inode);
299 unlock_kernel();
300}
301
302static kmem_cache_t *sysv_inode_cachep;
303
304static struct inode *sysv_alloc_inode(struct super_block *sb)
305{
306 struct sysv_inode_info *si;
307
308 si = kmem_cache_alloc(sysv_inode_cachep, SLAB_KERNEL);
309 if (!si)
310 return NULL;
311 return &si->vfs_inode;
312}
313
314static void sysv_destroy_inode(struct inode *inode)
315{
316 kmem_cache_free(sysv_inode_cachep, SYSV_I(inode));
317}
318
319static void init_once(void *p, kmem_cache_t *cachep, unsigned long flags)
320{
321 struct sysv_inode_info *si = (struct sysv_inode_info *)p;
322
323 if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
324 SLAB_CTOR_CONSTRUCTOR)
325 inode_init_once(&si->vfs_inode);
326}
327
328struct super_operations sysv_sops = {
329 .alloc_inode = sysv_alloc_inode,
330 .destroy_inode = sysv_destroy_inode,
331 .read_inode = sysv_read_inode,
332 .write_inode = sysv_write_inode,
333 .delete_inode = sysv_delete_inode,
334 .put_super = sysv_put_super,
335 .write_super = sysv_write_super,
336 .remount_fs = sysv_remount,
337 .statfs = sysv_statfs,
338};
339
340int __init sysv_init_icache(void)
341{
342 sysv_inode_cachep = kmem_cache_create("sysv_inode_cache",
343 sizeof(struct sysv_inode_info), 0,
344 SLAB_RECLAIM_ACCOUNT,
345 init_once, NULL);
346 if (!sysv_inode_cachep)
347 return -ENOMEM;
348 return 0;
349}
350
351void sysv_destroy_icache(void)
352{
353 kmem_cache_destroy(sysv_inode_cachep);
354}
diff --git a/fs/sysv/itree.c b/fs/sysv/itree.c
new file mode 100644
index 000000000000..86f5f8d43d0f
--- /dev/null
+++ b/fs/sysv/itree.c
@@ -0,0 +1,475 @@
1/*
2 * linux/fs/sysv/itree.c
3 *
4 * Handling of indirect blocks' trees.
5 * AV, Sep--Dec 2000
6 */
7
8#include <linux/buffer_head.h>
9#include <linux/mount.h>
10#include <linux/string.h>
11#include "sysv.h"
12
13enum {DIRECT = 10, DEPTH = 4}; /* Have triple indirect */
14
15static inline void dirty_indirect(struct buffer_head *bh, struct inode *inode)
16{
17 mark_buffer_dirty_inode(bh, inode);
18 if (IS_SYNC(inode))
19 sync_dirty_buffer(bh);
20}
21
22static int block_to_path(struct inode *inode, long block, int offsets[DEPTH])
23{
24 struct super_block *sb = inode->i_sb;
25 struct sysv_sb_info *sbi = SYSV_SB(sb);
26 int ptrs_bits = sbi->s_ind_per_block_bits;
27 unsigned long indirect_blocks = sbi->s_ind_per_block,
28 double_blocks = sbi->s_ind_per_block_2;
29 int n = 0;
30
31 if (block < 0) {
32 printk("sysv_block_map: block < 0\n");
33 } else if (block < DIRECT) {
34 offsets[n++] = block;
35 } else if ( (block -= DIRECT) < indirect_blocks) {
36 offsets[n++] = DIRECT;
37 offsets[n++] = block;
38 } else if ((block -= indirect_blocks) < double_blocks) {
39 offsets[n++] = DIRECT+1;
40 offsets[n++] = block >> ptrs_bits;
41 offsets[n++] = block & (indirect_blocks - 1);
42 } else if (((block -= double_blocks) >> (ptrs_bits * 2)) < indirect_blocks) {
43 offsets[n++] = DIRECT+2;
44 offsets[n++] = block >> (ptrs_bits * 2);
45 offsets[n++] = (block >> ptrs_bits) & (indirect_blocks - 1);
46 offsets[n++] = block & (indirect_blocks - 1);
47 } else {
48 /* nothing */;
49 }
50 return n;
51}
52
53static inline int block_to_cpu(struct sysv_sb_info *sbi, sysv_zone_t nr)
54{
55 return sbi->s_block_base + fs32_to_cpu(sbi, nr);
56}
57
58typedef struct {
59 sysv_zone_t *p;
60 sysv_zone_t key;
61 struct buffer_head *bh;
62} Indirect;
63
64static DEFINE_RWLOCK(pointers_lock);
65
66static inline void add_chain(Indirect *p, struct buffer_head *bh, sysv_zone_t *v)
67{
68 p->key = *(p->p = v);
69 p->bh = bh;
70}
71
72static inline int verify_chain(Indirect *from, Indirect *to)
73{
74 while (from <= to && from->key == *from->p)
75 from++;
76 return (from > to);
77}
78
79static inline sysv_zone_t *block_end(struct buffer_head *bh)
80{
81 return (sysv_zone_t*)((char*)bh->b_data + bh->b_size);
82}
83
84/*
85 * Requires read_lock(&pointers_lock) or write_lock(&pointers_lock)
86 */
87static Indirect *get_branch(struct inode *inode,
88 int depth,
89 int offsets[],
90 Indirect chain[],
91 int *err)
92{
93 struct super_block *sb = inode->i_sb;
94 Indirect *p = chain;
95 struct buffer_head *bh;
96
97 *err = 0;
98 add_chain(chain, NULL, SYSV_I(inode)->i_data + *offsets);
99 if (!p->key)
100 goto no_block;
101 while (--depth) {
102 int block = block_to_cpu(SYSV_SB(sb), p->key);
103 bh = sb_bread(sb, block);
104 if (!bh)
105 goto failure;
106 if (!verify_chain(chain, p))
107 goto changed;
108 add_chain(++p, bh, (sysv_zone_t*)bh->b_data + *++offsets);
109 if (!p->key)
110 goto no_block;
111 }
112 return NULL;
113
114changed:
115 brelse(bh);
116 *err = -EAGAIN;
117 goto no_block;
118failure:
119 *err = -EIO;
120no_block:
121 return p;
122}
123
124static int alloc_branch(struct inode *inode,
125 int num,
126 int *offsets,
127 Indirect *branch)
128{
129 int blocksize = inode->i_sb->s_blocksize;
130 int n = 0;
131 int i;
132
133 branch[0].key = sysv_new_block(inode->i_sb);
134 if (branch[0].key) for (n = 1; n < num; n++) {
135 struct buffer_head *bh;
136 int parent;
137 /* Allocate the next block */
138 branch[n].key = sysv_new_block(inode->i_sb);
139 if (!branch[n].key)
140 break;
141 /*
142 * Get buffer_head for parent block, zero it out and set
143 * the pointer to new one, then send parent to disk.
144 */
145 parent = block_to_cpu(SYSV_SB(inode->i_sb), branch[n-1].key);
146 bh = sb_getblk(inode->i_sb, parent);
147 lock_buffer(bh);
148 memset(bh->b_data, 0, blocksize);
149 branch[n].bh = bh;
150 branch[n].p = (sysv_zone_t*) bh->b_data + offsets[n];
151 *branch[n].p = branch[n].key;
152 set_buffer_uptodate(bh);
153 unlock_buffer(bh);
154 dirty_indirect(bh, inode);
155 }
156 if (n == num)
157 return 0;
158
159 /* Allocation failed, free what we already allocated */
160 for (i = 1; i < n; i++)
161 bforget(branch[i].bh);
162 for (i = 0; i < n; i++)
163 sysv_free_block(inode->i_sb, branch[i].key);
164 return -ENOSPC;
165}
166
167static inline int splice_branch(struct inode *inode,
168 Indirect chain[],
169 Indirect *where,
170 int num)
171{
172 int i;
173
174 /* Verify that place we are splicing to is still there and vacant */
175 write_lock(&pointers_lock);
176 if (!verify_chain(chain, where-1) || *where->p)
177 goto changed;
178 *where->p = where->key;
179 write_unlock(&pointers_lock);
180
181 inode->i_ctime = CURRENT_TIME_SEC;
182
183 /* had we spliced it onto indirect block? */
184 if (where->bh)
185 dirty_indirect(where->bh, inode);
186
187 if (IS_SYNC(inode))
188 sysv_sync_inode(inode);
189 else
190 mark_inode_dirty(inode);
191 return 0;
192
193changed:
194 write_unlock(&pointers_lock);
195 for (i = 1; i < num; i++)
196 bforget(where[i].bh);
197 for (i = 0; i < num; i++)
198 sysv_free_block(inode->i_sb, where[i].key);
199 return -EAGAIN;
200}
201
202static int get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create)
203{
204 int err = -EIO;
205 int offsets[DEPTH];
206 Indirect chain[DEPTH];
207 struct super_block *sb = inode->i_sb;
208 Indirect *partial;
209 int left;
210 int depth = block_to_path(inode, iblock, offsets);
211
212 if (depth == 0)
213 goto out;
214
215reread:
216 read_lock(&pointers_lock);
217 partial = get_branch(inode, depth, offsets, chain, &err);
218 read_unlock(&pointers_lock);
219
220 /* Simplest case - block found, no allocation needed */
221 if (!partial) {
222got_it:
223 map_bh(bh_result, sb, block_to_cpu(SYSV_SB(sb),
224 chain[depth-1].key));
225 /* Clean up and exit */
226 partial = chain+depth-1; /* the whole chain */
227 goto cleanup;
228 }
229
230 /* Next simple case - plain lookup or failed read of indirect block */
231 if (!create || err == -EIO) {
232cleanup:
233 while (partial > chain) {
234 brelse(partial->bh);
235 partial--;
236 }
237out:
238 return err;
239 }
240
241 /*
242 * Indirect block might be removed by truncate while we were
243 * reading it. Handling of that case (forget what we've got and
244 * reread) is taken out of the main path.
245 */
246 if (err == -EAGAIN)
247 goto changed;
248
249 left = (chain + depth) - partial;
250 err = alloc_branch(inode, left, offsets+(partial-chain), partial);
251 if (err)
252 goto cleanup;
253
254 if (splice_branch(inode, chain, partial, left) < 0)
255 goto changed;
256
257 set_buffer_new(bh_result);
258 goto got_it;
259
260changed:
261 while (partial > chain) {
262 brelse(partial->bh);
263 partial--;
264 }
265 goto reread;
266}
267
268static inline int all_zeroes(sysv_zone_t *p, sysv_zone_t *q)
269{
270 while (p < q)
271 if (*p++)
272 return 0;
273 return 1;
274}
275
276static Indirect *find_shared(struct inode *inode,
277 int depth,
278 int offsets[],
279 Indirect chain[],
280 sysv_zone_t *top)
281{
282 Indirect *partial, *p;
283 int k, err;
284
285 *top = 0;
286 for (k = depth; k > 1 && !offsets[k-1]; k--)
287 ;
288
289 write_lock(&pointers_lock);
290 partial = get_branch(inode, k, offsets, chain, &err);
291 if (!partial)
292 partial = chain + k-1;
293 /*
294 * If the branch acquired continuation since we've looked at it -
295 * fine, it should all survive and (new) top doesn't belong to us.
296 */
297 if (!partial->key && *partial->p) {
298 write_unlock(&pointers_lock);
299 goto no_top;
300 }
301 for (p=partial; p>chain && all_zeroes((sysv_zone_t*)p->bh->b_data,p->p); p--)
302 ;
303 /*
304 * OK, we've found the last block that must survive. The rest of our
305 * branch should be detached before unlocking. However, if that rest
306 * of branch is all ours and does not grow immediately from the inode
307 * it's easier to cheat and just decrement partial->p.
308 */
309 if (p == chain + k - 1 && p > chain) {
310 p->p--;
311 } else {
312 *top = *p->p;
313 *p->p = 0;
314 }
315 write_unlock(&pointers_lock);
316
317 while (partial > p) {
318 brelse(partial->bh);
319 partial--;
320 }
321no_top:
322 return partial;
323}
324
325static inline void free_data(struct inode *inode, sysv_zone_t *p, sysv_zone_t *q)
326{
327 for ( ; p < q ; p++) {
328 sysv_zone_t nr = *p;
329 if (nr) {
330 *p = 0;
331 sysv_free_block(inode->i_sb, nr);
332 mark_inode_dirty(inode);
333 }
334 }
335}
336
337static void free_branches(struct inode *inode, sysv_zone_t *p, sysv_zone_t *q, int depth)
338{
339 struct buffer_head * bh;
340 struct super_block *sb = inode->i_sb;
341
342 if (depth--) {
343 for ( ; p < q ; p++) {
344 int block;
345 sysv_zone_t nr = *p;
346 if (!nr)
347 continue;
348 *p = 0;
349 block = block_to_cpu(SYSV_SB(sb), nr);
350 bh = sb_bread(sb, block);
351 if (!bh)
352 continue;
353 free_branches(inode, (sysv_zone_t*)bh->b_data,
354 block_end(bh), depth);
355 bforget(bh);
356 sysv_free_block(sb, nr);
357 mark_inode_dirty(inode);
358 }
359 } else
360 free_data(inode, p, q);
361}
362
363void sysv_truncate (struct inode * inode)
364{
365 sysv_zone_t *i_data = SYSV_I(inode)->i_data;
366 int offsets[DEPTH];
367 Indirect chain[DEPTH];
368 Indirect *partial;
369 sysv_zone_t nr = 0;
370 int n;
371 long iblock;
372 unsigned blocksize;
373
374 if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
375 S_ISLNK(inode->i_mode)))
376 return;
377
378 blocksize = inode->i_sb->s_blocksize;
379 iblock = (inode->i_size + blocksize-1)
380 >> inode->i_sb->s_blocksize_bits;
381
382 block_truncate_page(inode->i_mapping, inode->i_size, get_block);
383
384 n = block_to_path(inode, iblock, offsets);
385 if (n == 0)
386 return;
387
388 if (n == 1) {
389 free_data(inode, i_data+offsets[0], i_data + DIRECT);
390 goto do_indirects;
391 }
392
393 partial = find_shared(inode, n, offsets, chain, &nr);
394 /* Kill the top of shared branch (already detached) */
395 if (nr) {
396 if (partial == chain)
397 mark_inode_dirty(inode);
398 else
399 dirty_indirect(partial->bh, inode);
400 free_branches(inode, &nr, &nr+1, (chain+n-1) - partial);
401 }
402 /* Clear the ends of indirect blocks on the shared branch */
403 while (partial > chain) {
404 free_branches(inode, partial->p + 1, block_end(partial->bh),
405 (chain+n-1) - partial);
406 dirty_indirect(partial->bh, inode);
407 brelse (partial->bh);
408 partial--;
409 }
410do_indirects:
411 /* Kill the remaining (whole) subtrees (== subtrees deeper than...) */
412 while (n < DEPTH) {
413 nr = i_data[DIRECT + n - 1];
414 if (nr) {
415 i_data[DIRECT + n - 1] = 0;
416 mark_inode_dirty(inode);
417 free_branches(inode, &nr, &nr+1, n);
418 }
419 n++;
420 }
421 inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
422 if (IS_SYNC(inode))
423 sysv_sync_inode (inode);
424 else
425 mark_inode_dirty(inode);
426}
427
428static unsigned sysv_nblocks(struct super_block *s, loff_t size)
429{
430 struct sysv_sb_info *sbi = SYSV_SB(s);
431 int ptrs_bits = sbi->s_ind_per_block_bits;
432 unsigned blocks, res, direct = DIRECT, i = DEPTH;
433 blocks = (size + s->s_blocksize - 1) >> s->s_blocksize_bits;
434 res = blocks;
435 while (--i && blocks > direct) {
436 blocks = ((blocks - direct - 1) >> ptrs_bits) + 1;
437 res += blocks;
438 direct = 1;
439 }
440 return blocks;
441}
442
443int sysv_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
444{
445 struct super_block *s = mnt->mnt_sb;
446 generic_fillattr(dentry->d_inode, stat);
447 stat->blocks = (s->s_blocksize / 512) * sysv_nblocks(s, stat->size);
448 stat->blksize = s->s_blocksize;
449 return 0;
450}
451
452static int sysv_writepage(struct page *page, struct writeback_control *wbc)
453{
454 return block_write_full_page(page,get_block,wbc);
455}
456static int sysv_readpage(struct file *file, struct page *page)
457{
458 return block_read_full_page(page,get_block);
459}
460static int sysv_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
461{
462 return block_prepare_write(page,from,to,get_block);
463}
464static sector_t sysv_bmap(struct address_space *mapping, sector_t block)
465{
466 return generic_block_bmap(mapping,block,get_block);
467}
468struct address_space_operations sysv_aops = {
469 .readpage = sysv_readpage,
470 .writepage = sysv_writepage,
471 .sync_page = block_sync_page,
472 .prepare_write = sysv_prepare_write,
473 .commit_write = generic_commit_write,
474 .bmap = sysv_bmap
475};
diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c
new file mode 100644
index 000000000000..7f0e4b53085e
--- /dev/null
+++ b/fs/sysv/namei.c
@@ -0,0 +1,318 @@
1/*
2 * linux/fs/sysv/namei.c
3 *
4 * minix/namei.c
5 * Copyright (C) 1991, 1992 Linus Torvalds
6 *
7 * coh/namei.c
8 * Copyright (C) 1993 Pascal Haible, Bruno Haible
9 *
10 * sysv/namei.c
11 * Copyright (C) 1993 Bruno Haible
12 * Copyright (C) 1997, 1998 Krzysztof G. Baranowski
13 */
14
15#include <linux/pagemap.h>
16#include <linux/smp_lock.h>
17#include "sysv.h"
18
19static inline void inc_count(struct inode *inode)
20{
21 inode->i_nlink++;
22 mark_inode_dirty(inode);
23}
24
25static inline void dec_count(struct inode *inode)
26{
27 inode->i_nlink--;
28 mark_inode_dirty(inode);
29}
30
31static int add_nondir(struct dentry *dentry, struct inode *inode)
32{
33 int err = sysv_add_link(dentry, inode);
34 if (!err) {
35 d_instantiate(dentry, inode);
36 return 0;
37 }
38 dec_count(inode);
39 iput(inode);
40 return err;
41}
42
43static int sysv_hash(struct dentry *dentry, struct qstr *qstr)
44{
45 /* Truncate the name in place, avoids having to define a compare
46 function. */
47 if (qstr->len > SYSV_NAMELEN) {
48 qstr->len = SYSV_NAMELEN;
49 qstr->hash = full_name_hash(qstr->name, qstr->len);
50 }
51 return 0;
52}
53
54struct dentry_operations sysv_dentry_operations = {
55 .d_hash = sysv_hash,
56};
57
58static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry, struct nameidata *nd)
59{
60 struct inode * inode = NULL;
61 ino_t ino;
62
63 dentry->d_op = dir->i_sb->s_root->d_op;
64 if (dentry->d_name.len > SYSV_NAMELEN)
65 return ERR_PTR(-ENAMETOOLONG);
66 ino = sysv_inode_by_name(dentry);
67
68 if (ino) {
69 inode = iget(dir->i_sb, ino);
70 if (!inode)
71 return ERR_PTR(-EACCES);
72 }
73 d_add(dentry, inode);
74 return NULL;
75}
76
77static int sysv_mknod(struct inode * dir, struct dentry * dentry, int mode, dev_t rdev)
78{
79 struct inode * inode;
80 int err;
81
82 if (!old_valid_dev(rdev))
83 return -EINVAL;
84
85 inode = sysv_new_inode(dir, mode);
86 err = PTR_ERR(inode);
87
88 if (!IS_ERR(inode)) {
89 sysv_set_inode(inode, rdev);
90 mark_inode_dirty(inode);
91 err = add_nondir(dentry, inode);
92 }
93 return err;
94}
95
96static int sysv_create(struct inode * dir, struct dentry * dentry, int mode, struct nameidata *nd)
97{
98 return sysv_mknod(dir, dentry, mode, 0);
99}
100
101static int sysv_symlink(struct inode * dir, struct dentry * dentry,
102 const char * symname)
103{
104 int err = -ENAMETOOLONG;
105 int l = strlen(symname)+1;
106 struct inode * inode;
107
108 if (l > dir->i_sb->s_blocksize)
109 goto out;
110
111 inode = sysv_new_inode(dir, S_IFLNK|0777);
112 err = PTR_ERR(inode);
113 if (IS_ERR(inode))
114 goto out;
115
116 sysv_set_inode(inode, 0);
117 err = page_symlink(inode, symname, l);
118 if (err)
119 goto out_fail;
120
121 mark_inode_dirty(inode);
122 err = add_nondir(dentry, inode);
123out:
124 return err;
125
126out_fail:
127 dec_count(inode);
128 iput(inode);
129 goto out;
130}
131
132static int sysv_link(struct dentry * old_dentry, struct inode * dir,
133 struct dentry * dentry)
134{
135 struct inode *inode = old_dentry->d_inode;
136
137 if (inode->i_nlink >= SYSV_SB(inode->i_sb)->s_link_max)
138 return -EMLINK;
139
140 inode->i_ctime = CURRENT_TIME_SEC;
141 inc_count(inode);
142 atomic_inc(&inode->i_count);
143
144 return add_nondir(dentry, inode);
145}
146
147static int sysv_mkdir(struct inode * dir, struct dentry *dentry, int mode)
148{
149 struct inode * inode;
150 int err = -EMLINK;
151
152 if (dir->i_nlink >= SYSV_SB(dir->i_sb)->s_link_max)
153 goto out;
154 inc_count(dir);
155
156 inode = sysv_new_inode(dir, S_IFDIR|mode);
157 err = PTR_ERR(inode);
158 if (IS_ERR(inode))
159 goto out_dir;
160
161 sysv_set_inode(inode, 0);
162
163 inc_count(inode);
164
165 err = sysv_make_empty(inode, dir);
166 if (err)
167 goto out_fail;
168
169 err = sysv_add_link(dentry, inode);
170 if (err)
171 goto out_fail;
172
173 d_instantiate(dentry, inode);
174out:
175 return err;
176
177out_fail:
178 dec_count(inode);
179 dec_count(inode);
180 iput(inode);
181out_dir:
182 dec_count(dir);
183 goto out;
184}
185
186static int sysv_unlink(struct inode * dir, struct dentry * dentry)
187{
188 struct inode * inode = dentry->d_inode;
189 struct page * page;
190 struct sysv_dir_entry * de;
191 int err = -ENOENT;
192
193 de = sysv_find_entry(dentry, &page);
194 if (!de)
195 goto out;
196
197 err = sysv_delete_entry (de, page);
198 if (err)
199 goto out;
200
201 inode->i_ctime = dir->i_ctime;
202 dec_count(inode);
203out:
204 return err;
205}
206
207static int sysv_rmdir(struct inode * dir, struct dentry * dentry)
208{
209 struct inode *inode = dentry->d_inode;
210 int err = -ENOTEMPTY;
211
212 if (sysv_empty_dir(inode)) {
213 err = sysv_unlink(dir, dentry);
214 if (!err) {
215 inode->i_size = 0;
216 dec_count(inode);
217 dec_count(dir);
218 }
219 }
220 return err;
221}
222
223/*
224 * Anybody can rename anything with this: the permission checks are left to the
225 * higher-level routines.
226 */
227static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
228 struct inode * new_dir, struct dentry * new_dentry)
229{
230 struct inode * old_inode = old_dentry->d_inode;
231 struct inode * new_inode = new_dentry->d_inode;
232 struct page * dir_page = NULL;
233 struct sysv_dir_entry * dir_de = NULL;
234 struct page * old_page;
235 struct sysv_dir_entry * old_de;
236 int err = -ENOENT;
237
238 old_de = sysv_find_entry(old_dentry, &old_page);
239 if (!old_de)
240 goto out;
241
242 if (S_ISDIR(old_inode->i_mode)) {
243 err = -EIO;
244 dir_de = sysv_dotdot(old_inode, &dir_page);
245 if (!dir_de)
246 goto out_old;
247 }
248
249 if (new_inode) {
250 struct page * new_page;
251 struct sysv_dir_entry * new_de;
252
253 err = -ENOTEMPTY;
254 if (dir_de && !sysv_empty_dir(new_inode))
255 goto out_dir;
256
257 err = -ENOENT;
258 new_de = sysv_find_entry(new_dentry, &new_page);
259 if (!new_de)
260 goto out_dir;
261 inc_count(old_inode);
262 sysv_set_link(new_de, new_page, old_inode);
263 new_inode->i_ctime = CURRENT_TIME_SEC;
264 if (dir_de)
265 new_inode->i_nlink--;
266 dec_count(new_inode);
267 } else {
268 if (dir_de) {
269 err = -EMLINK;
270 if (new_dir->i_nlink >= SYSV_SB(new_dir->i_sb)->s_link_max)
271 goto out_dir;
272 }
273 inc_count(old_inode);
274 err = sysv_add_link(new_dentry, old_inode);
275 if (err) {
276 dec_count(old_inode);
277 goto out_dir;
278 }
279 if (dir_de)
280 inc_count(new_dir);
281 }
282
283 sysv_delete_entry(old_de, old_page);
284 dec_count(old_inode);
285
286 if (dir_de) {
287 sysv_set_link(dir_de, dir_page, new_dir);
288 dec_count(old_dir);
289 }
290 return 0;
291
292out_dir:
293 if (dir_de) {
294 kunmap(dir_page);
295 page_cache_release(dir_page);
296 }
297out_old:
298 kunmap(old_page);
299 page_cache_release(old_page);
300out:
301 return err;
302}
303
304/*
305 * directories can handle most operations...
306 */
307struct inode_operations sysv_dir_inode_operations = {
308 .create = sysv_create,
309 .lookup = sysv_lookup,
310 .link = sysv_link,
311 .unlink = sysv_unlink,
312 .symlink = sysv_symlink,
313 .mkdir = sysv_mkdir,
314 .rmdir = sysv_rmdir,
315 .mknod = sysv_mknod,
316 .rename = sysv_rename,
317 .getattr = sysv_getattr,
318};
diff --git a/fs/sysv/super.c b/fs/sysv/super.c
new file mode 100644
index 000000000000..59e76b51142b
--- /dev/null
+++ b/fs/sysv/super.c
@@ -0,0 +1,572 @@
1/*
2 * linux/fs/sysv/inode.c
3 *
4 * minix/inode.c
5 * Copyright (C) 1991, 1992 Linus Torvalds
6 *
7 * xenix/inode.c
8 * Copyright (C) 1992 Doug Evans
9 *
10 * coh/inode.c
11 * Copyright (C) 1993 Pascal Haible, Bruno Haible
12 *
13 * sysv/inode.c
14 * Copyright (C) 1993 Paul B. Monday
15 *
16 * sysv/inode.c
17 * Copyright (C) 1993 Bruno Haible
18 * Copyright (C) 1997, 1998 Krzysztof G. Baranowski
19 *
20 * This file contains code for read/parsing the superblock.
21 */
22
23#include <linux/module.h>
24#include <linux/init.h>
25#include <linux/slab.h>
26#include <linux/buffer_head.h>
27#include "sysv.h"
28
29/*
30 * The following functions try to recognize specific filesystems.
31 *
32 * We recognize:
33 * - Xenix FS by its magic number.
34 * - SystemV FS by its magic number.
35 * - Coherent FS by its funny fname/fpack field.
36 * - SCO AFS by s_nfree == 0xffff
37 * - V7 FS has no distinguishing features.
38 *
39 * We discriminate among SystemV4 and SystemV2 FS by the assumption that
40 * the time stamp is not < 01-01-1980.
41 */
42
43enum {
44 JAN_1_1980 = (10*365 + 2) * 24 * 60 * 60
45};
46
47static void detected_xenix(struct sysv_sb_info *sbi)
48{
49 struct buffer_head *bh1 = sbi->s_bh1;
50 struct buffer_head *bh2 = sbi->s_bh2;
51 struct xenix_super_block * sbd1;
52 struct xenix_super_block * sbd2;
53
54 if (bh1 != bh2)
55 sbd1 = sbd2 = (struct xenix_super_block *) bh1->b_data;
56 else {
57 /* block size = 512, so bh1 != bh2 */
58 sbd1 = (struct xenix_super_block *) bh1->b_data;
59 sbd2 = (struct xenix_super_block *) (bh2->b_data - 512);
60 }
61
62 sbi->s_link_max = XENIX_LINK_MAX;
63 sbi->s_fic_size = XENIX_NICINOD;
64 sbi->s_flc_size = XENIX_NICFREE;
65 sbi->s_sbd1 = (char *)sbd1;
66 sbi->s_sbd2 = (char *)sbd2;
67 sbi->s_sb_fic_count = &sbd1->s_ninode;
68 sbi->s_sb_fic_inodes = &sbd1->s_inode[0];
69 sbi->s_sb_total_free_inodes = &sbd2->s_tinode;
70 sbi->s_bcache_count = &sbd1->s_nfree;
71 sbi->s_bcache = &sbd1->s_free[0];
72 sbi->s_free_blocks = &sbd2->s_tfree;
73 sbi->s_sb_time = &sbd2->s_time;
74 sbi->s_firstdatazone = fs16_to_cpu(sbi, sbd1->s_isize);
75 sbi->s_nzones = fs32_to_cpu(sbi, sbd1->s_fsize);
76}
77
78static void detected_sysv4(struct sysv_sb_info *sbi)
79{
80 struct sysv4_super_block * sbd;
81 struct buffer_head *bh1 = sbi->s_bh1;
82 struct buffer_head *bh2 = sbi->s_bh2;
83
84 if (bh1 == bh2)
85 sbd = (struct sysv4_super_block *) (bh1->b_data + BLOCK_SIZE/2);
86 else
87 sbd = (struct sysv4_super_block *) bh2->b_data;
88
89 sbi->s_link_max = SYSV_LINK_MAX;
90 sbi->s_fic_size = SYSV_NICINOD;
91 sbi->s_flc_size = SYSV_NICFREE;
92 sbi->s_sbd1 = (char *)sbd;
93 sbi->s_sbd2 = (char *)sbd;
94 sbi->s_sb_fic_count = &sbd->s_ninode;
95 sbi->s_sb_fic_inodes = &sbd->s_inode[0];
96 sbi->s_sb_total_free_inodes = &sbd->s_tinode;
97 sbi->s_bcache_count = &sbd->s_nfree;
98 sbi->s_bcache = &sbd->s_free[0];
99 sbi->s_free_blocks = &sbd->s_tfree;
100 sbi->s_sb_time = &sbd->s_time;
101 sbi->s_sb_state = &sbd->s_state;
102 sbi->s_firstdatazone = fs16_to_cpu(sbi, sbd->s_isize);
103 sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize);
104}
105
106static void detected_sysv2(struct sysv_sb_info *sbi)
107{
108 struct sysv2_super_block *sbd;
109 struct buffer_head *bh1 = sbi->s_bh1;
110 struct buffer_head *bh2 = sbi->s_bh2;
111
112 if (bh1 == bh2)
113 sbd = (struct sysv2_super_block *) (bh1->b_data + BLOCK_SIZE/2);
114 else
115 sbd = (struct sysv2_super_block *) bh2->b_data;
116
117 sbi->s_link_max = SYSV_LINK_MAX;
118 sbi->s_fic_size = SYSV_NICINOD;
119 sbi->s_flc_size = SYSV_NICFREE;
120 sbi->s_sbd1 = (char *)sbd;
121 sbi->s_sbd2 = (char *)sbd;
122 sbi->s_sb_fic_count = &sbd->s_ninode;
123 sbi->s_sb_fic_inodes = &sbd->s_inode[0];
124 sbi->s_sb_total_free_inodes = &sbd->s_tinode;
125 sbi->s_bcache_count = &sbd->s_nfree;
126 sbi->s_bcache = &sbd->s_free[0];
127 sbi->s_free_blocks = &sbd->s_tfree;
128 sbi->s_sb_time = &sbd->s_time;
129 sbi->s_sb_state = &sbd->s_state;
130 sbi->s_firstdatazone = fs16_to_cpu(sbi, sbd->s_isize);
131 sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize);
132}
133
134static void detected_coherent(struct sysv_sb_info *sbi)
135{
136 struct coh_super_block * sbd;
137 struct buffer_head *bh1 = sbi->s_bh1;
138
139 sbd = (struct coh_super_block *) bh1->b_data;
140
141 sbi->s_link_max = COH_LINK_MAX;
142 sbi->s_fic_size = COH_NICINOD;
143 sbi->s_flc_size = COH_NICFREE;
144 sbi->s_sbd1 = (char *)sbd;
145 sbi->s_sbd2 = (char *)sbd;
146 sbi->s_sb_fic_count = &sbd->s_ninode;
147 sbi->s_sb_fic_inodes = &sbd->s_inode[0];
148 sbi->s_sb_total_free_inodes = &sbd->s_tinode;
149 sbi->s_bcache_count = &sbd->s_nfree;
150 sbi->s_bcache = &sbd->s_free[0];
151 sbi->s_free_blocks = &sbd->s_tfree;
152 sbi->s_sb_time = &sbd->s_time;
153 sbi->s_firstdatazone = fs16_to_cpu(sbi, sbd->s_isize);
154 sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize);
155}
156
157static void detected_v7(struct sysv_sb_info *sbi)
158{
159 struct buffer_head *bh2 = sbi->s_bh2;
160 struct v7_super_block *sbd = (struct v7_super_block *)bh2->b_data;
161
162 sbi->s_link_max = V7_LINK_MAX;
163 sbi->s_fic_size = V7_NICINOD;
164 sbi->s_flc_size = V7_NICFREE;
165 sbi->s_sbd1 = (char *)sbd;
166 sbi->s_sbd2 = (char *)sbd;
167 sbi->s_sb_fic_count = &sbd->s_ninode;
168 sbi->s_sb_fic_inodes = &sbd->s_inode[0];
169 sbi->s_sb_total_free_inodes = &sbd->s_tinode;
170 sbi->s_bcache_count = &sbd->s_nfree;
171 sbi->s_bcache = &sbd->s_free[0];
172 sbi->s_free_blocks = &sbd->s_tfree;
173 sbi->s_sb_time = &sbd->s_time;
174 sbi->s_firstdatazone = fs16_to_cpu(sbi, sbd->s_isize);
175 sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize);
176}
177
178static int detect_xenix(struct sysv_sb_info *sbi, struct buffer_head *bh)
179{
180 struct xenix_super_block *sbd = (struct xenix_super_block *)bh->b_data;
181 if (*(__le32 *)&sbd->s_magic == cpu_to_le32(0x2b5544))
182 sbi->s_bytesex = BYTESEX_LE;
183 else if (*(__be32 *)&sbd->s_magic == cpu_to_be32(0x2b5544))
184 sbi->s_bytesex = BYTESEX_BE;
185 else
186 return 0;
187 switch (fs32_to_cpu(sbi, sbd->s_type)) {
188 case 1:
189 sbi->s_type = FSTYPE_XENIX;
190 return 1;
191 case 2:
192 sbi->s_type = FSTYPE_XENIX;
193 return 2;
194 default:
195 return 0;
196 }
197}
198
199static int detect_sysv(struct sysv_sb_info *sbi, struct buffer_head *bh)
200{
201 struct super_block *sb = sbi->s_sb;
202 /* All relevant fields are at the same offsets in R2 and R4 */
203 struct sysv4_super_block * sbd;
204 u32 type;
205
206 sbd = (struct sysv4_super_block *) (bh->b_data + BLOCK_SIZE/2);
207 if (*(__le32 *)&sbd->s_magic == cpu_to_le32(0xfd187e20))
208 sbi->s_bytesex = BYTESEX_LE;
209 else if (*(__be32 *)&sbd->s_magic == cpu_to_be32(0xfd187e20))
210 sbi->s_bytesex = BYTESEX_BE;
211 else
212 return 0;
213
214 type = fs32_to_cpu(sbi, sbd->s_type);
215
216 if (fs16_to_cpu(sbi, sbd->s_nfree) == 0xffff) {
217 sbi->s_type = FSTYPE_AFS;
218 sbi->s_forced_ro = 1;
219 if (!(sb->s_flags & MS_RDONLY)) {
220 printk("SysV FS: SCO EAFS on %s detected, "
221 "forcing read-only mode.\n",
222 sb->s_id);
223 }
224 return type;
225 }
226
227 if (fs32_to_cpu(sbi, sbd->s_time) < JAN_1_1980) {
228 /* this is likely to happen on SystemV2 FS */
229 if (type > 3 || type < 1)
230 return 0;
231 sbi->s_type = FSTYPE_SYSV2;
232 return type;
233 }
234 if ((type > 3 || type < 1) && (type > 0x30 || type < 0x10))
235 return 0;
236
237 /* On Interactive Unix (ISC) Version 4.0/3.x s_type field = 0x10,
238 0x20 or 0x30 indicates that symbolic links and the 14-character
239 filename limit is gone. Due to lack of information about this
240 feature read-only mode seems to be a reasonable approach... -KGB */
241
242 if (type >= 0x10) {
243 printk("SysV FS: can't handle long file names on %s, "
244 "forcing read-only mode.\n", sb->s_id);
245 sbi->s_forced_ro = 1;
246 }
247
248 sbi->s_type = FSTYPE_SYSV4;
249 return type >= 0x10 ? type >> 4 : type;
250}
251
252static int detect_coherent(struct sysv_sb_info *sbi, struct buffer_head *bh)
253{
254 struct coh_super_block * sbd;
255
256 sbd = (struct coh_super_block *) (bh->b_data + BLOCK_SIZE/2);
257 if ((memcmp(sbd->s_fname,"noname",6) && memcmp(sbd->s_fname,"xxxxx ",6))
258 || (memcmp(sbd->s_fpack,"nopack",6) && memcmp(sbd->s_fpack,"xxxxx\n",6)))
259 return 0;
260 sbi->s_bytesex = BYTESEX_PDP;
261 sbi->s_type = FSTYPE_COH;
262 return 1;
263}
264
265static int detect_sysv_odd(struct sysv_sb_info *sbi, struct buffer_head *bh)
266{
267 int size = detect_sysv(sbi, bh);
268
269 return size>2 ? 0 : size;
270}
271
272static struct {
273 int block;
274 int (*test)(struct sysv_sb_info *, struct buffer_head *);
275} flavours[] = {
276 {1, detect_xenix},
277 {0, detect_sysv},
278 {0, detect_coherent},
279 {9, detect_sysv_odd},
280 {15,detect_sysv_odd},
281 {18,detect_sysv},
282};
283
284static char *flavour_names[] = {
285 [FSTYPE_XENIX] = "Xenix",
286 [FSTYPE_SYSV4] = "SystemV",
287 [FSTYPE_SYSV2] = "SystemV Release 2",
288 [FSTYPE_COH] = "Coherent",
289 [FSTYPE_V7] = "V7",
290 [FSTYPE_AFS] = "AFS",
291};
292
293static void (*flavour_setup[])(struct sysv_sb_info *) = {
294 [FSTYPE_XENIX] = detected_xenix,
295 [FSTYPE_SYSV4] = detected_sysv4,
296 [FSTYPE_SYSV2] = detected_sysv2,
297 [FSTYPE_COH] = detected_coherent,
298 [FSTYPE_V7] = detected_v7,
299 [FSTYPE_AFS] = detected_sysv4,
300};
301
302static int complete_read_super(struct super_block *sb, int silent, int size)
303{
304 struct sysv_sb_info *sbi = SYSV_SB(sb);
305 struct inode *root_inode;
306 char *found = flavour_names[sbi->s_type];
307 u_char n_bits = size+8;
308 int bsize = 1 << n_bits;
309 int bsize_4 = bsize >> 2;
310
311 sbi->s_firstinodezone = 2;
312
313 flavour_setup[sbi->s_type](sbi);
314
315 sbi->s_truncate = 1;
316 sbi->s_ndatazones = sbi->s_nzones - sbi->s_firstdatazone;
317 sbi->s_inodes_per_block = bsize >> 6;
318 sbi->s_inodes_per_block_1 = (bsize >> 6)-1;
319 sbi->s_inodes_per_block_bits = n_bits-6;
320 sbi->s_ind_per_block = bsize_4;
321 sbi->s_ind_per_block_2 = bsize_4*bsize_4;
322 sbi->s_toobig_block = 10 + bsize_4 * (1 + bsize_4 * (1 + bsize_4));
323 sbi->s_ind_per_block_bits = n_bits-2;
324
325 sbi->s_ninodes = (sbi->s_firstdatazone - sbi->s_firstinodezone)
326 << sbi->s_inodes_per_block_bits;
327
328 if (!silent)
329 printk("VFS: Found a %s FS (block size = %ld) on device %s\n",
330 found, sb->s_blocksize, sb->s_id);
331
332 sb->s_magic = SYSV_MAGIC_BASE + sbi->s_type;
333 /* set up enough so that it can read an inode */
334 sb->s_op = &sysv_sops;
335 root_inode = iget(sb,SYSV_ROOT_INO);
336 if (!root_inode || is_bad_inode(root_inode)) {
337 printk("SysV FS: get root inode failed\n");
338 return 0;
339 }
340 sb->s_root = d_alloc_root(root_inode);
341 if (!sb->s_root) {
342 iput(root_inode);
343 printk("SysV FS: get root dentry failed\n");
344 return 0;
345 }
346 if (sbi->s_forced_ro)
347 sb->s_flags |= MS_RDONLY;
348 if (sbi->s_truncate)
349 sb->s_root->d_op = &sysv_dentry_operations;
350 sb->s_dirt = 1;
351 return 1;
352}
353
354static int sysv_fill_super(struct super_block *sb, void *data, int silent)
355{
356 struct buffer_head *bh1, *bh = NULL;
357 struct sysv_sb_info *sbi;
358 unsigned long blocknr;
359 int size = 0, i;
360
361 if (1024 != sizeof (struct xenix_super_block))
362 panic("Xenix FS: bad superblock size");
363 if (512 != sizeof (struct sysv4_super_block))
364 panic("SystemV FS: bad superblock size");
365 if (512 != sizeof (struct sysv2_super_block))
366 panic("SystemV FS: bad superblock size");
367 if (500 != sizeof (struct coh_super_block))
368 panic("Coherent FS: bad superblock size");
369 if (64 != sizeof (struct sysv_inode))
370 panic("sysv fs: bad inode size");
371
372 sbi = kmalloc(sizeof(struct sysv_sb_info), GFP_KERNEL);
373 if (!sbi)
374 return -ENOMEM;
375 memset(sbi, 0, sizeof(struct sysv_sb_info));
376
377 sbi->s_sb = sb;
378 sbi->s_block_base = 0;
379 sb->s_fs_info = sbi;
380
381 sb_set_blocksize(sb, BLOCK_SIZE);
382
383 for (i = 0; i < sizeof(flavours)/sizeof(flavours[0]) && !size; i++) {
384 brelse(bh);
385 bh = sb_bread(sb, flavours[i].block);
386 if (!bh)
387 continue;
388 size = flavours[i].test(SYSV_SB(sb), bh);
389 }
390
391 if (!size)
392 goto Eunknown;
393
394 switch (size) {
395 case 1:
396 blocknr = bh->b_blocknr << 1;
397 brelse(bh);
398 sb_set_blocksize(sb, 512);
399 bh1 = sb_bread(sb, blocknr);
400 bh = sb_bread(sb, blocknr + 1);
401 break;
402 case 2:
403 bh1 = bh;
404 break;
405 case 3:
406 blocknr = bh->b_blocknr >> 1;
407 brelse(bh);
408 sb_set_blocksize(sb, 2048);
409 bh1 = bh = sb_bread(sb, blocknr);
410 break;
411 default:
412 goto Ebadsize;
413 }
414
415 if (bh && bh1) {
416 sbi->s_bh1 = bh1;
417 sbi->s_bh2 = bh;
418 if (complete_read_super(sb, silent, size))
419 return 0;
420 }
421
422 brelse(bh1);
423 brelse(bh);
424 sb_set_blocksize(sb, BLOCK_SIZE);
425 printk("oldfs: cannot read superblock\n");
426failed:
427 kfree(sbi);
428 return -EINVAL;
429
430Eunknown:
431 brelse(bh);
432 if (!silent)
433 printk("VFS: unable to find oldfs superblock on device %s\n",
434 sb->s_id);
435 goto failed;
436Ebadsize:
437 brelse(bh);
438 if (!silent)
439 printk("VFS: oldfs: unsupported block size (%dKb)\n",
440 1<<(size-2));
441 goto failed;
442}
443
444static int v7_fill_super(struct super_block *sb, void *data, int silent)
445{
446 struct sysv_sb_info *sbi;
447 struct buffer_head *bh, *bh2 = NULL;
448 struct v7_super_block *v7sb;
449 struct sysv_inode *v7i;
450
451 if (440 != sizeof (struct v7_super_block))
452 panic("V7 FS: bad super-block size");
453 if (64 != sizeof (struct sysv_inode))
454 panic("sysv fs: bad i-node size");
455
456 sbi = kmalloc(sizeof(struct sysv_sb_info), GFP_KERNEL);
457 if (!sbi)
458 return -ENOMEM;
459 memset(sbi, 0, sizeof(struct sysv_sb_info));
460
461 sbi->s_sb = sb;
462 sbi->s_block_base = 0;
463 sbi->s_type = FSTYPE_V7;
464 sbi->s_bytesex = BYTESEX_PDP;
465 sb->s_fs_info = sbi;
466
467 sb_set_blocksize(sb, 512);
468
469 if ((bh = sb_bread(sb, 1)) == NULL) {
470 if (!silent)
471 printk("VFS: unable to read V7 FS superblock on "
472 "device %s.\n", sb->s_id);
473 goto failed;
474 }
475
476 /* plausibility check on superblock */
477 v7sb = (struct v7_super_block *) bh->b_data;
478 if (fs16_to_cpu(sbi, v7sb->s_nfree) > V7_NICFREE ||
479 fs16_to_cpu(sbi, v7sb->s_ninode) > V7_NICINOD ||
480 fs32_to_cpu(sbi, v7sb->s_time) == 0)
481 goto failed;
482
483 /* plausibility check on root inode: it is a directory,
484 with a nonzero size that is a multiple of 16 */
485 if ((bh2 = sb_bread(sb, 2)) == NULL)
486 goto failed;
487 v7i = (struct sysv_inode *)(bh2->b_data + 64);
488 if ((fs16_to_cpu(sbi, v7i->i_mode) & ~0777) != S_IFDIR ||
489 (fs32_to_cpu(sbi, v7i->i_size) == 0) ||
490 (fs32_to_cpu(sbi, v7i->i_size) & 017) != 0)
491 goto failed;
492 brelse(bh2);
493 bh2 = NULL;
494
495 sbi->s_bh1 = bh;
496 sbi->s_bh2 = bh;
497 if (complete_read_super(sb, silent, 1))
498 return 0;
499
500failed:
501 brelse(bh2);
502 brelse(bh);
503 kfree(sbi);
504 return -EINVAL;
505}
506
507/* Every kernel module contains stuff like this. */
508
509static struct super_block *sysv_get_sb(struct file_system_type *fs_type,
510 int flags, const char *dev_name, void *data)
511{
512 return get_sb_bdev(fs_type, flags, dev_name, data, sysv_fill_super);
513}
514
515static struct super_block *v7_get_sb(struct file_system_type *fs_type,
516 int flags, const char *dev_name, void *data)
517{
518 return get_sb_bdev(fs_type, flags, dev_name, data, v7_fill_super);
519}
520
521static struct file_system_type sysv_fs_type = {
522 .owner = THIS_MODULE,
523 .name = "sysv",
524 .get_sb = sysv_get_sb,
525 .kill_sb = kill_block_super,
526 .fs_flags = FS_REQUIRES_DEV,
527};
528
529static struct file_system_type v7_fs_type = {
530 .owner = THIS_MODULE,
531 .name = "v7",
532 .get_sb = v7_get_sb,
533 .kill_sb = kill_block_super,
534 .fs_flags = FS_REQUIRES_DEV,
535};
536
537extern int sysv_init_icache(void) __init;
538extern void sysv_destroy_icache(void);
539
540static int __init init_sysv_fs(void)
541{
542 int error;
543
544 error = sysv_init_icache();
545 if (error)
546 goto out;
547 error = register_filesystem(&sysv_fs_type);
548 if (error)
549 goto destroy_icache;
550 error = register_filesystem(&v7_fs_type);
551 if (error)
552 goto unregister;
553 return 0;
554
555unregister:
556 unregister_filesystem(&sysv_fs_type);
557destroy_icache:
558 sysv_destroy_icache();
559out:
560 return error;
561}
562
563static void __exit exit_sysv_fs(void)
564{
565 unregister_filesystem(&sysv_fs_type);
566 unregister_filesystem(&v7_fs_type);
567 sysv_destroy_icache();
568}
569
570module_init(init_sysv_fs)
571module_exit(exit_sysv_fs)
572MODULE_LICENSE("GPL");
diff --git a/fs/sysv/symlink.c b/fs/sysv/symlink.c
new file mode 100644
index 000000000000..ed637db2dcb1
--- /dev/null
+++ b/fs/sysv/symlink.c
@@ -0,0 +1,20 @@
1/*
2 * linux/fs/sysv/symlink.c
3 *
4 * Handling of System V filesystem fast symlinks extensions.
5 * Aug 2001, Christoph Hellwig (hch@infradead.org)
6 */
7
8#include "sysv.h"
9#include <linux/namei.h>
10
11static int sysv_follow_link(struct dentry *dentry, struct nameidata *nd)
12{
13 nd_set_link(nd, (char *)SYSV_I(dentry->d_inode)->i_data);
14 return 0;
15}
16
17struct inode_operations sysv_fast_symlink_inode_operations = {
18 .readlink = generic_readlink,
19 .follow_link = sysv_follow_link,
20};
diff --git a/fs/sysv/sysv.h b/fs/sysv/sysv.h
new file mode 100644
index 000000000000..b7f9b4a42aab
--- /dev/null
+++ b/fs/sysv/sysv.h
@@ -0,0 +1,244 @@
1#ifndef _SYSV_H
2#define _SYSV_H
3
4#include <linux/buffer_head.h>
5
6typedef __u16 __bitwise __fs16;
7typedef __u32 __bitwise __fs32;
8
9#include <linux/sysv_fs.h>
10
11/*
12 * SystemV/V7/Coherent super-block data in memory
13 *
14 * The SystemV/V7/Coherent superblock contains dynamic data (it gets modified
15 * while the system is running). This is in contrast to the Minix and Berkeley
16 * filesystems (where the superblock is never modified). This affects the
17 * sync() operation: we must keep the superblock in a disk buffer and use this
18 * one as our "working copy".
19 */
20
21struct sysv_sb_info {
22 struct super_block *s_sb; /* VFS superblock */
23 int s_type; /* file system type: FSTYPE_{XENIX|SYSV|COH} */
24 char s_bytesex; /* bytesex (le/be/pdp) */
25 char s_truncate; /* if 1: names > SYSV_NAMELEN chars are truncated */
26 /* if 0: they are disallowed (ENAMETOOLONG) */
27 nlink_t s_link_max; /* max number of hard links to a file */
28 unsigned int s_inodes_per_block; /* number of inodes per block */
29 unsigned int s_inodes_per_block_1; /* inodes_per_block - 1 */
30 unsigned int s_inodes_per_block_bits; /* log2(inodes_per_block) */
31 unsigned int s_ind_per_block; /* number of indirections per block */
32 unsigned int s_ind_per_block_bits; /* log2(ind_per_block) */
33 unsigned int s_ind_per_block_2; /* ind_per_block ^ 2 */
34 unsigned int s_toobig_block; /* 10 + ipb + ipb^2 + ipb^3 */
35 unsigned int s_block_base; /* physical block number of block 0 */
36 unsigned short s_fic_size; /* free inode cache size, NICINOD */
37 unsigned short s_flc_size; /* free block list chunk size, NICFREE */
38 /* The superblock is kept in one or two disk buffers: */
39 struct buffer_head *s_bh1;
40 struct buffer_head *s_bh2;
41 /* These are pointers into the disk buffer, to compensate for
42 different superblock layout. */
43 char * s_sbd1; /* entire superblock data, for part 1 */
44 char * s_sbd2; /* entire superblock data, for part 2 */
45 __fs16 *s_sb_fic_count; /* pointer to s_sbd->s_ninode */
46 sysv_ino_t *s_sb_fic_inodes; /* pointer to s_sbd->s_inode */
47 __fs16 *s_sb_total_free_inodes; /* pointer to s_sbd->s_tinode */
48 __fs16 *s_bcache_count; /* pointer to s_sbd->s_nfree */
49 sysv_zone_t *s_bcache; /* pointer to s_sbd->s_free */
50 __fs32 *s_free_blocks; /* pointer to s_sbd->s_tfree */
51 __fs32 *s_sb_time; /* pointer to s_sbd->s_time */
52 __fs32 *s_sb_state; /* pointer to s_sbd->s_state, only FSTYPE_SYSV */
53 /* We keep those superblock entities that don't change here;
54 this saves us an indirection and perhaps a conversion. */
55 u32 s_firstinodezone; /* index of first inode zone */
56 u32 s_firstdatazone; /* same as s_sbd->s_isize */
57 u32 s_ninodes; /* total number of inodes */
58 u32 s_ndatazones; /* total number of data zones */
59 u32 s_nzones; /* same as s_sbd->s_fsize */
60 u16 s_namelen; /* max length of dir entry */
61 int s_forced_ro;
62};
63
64/*
65 * SystemV/V7/Coherent FS inode data in memory
66 */
67struct sysv_inode_info {
68 __fs32 i_data[13];
69 u32 i_dir_start_lookup;
70 struct inode vfs_inode;
71};
72
73
74static inline struct sysv_inode_info *SYSV_I(struct inode *inode)
75{
76 return list_entry(inode, struct sysv_inode_info, vfs_inode);
77}
78
79static inline struct sysv_sb_info *SYSV_SB(struct super_block *sb)
80{
81 return sb->s_fs_info;
82}
83
84
85/* identify the FS in memory */
86enum {
87 FSTYPE_NONE = 0,
88 FSTYPE_XENIX,
89 FSTYPE_SYSV4,
90 FSTYPE_SYSV2,
91 FSTYPE_COH,
92 FSTYPE_V7,
93 FSTYPE_AFS,
94 FSTYPE_END,
95};
96
97#define SYSV_MAGIC_BASE 0x012FF7B3
98
99#define XENIX_SUPER_MAGIC (SYSV_MAGIC_BASE+FSTYPE_XENIX)
100#define SYSV4_SUPER_MAGIC (SYSV_MAGIC_BASE+FSTYPE_SYSV4)
101#define SYSV2_SUPER_MAGIC (SYSV_MAGIC_BASE+FSTYPE_SYSV2)
102#define COH_SUPER_MAGIC (SYSV_MAGIC_BASE+FSTYPE_COH)
103
104
105/* Admissible values for i_nlink: 0.._LINK_MAX */
106enum {
107 XENIX_LINK_MAX = 126, /* ?? */
108 SYSV_LINK_MAX = 126, /* 127? 251? */
109 V7_LINK_MAX = 126, /* ?? */
110 COH_LINK_MAX = 10000,
111};
112
113
114static inline void dirty_sb(struct super_block *sb)
115{
116 struct sysv_sb_info *sbi = SYSV_SB(sb);
117
118 mark_buffer_dirty(sbi->s_bh1);
119 if (sbi->s_bh1 != sbi->s_bh2)
120 mark_buffer_dirty(sbi->s_bh2);
121 sb->s_dirt = 1;
122}
123
124
125/* ialloc.c */
126extern struct sysv_inode *sysv_raw_inode(struct super_block *, unsigned,
127 struct buffer_head **);
128extern struct inode * sysv_new_inode(const struct inode *, mode_t);
129extern void sysv_free_inode(struct inode *);
130extern unsigned long sysv_count_free_inodes(struct super_block *);
131
132/* balloc.c */
133extern sysv_zone_t sysv_new_block(struct super_block *);
134extern void sysv_free_block(struct super_block *, sysv_zone_t);
135extern unsigned long sysv_count_free_blocks(struct super_block *);
136
137/* itree.c */
138extern void sysv_truncate(struct inode *);
139
140/* inode.c */
141extern int sysv_write_inode(struct inode *, int);
142extern int sysv_sync_inode(struct inode *);
143extern int sysv_sync_file(struct file *, struct dentry *, int);
144extern void sysv_set_inode(struct inode *, dev_t);
145extern int sysv_getattr(struct vfsmount *, struct dentry *, struct kstat *);
146
147/* dir.c */
148extern struct sysv_dir_entry *sysv_find_entry(struct dentry *, struct page **);
149extern int sysv_add_link(struct dentry *, struct inode *);
150extern int sysv_delete_entry(struct sysv_dir_entry *, struct page *);
151extern int sysv_make_empty(struct inode *, struct inode *);
152extern int sysv_empty_dir(struct inode *);
153extern void sysv_set_link(struct sysv_dir_entry *, struct page *,
154 struct inode *);
155extern struct sysv_dir_entry *sysv_dotdot(struct inode *, struct page **);
156extern ino_t sysv_inode_by_name(struct dentry *);
157
158
159extern struct inode_operations sysv_file_inode_operations;
160extern struct inode_operations sysv_dir_inode_operations;
161extern struct inode_operations sysv_fast_symlink_inode_operations;
162extern struct file_operations sysv_file_operations;
163extern struct file_operations sysv_dir_operations;
164extern struct address_space_operations sysv_aops;
165extern struct super_operations sysv_sops;
166extern struct dentry_operations sysv_dentry_operations;
167
168
169enum {
170 BYTESEX_LE,
171 BYTESEX_PDP,
172 BYTESEX_BE,
173};
174
175static inline u32 PDP_swab(u32 x)
176{
177#ifdef __LITTLE_ENDIAN
178 return ((x & 0xffff) << 16) | ((x & 0xffff0000) >> 16);
179#else
180#ifdef __BIG_ENDIAN
181 return ((x & 0xff00ff) << 8) | ((x & 0xff00ff00) >> 8);
182#else
183#error BYTESEX
184#endif
185#endif
186}
187
188static inline __u32 fs32_to_cpu(struct sysv_sb_info *sbi, __fs32 n)
189{
190 if (sbi->s_bytesex == BYTESEX_PDP)
191 return PDP_swab((__force __u32)n);
192 else if (sbi->s_bytesex == BYTESEX_LE)
193 return le32_to_cpu((__force __le32)n);
194 else
195 return be32_to_cpu((__force __be32)n);
196}
197
198static inline __fs32 cpu_to_fs32(struct sysv_sb_info *sbi, __u32 n)
199{
200 if (sbi->s_bytesex == BYTESEX_PDP)
201 return (__force __fs32)PDP_swab(n);
202 else if (sbi->s_bytesex == BYTESEX_LE)
203 return (__force __fs32)cpu_to_le32(n);
204 else
205 return (__force __fs32)cpu_to_be32(n);
206}
207
208static inline __fs32 fs32_add(struct sysv_sb_info *sbi, __fs32 *n, int d)
209{
210 if (sbi->s_bytesex == BYTESEX_PDP)
211 *(__u32*)n = PDP_swab(PDP_swab(*(__u32*)n)+d);
212 else if (sbi->s_bytesex == BYTESEX_LE)
213 *(__le32*)n = cpu_to_le32(le32_to_cpu(*(__le32*)n)+d);
214 else
215 *(__be32*)n = cpu_to_be32(be32_to_cpu(*(__be32*)n)+d);
216 return *n;
217}
218
219static inline __u16 fs16_to_cpu(struct sysv_sb_info *sbi, __fs16 n)
220{
221 if (sbi->s_bytesex != BYTESEX_BE)
222 return le16_to_cpu((__force __le16)n);
223 else
224 return be16_to_cpu((__force __be16)n);
225}
226
227static inline __fs16 cpu_to_fs16(struct sysv_sb_info *sbi, __u16 n)
228{
229 if (sbi->s_bytesex != BYTESEX_BE)
230 return (__force __fs16)cpu_to_le16(n);
231 else
232 return (__force __fs16)cpu_to_be16(n);
233}
234
235static inline __fs16 fs16_add(struct sysv_sb_info *sbi, __fs16 *n, int d)
236{
237 if (sbi->s_bytesex != BYTESEX_BE)
238 *(__le16*)n = cpu_to_le16(le16_to_cpu(*(__le16 *)n)+d);
239 else
240 *(__be16*)n = cpu_to_be16(be16_to_cpu(*(__be16 *)n)+d);
241 return *n;
242}
243
244#endif /* _SYSV_H */