aboutsummaryrefslogtreecommitdiffstats
path: root/fs/affs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/affs')
-rw-r--r--fs/affs/Changes343
-rw-r--r--fs/affs/Makefile9
-rw-r--r--fs/affs/affs.h304
-rw-r--r--fs/affs/amigaffs.c509
-rw-r--r--fs/affs/bitmap.c390
-rw-r--r--fs/affs/dir.c155
-rw-r--r--fs/affs/file.c920
-rw-r--r--fs/affs/inode.c411
-rw-r--r--fs/affs/namei.c443
-rw-r--r--fs/affs/super.c569
-rw-r--r--fs/affs/symlink.c78
11 files changed, 4131 insertions, 0 deletions
diff --git a/fs/affs/Changes b/fs/affs/Changes
new file mode 100644
index 000000000000..a29409c1ffe0
--- /dev/null
+++ b/fs/affs/Changes
@@ -0,0 +1,343 @@
1(Note: I consider version numbers as cheap. That means
2that I do not like numbers like 0.1 and the like for
3things that can be used since quite some time. But
4then, 3.1 doesn't mean 'perfectly stable', too.)
5
6Known bugs:
7-----------
8
9- Doesn't work on the alpha. The only 64/32-bit
10 problem that I'm aware of (pointer/int conversion
11 in readdir()) gives compiler warnings but is
12 apparently not causing the failure, as directory
13 reads basically work (but all files are of size 0).
14 Alas, I've got no alpha to debug. :-(
15
16- The partition checker (drivers/block/genhd.c)
17 doesn't work with devices which have 256 byte
18 blocks (some very old SCSI drives).
19
20- The feature to automatically make the fs clean
21 might leave a trashed file system with the
22 bitmap flag set valid.
23
24- When a file is truncated to a size that is not
25 a multiple of the blocksize, the rest of the
26 last allocated block is not cleared. Well,
27 this fs never claimed to be Posix conformant.
28
29Please direct bug reports to: zippel@linux-m68k.org
30
31Version 3.20
32------------
33- kill kernel lock
34- fix for a possible bitmap corruption
35
36Version 3.19
37------------
38
39- sizeof changes from Kernel Janitor Project
40- several bug fixes found with fsx
41
42Version 3.18
43------------
44
45- change to global min macro + warning fixes
46- add module tags
47
48Version 3.17
49------------
50
51- locking fixes
52- wrong sign in __affs_hash_dentry
53- remove unnecessary check in affs_new_inode
54- enable international mode for dircache fs
55
56Version 3.16
57------------
58
59- use mark_buffer_dirty_inode instead of mark_buffer_dirty.
60- introduce affs_lock_{link|dir|ext}.
61
62Version 3.15
63------------
64
65- disable link to directories until we can properly support them.
66- locking fixes for link creation/removal.
67
68Version 3.14
69------------
70
71- correctly cut off long file names for compares
72- correctly initialize s_last_bmap
73
74Version 3.13
75------------
76
77Major cleanup for 2.4 [Roman Zippel]
78- new extended block handling
79- new bitmap allocation functions
80- locking should be safe for the future
81- cleanup of some interfaces
82
83Version 3.12
84------------
85
86more 2.4 fixes: [Roman Zippel]
87- s_lock changes
88- increased getblock mess
89- clear meta blocks
90
91Version 3.11
92------------
93
94- Converted to use 2.3.x page cache [Dave Jones <dave@powertweak.com>]
95- Corruption in truncate() bugfix [Ken Tyler <kent@werple.net.au>]
96
97Version 3.10
98------------
99
100- Changed partition checker to allow devices
101 with physical blocks != 512 bytes.
102
103- The partition checker now also ignores the
104 word at 0xd0 that Windows likes to write to.
105
106Version 3.9
107-----------
108
109- Moved cleanup from release_file() to put_inode().
110 This makes the first one obsolete.
111
112- truncate() zeroes the unused remainder of a
113 partially used last block when a file is truncated.
114 It also marks the inode dirty now (which is not
115 really necessary as notify_change() will do
116 it anyway).
117
118- Added a few comments, fixed some typos (and
119 introduced some new ones), made the debug messages
120 more consistent. Changed a bad example in the
121 doc file (affs.txt).
122
123- Sets the NOEXEC flag in read_super() for old file
124 systems, since you can't run programs on them.
125
126Version 3.8
127-----------
128Bill Hawes kindly reviewed the affs and sent me the
129patches he did. They're marked (BH). Thanks, Bill!
130
131- Cleanup of error handling in read_super().
132 Didn't release all resources in case of an
133 error. (BH)
134
135- put_inode() releases the ext cache only if it's
136 no longer needed. (BH)
137
138- One set of dentry callbacks is enough. (BH)
139
140- Cleanup of error handling in namei.c. (BH)
141
142- Cleanup of error handling in file.c. (BH)
143
144- The original blocksize of the device is
145 restored when the fs is unmounted. (BH)
146
147- getblock() did not invalidate the key cache
148 when it allocated a new block.
149
150- Removed some unnecessary locks as Bill
151 suggested.
152
153- Simplified match_name(), changed all hashing
154 and case insensitive name comparisons to use
155 uppercase. This makes the tolower() routines
156 obsolete.
157
158- Added mount option 'mufs' to force muFS
159 uid/gid interpretation.
160
161- File mode changes were not updated on disk.
162 This was fixed before, but somehow got lost.
163
164Version 3.7
165-----------
166
167- Added dentry callbacks to allow the dcache to
168 operate case insensitive and length ignorant
169 like the affs itself.
170
171- getblock() didn't update the lastblock field in the
172 inode if the fs was not an OFS. This bug only shows
173 up if a file was enlarged via truncate() and there
174 was not enough space.
175
176- Remove some more superfluous code left over from
177 the old link days ...
178
179- Fixed some oversights which were in patch 2.1.78.
180
181- Fixed a few typos.
182
183Version 3.6
184-----------
185
186- dentry changes. (Thanks to Jes Sorensen for his help.)
187
188- Fixed bug in balloc(): Superblock was not set dirty after
189 the bitmap was changed, so the bitmap wasn't sync'd.
190
191- Fixed nasty bug in find_new_zone(): If the current
192 zone number was zero, the loop didn't terminate,
193 causing a solid lock-up.
194
195- Removed support for old-style directory reads.
196
197- Fixed bug in add_entry(): When doing a sorted insert,
198 the pointer to the next entry in the hash chain wasn't
199 correctly byte-swapped. Since most of the users of the
200 affs use it on a 68k, they didn't notice. But why did
201 I not find this during my tests?
202
203- Fixed some oversights (version wasn't updated on some
204 directory changes).
205
206- Handling of hard links rewritten. To the VFS
207 they appear now as normal Unix links. They are
208 now resolved only once in lookup(). The backside
209 is that unlink(), rename() and rmdir() have to
210 be smart about them, but the result is worth the
211 effort. This also led to some code cleanup.
212
213- Changed name type to unsigned char; the test for
214 invalid filenames didn't work correctly.
215 (Thanks to Michael Krause for pointing at this.)
216
217- Changed mapping of executable flag.
218
219- Changed all network byte-order macros to the
220 recommended ones.
221
222- Added a remount function, so attempts to remount
223 a dircache filesystem or one with errors read/write
224 can be trapped. Previously, ro remounts didn't
225 flush the super block, and rw remounts didn't
226 create allocation zones ...
227
228- Call shrink_dcache_parent() in rmdir().
229 (Thanks to Bill Hawes.)
230
231- Permission checks in unlink().
232
233- Allow mounting of volumes with superfluous
234 bitmap pointers read only, also allows them
235 to be remounted read/write.
236
237- Owner/Group defaults now to the fs user (i.e.
238 the one that mounted it) instead of root. This
239 obsoletes the mount options uid and gid.
240
241- Argument to volume option could overflow the
242 name buffer. It is now silently truncated to
243 30 characters. (Damn it! This kind of bug
244 is too embarrassing.)
245
246- Split inode.c into 2 files, the superblock
247 routines desperately wanted their own file.
248
249- truncate() didn't allocate an extension block
250 cache. If a file was extended by means of
251 truncate(), this led to an Oops.
252
253- fsuser is now checked last.
254
255- rename() will not ignore changes in filename
256 casing any more (though mv(1) still won't allow
257 you to do "mv oldname OldName").
258
259Version 3.5
260-----------
261
262- Extension block caches are now allocated on
263 demand instead of when a file is opened, as
264 files can be read and written without opening
265 them (e. g. the loopback device does this).
266
267- Removed an unused function.
268
269Version 3.4
270-----------
271
272- Hash chains are now sorted by block numbers.
273 (Thanks to Kars de Jong for finding this.)
274- Removed all unnecessary external symbols.
275
276Version 3.3
277-----------
278
279- Tried to make all types 'correct' and consistent.
280- Errors and warnings are now reported via a
281 function. They are all prefixed by a severity
282 and have the same appearance:
283 "AFFS: <function>: <error message>"
284 (There's one exception to this, as in that function
285 is no pointer to the super block available.)
286- The filesystem is remounted read-only after an
287 error.
288- The names of newly created filesystem objects are
289 now checked for validity.
290- Minor cleanups in comments.
291- Added this Changes file. At last!
292
293Version 3.2
294-----------
295
296- Extension block cache: Reading/writing of huge files
297 (several MB) is much faster (of course the added
298 overhead slows down opening, but this is hardly
299 noticeable).
300- The same get_block()-routine can now be used for
301 both OFS and FFS.
302- The super block is now searched in the block that
303 was calculated and in the one following. This
304 should remedy the round-off error introduced by
305 the 1-k blocks that Linux uses.
306- Minor changes to adhere to the new VFS interface.
307- The number of used blocks is now also calculated
308 if the filesystem is mounted read-only.
309- Prefixed some constants with AFFS_ to avoid name
310 clashes.
311- Removed 'EXPERIMENTAL' status.
312
313Version 3.1
314-----------
315
316- Fixed a nasty bug which didn't allow read-only
317 mounts.
318- Allow dir-cache filesystems to be mounted
319 read only.
320- OFS support.
321- Several other changes I just cannot remember
322 any more.
323
324Version 3.0
325-----------
326
327- Almost complete rewrite for the new VFS
328 interface in Linux 1.3.
329- Write support.
330- Support for hard and symbolic links.
331- Lots of things I remember even less ...
332
333Version 2.0
334-----------
335
336- Fixed a few things to get it compiled.
337- Automatic root block calculation.
338- Partition checker for genhd.c
339
340========================================
341
342Let's just call Ray Burr's original affs
343'Version 1.0'.
diff --git a/fs/affs/Makefile b/fs/affs/Makefile
new file mode 100644
index 000000000000..b2c4f54446f3
--- /dev/null
+++ b/fs/affs/Makefile
@@ -0,0 +1,9 @@
1#
2# Makefile for the Linux affs filesystem routines.
3#
4
5#EXTRA_CFLAGS=-DDEBUG=1
6
7obj-$(CONFIG_AFFS_FS) += affs.o
8
9affs-objs := super.o namei.o inode.o file.o dir.o amigaffs.o bitmap.o symlink.o
diff --git a/fs/affs/affs.h b/fs/affs/affs.h
new file mode 100644
index 000000000000..0c6799f2137a
--- /dev/null
+++ b/fs/affs/affs.h
@@ -0,0 +1,304 @@
1#include <linux/types.h>
2#include <linux/fs.h>
3#include <linux/buffer_head.h>
4#include <linux/affs_fs.h>
5#include <linux/amigaffs.h>
6
7/* AmigaOS allows file names with up to 30 characters length.
8 * Names longer than that will be silently truncated. If you
9 * want to disallow this, comment out the following #define.
10 * Creating filesystem objects with longer names will then
11 * result in an error (ENAMETOOLONG).
12 */
13/*#define AFFS_NO_TRUNCATE */
14
15/* Ugly macros make the code more pretty. */
16
17#define GET_END_PTR(st,p,sz) ((st *)((char *)(p)+((sz)-sizeof(st))))
18#define AFFS_GET_HASHENTRY(data,hashkey) be32_to_cpu(((struct dir_front *)data)->hashtable[hashkey])
19#define AFFS_BLOCK(sb, bh, blk) (AFFS_HEAD(bh)->table[AFFS_SB(sb)->s_hashsize-1-(blk)])
20
21#ifdef __LITTLE_ENDIAN
22#define BO_EXBITS 0x18UL
23#elif defined(__BIG_ENDIAN)
24#define BO_EXBITS 0x00UL
25#else
26#error Endianness must be known for affs to work.
27#endif
28
29#define AFFS_HEAD(bh) ((struct affs_head *)(bh)->b_data)
30#define AFFS_TAIL(sb, bh) ((struct affs_tail *)((bh)->b_data+(sb)->s_blocksize-sizeof(struct affs_tail)))
31#define AFFS_ROOT_HEAD(bh) ((struct affs_root_head *)(bh)->b_data)
32#define AFFS_ROOT_TAIL(sb, bh) ((struct affs_root_tail *)((bh)->b_data+(sb)->s_blocksize-sizeof(struct affs_root_tail)))
33#define AFFS_DATA_HEAD(bh) ((struct affs_data_head *)(bh)->b_data)
34#define AFFS_DATA(bh) (((struct affs_data_head *)(bh)->b_data)->data)
35
36#define AFFS_CACHE_SIZE PAGE_SIZE
37
38#define AFFS_MAX_PREALLOC 32
39#define AFFS_LC_SIZE (AFFS_CACHE_SIZE/sizeof(u32)/2)
40#define AFFS_AC_SIZE (AFFS_CACHE_SIZE/sizeof(struct affs_ext_key)/2)
41#define AFFS_AC_MASK (AFFS_AC_SIZE-1)
42
43struct affs_ext_key {
44 u32 ext; /* idx of the extended block */
45 u32 key; /* block number */
46};
47
48/*
49 * affs fs inode data in memory
50 */
51struct affs_inode_info {
52 u32 i_opencnt;
53 struct semaphore i_link_lock; /* Protects internal inode access. */
54 struct semaphore i_ext_lock; /* Protects internal inode access. */
55#define i_hash_lock i_ext_lock
56 u32 i_blkcnt; /* block count */
57 u32 i_extcnt; /* extended block count */
58 u32 *i_lc; /* linear cache of extended blocks */
59 u32 i_lc_size;
60 u32 i_lc_shift;
61 u32 i_lc_mask;
62 struct affs_ext_key *i_ac; /* associative cache of extended blocks */
63 u32 i_ext_last; /* last accessed extended block */
64 struct buffer_head *i_ext_bh; /* bh of last extended block */
65 loff_t mmu_private;
66 u32 i_protect; /* unused attribute bits */
67 u32 i_lastalloc; /* last allocated block */
68 int i_pa_cnt; /* number of preallocated blocks */
69 struct inode vfs_inode;
70};
71
72/* short cut to get to the affs specific inode data */
73static inline struct affs_inode_info *AFFS_I(struct inode *inode)
74{
75 return list_entry(inode, struct affs_inode_info, vfs_inode);
76}
77
78/*
79 * super-block data in memory
80 *
81 * Block numbers are adjusted for their actual size
82 *
83 */
84
85struct affs_bm_info {
86 u32 bm_key; /* Disk block number */
87 u32 bm_free; /* Free blocks in here */
88};
89
90struct affs_sb_info {
91 int s_partition_size; /* Partition size in blocks. */
92 int s_reserved; /* Number of reserved blocks. */
93 //u32 s_blksize; /* Initial device blksize */
94 u32 s_data_blksize; /* size of the data block w/o header */
95 u32 s_root_block; /* FFS root block number. */
96 int s_hashsize; /* Size of hash table. */
97 unsigned long s_flags; /* See below. */
98 uid_t s_uid; /* uid to override */
99 gid_t s_gid; /* gid to override */
100 umode_t s_mode; /* mode to override */
101 struct buffer_head *s_root_bh; /* Cached root block. */
102 struct semaphore s_bmlock; /* Protects bitmap access. */
103 struct affs_bm_info *s_bitmap; /* Bitmap infos. */
104 u32 s_bmap_count; /* # of bitmap blocks. */
105 u32 s_bmap_bits; /* # of bits in one bitmap blocks */
106 u32 s_last_bmap;
107 struct buffer_head *s_bmap_bh;
108 char *s_prefix; /* Prefix for volumes and assigns. */
109 int s_prefix_len; /* Length of prefix. */
110 char s_volume[32]; /* Volume prefix for absolute symlinks. */
111};
112
113#define SF_INTL 0x0001 /* International filesystem. */
114#define SF_BM_VALID 0x0002 /* Bitmap is valid. */
115#define SF_IMMUTABLE 0x0004 /* Protection bits cannot be changed */
116#define SF_QUIET 0x0008 /* chmod errors will be not reported */
117#define SF_SETUID 0x0010 /* Ignore Amiga uid */
118#define SF_SETGID 0x0020 /* Ignore Amiga gid */
119#define SF_SETMODE 0x0040 /* Ignore Amiga protection bits */
120#define SF_MUFS 0x0100 /* Use MUFS uid/gid mapping */
121#define SF_OFS 0x0200 /* Old filesystem */
122#define SF_PREFIX 0x0400 /* Buffer for prefix is allocated */
123#define SF_VERBOSE 0x0800 /* Talk about fs when mounting */
124
125/* short cut to get to the affs specific sb data */
126static inline struct affs_sb_info *AFFS_SB(struct super_block *sb)
127{
128 return sb->s_fs_info;
129}
130
131/* amigaffs.c */
132
133extern int affs_insert_hash(struct inode *inode, struct buffer_head *bh);
134extern int affs_remove_hash(struct inode *dir, struct buffer_head *rem_bh);
135extern int affs_remove_header(struct dentry *dentry);
136extern u32 affs_checksum_block(struct super_block *sb, struct buffer_head *bh);
137extern void affs_fix_checksum(struct super_block *sb, struct buffer_head *bh);
138extern void secs_to_datestamp(time_t secs, struct affs_date *ds);
139extern mode_t prot_to_mode(u32 prot);
140extern void mode_to_prot(struct inode *inode);
141extern void affs_error(struct super_block *sb, const char *function, const char *fmt, ...);
142extern void affs_warning(struct super_block *sb, const char *function, const char *fmt, ...);
143extern int affs_check_name(const unsigned char *name, int len);
144extern int affs_copy_name(unsigned char *bstr, struct dentry *dentry);
145
146/* bitmap. c */
147
148extern u32 affs_count_free_blocks(struct super_block *s);
149extern void affs_free_block(struct super_block *sb, u32 block);
150extern u32 affs_alloc_block(struct inode *inode, u32 goal);
151extern int affs_init_bitmap(struct super_block *sb, int *flags);
152extern void affs_free_bitmap(struct super_block *sb);
153
154/* namei.c */
155
156extern int affs_hash_name(struct super_block *sb, const u8 *name, unsigned int len);
157extern struct dentry *affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *);
158extern int affs_unlink(struct inode *dir, struct dentry *dentry);
159extern int affs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *);
160extern int affs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
161extern int affs_rmdir(struct inode *dir, struct dentry *dentry);
162extern int affs_link(struct dentry *olddentry, struct inode *dir,
163 struct dentry *dentry);
164extern int affs_symlink(struct inode *dir, struct dentry *dentry,
165 const char *symname);
166extern int affs_rename(struct inode *old_dir, struct dentry *old_dentry,
167 struct inode *new_dir, struct dentry *new_dentry);
168
169/* inode.c */
170
171extern unsigned long affs_parent_ino(struct inode *dir);
172extern struct inode *affs_new_inode(struct inode *dir);
173extern int affs_notify_change(struct dentry *dentry, struct iattr *attr);
174extern void affs_put_inode(struct inode *inode);
175extern void affs_delete_inode(struct inode *inode);
176extern void affs_clear_inode(struct inode *inode);
177extern void affs_read_inode(struct inode *inode);
178extern int affs_write_inode(struct inode *inode, int);
179extern int affs_add_entry(struct inode *dir, struct inode *inode, struct dentry *dentry, s32 type);
180
181/* file.c */
182
183void affs_free_prealloc(struct inode *inode);
184extern void affs_truncate(struct inode *);
185
186/* dir.c */
187
188extern void affs_dir_truncate(struct inode *);
189
190/* jump tables */
191
192extern struct inode_operations affs_file_inode_operations;
193extern struct inode_operations affs_dir_inode_operations;
194extern struct inode_operations affs_symlink_inode_operations;
195extern struct file_operations affs_file_operations;
196extern struct file_operations affs_file_operations_ofs;
197extern struct file_operations affs_dir_operations;
198extern struct address_space_operations affs_symlink_aops;
199extern struct address_space_operations affs_aops;
200extern struct address_space_operations affs_aops_ofs;
201
202extern struct dentry_operations affs_dentry_operations;
203extern struct dentry_operations affs_dentry_operations_intl;
204
205static inline void
206affs_set_blocksize(struct super_block *sb, int size)
207{
208 sb_set_blocksize(sb, size);
209}
210static inline struct buffer_head *
211affs_bread(struct super_block *sb, int block)
212{
213 pr_debug("affs_bread: %d\n", block);
214 if (block >= AFFS_SB(sb)->s_reserved && block < AFFS_SB(sb)->s_partition_size)
215 return sb_bread(sb, block);
216 return NULL;
217}
218static inline struct buffer_head *
219affs_getblk(struct super_block *sb, int block)
220{
221 pr_debug("affs_getblk: %d\n", block);
222 if (block >= AFFS_SB(sb)->s_reserved && block < AFFS_SB(sb)->s_partition_size)
223 return sb_getblk(sb, block);
224 return NULL;
225}
226static inline struct buffer_head *
227affs_getzeroblk(struct super_block *sb, int block)
228{
229 struct buffer_head *bh;
230 pr_debug("affs_getzeroblk: %d\n", block);
231 if (block >= AFFS_SB(sb)->s_reserved && block < AFFS_SB(sb)->s_partition_size) {
232 bh = sb_getblk(sb, block);
233 lock_buffer(bh);
234 memset(bh->b_data, 0 , sb->s_blocksize);
235 set_buffer_uptodate(bh);
236 unlock_buffer(bh);
237 return bh;
238 }
239 return NULL;
240}
241static inline struct buffer_head *
242affs_getemptyblk(struct super_block *sb, int block)
243{
244 struct buffer_head *bh;
245 pr_debug("affs_getemptyblk: %d\n", block);
246 if (block >= AFFS_SB(sb)->s_reserved && block < AFFS_SB(sb)->s_partition_size) {
247 bh = sb_getblk(sb, block);
248 wait_on_buffer(bh);
249 set_buffer_uptodate(bh);
250 return bh;
251 }
252 return NULL;
253}
254static inline void
255affs_brelse(struct buffer_head *bh)
256{
257 if (bh)
258 pr_debug("affs_brelse: %lld\n", (long long) bh->b_blocknr);
259 brelse(bh);
260}
261
262static inline void
263affs_adjust_checksum(struct buffer_head *bh, u32 val)
264{
265 u32 tmp = be32_to_cpu(((__be32 *)bh->b_data)[5]);
266 ((__be32 *)bh->b_data)[5] = cpu_to_be32(tmp - val);
267}
268static inline void
269affs_adjust_bitmapchecksum(struct buffer_head *bh, u32 val)
270{
271 u32 tmp = be32_to_cpu(((__be32 *)bh->b_data)[0]);
272 ((__be32 *)bh->b_data)[0] = cpu_to_be32(tmp - val);
273}
274
275static inline void
276affs_lock_link(struct inode *inode)
277{
278 down(&AFFS_I(inode)->i_link_lock);
279}
280static inline void
281affs_unlock_link(struct inode *inode)
282{
283 up(&AFFS_I(inode)->i_link_lock);
284}
285static inline void
286affs_lock_dir(struct inode *inode)
287{
288 down(&AFFS_I(inode)->i_hash_lock);
289}
290static inline void
291affs_unlock_dir(struct inode *inode)
292{
293 up(&AFFS_I(inode)->i_hash_lock);
294}
295static inline void
296affs_lock_ext(struct inode *inode)
297{
298 down(&AFFS_I(inode)->i_ext_lock);
299}
300static inline void
301affs_unlock_ext(struct inode *inode)
302{
303 up(&AFFS_I(inode)->i_ext_lock);
304}
diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c
new file mode 100644
index 000000000000..ccd624ef4272
--- /dev/null
+++ b/fs/affs/amigaffs.c
@@ -0,0 +1,509 @@
1/*
2 * linux/fs/affs/amigaffs.c
3 *
4 * (c) 1996 Hans-Joachim Widmaier - Rewritten
5 *
6 * (C) 1993 Ray Burr - Amiga FFS filesystem.
7 *
8 * Please send bug reports to: hjw@zvw.de
9 */
10
11#include "affs.h"
12
13extern struct timezone sys_tz;
14
15static char ErrorBuffer[256];
16
17/*
18 * Functions for accessing Amiga-FFS structures.
19 */
20
21
22/* Insert a header block bh into the directory dir
23 * caller must hold AFFS_DIR->i_hash_lock!
24 */
25
26int
27affs_insert_hash(struct inode *dir, struct buffer_head *bh)
28{
29 struct super_block *sb = dir->i_sb;
30 struct buffer_head *dir_bh;
31 u32 ino, hash_ino;
32 int offset;
33
34 ino = bh->b_blocknr;
35 offset = affs_hash_name(sb, AFFS_TAIL(sb, bh)->name + 1, AFFS_TAIL(sb, bh)->name[0]);
36
37 pr_debug("AFFS: insert_hash(dir=%u, ino=%d)\n", (u32)dir->i_ino, ino);
38
39 dir_bh = affs_bread(sb, dir->i_ino);
40 if (!dir_bh)
41 return -EIO;
42
43 hash_ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[offset]);
44 while (hash_ino) {
45 affs_brelse(dir_bh);
46 dir_bh = affs_bread(sb, hash_ino);
47 if (!dir_bh)
48 return -EIO;
49 hash_ino = be32_to_cpu(AFFS_TAIL(sb, dir_bh)->hash_chain);
50 }
51 AFFS_TAIL(sb, bh)->parent = cpu_to_be32(dir->i_ino);
52 AFFS_TAIL(sb, bh)->hash_chain = 0;
53 affs_fix_checksum(sb, bh);
54
55 if (dir->i_ino == dir_bh->b_blocknr)
56 AFFS_HEAD(dir_bh)->table[offset] = cpu_to_be32(ino);
57 else
58 AFFS_TAIL(sb, dir_bh)->hash_chain = cpu_to_be32(ino);
59
60 affs_adjust_checksum(dir_bh, ino);
61 mark_buffer_dirty_inode(dir_bh, dir);
62 affs_brelse(dir_bh);
63
64 dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
65 dir->i_version++;
66 mark_inode_dirty(dir);
67
68 return 0;
69}
70
71/* Remove a header block from its directory.
72 * caller must hold AFFS_DIR->i_hash_lock!
73 */
74
75int
76affs_remove_hash(struct inode *dir, struct buffer_head *rem_bh)
77{
78 struct super_block *sb;
79 struct buffer_head *bh;
80 u32 rem_ino, hash_ino;
81 __be32 ino;
82 int offset, retval;
83
84 sb = dir->i_sb;
85 rem_ino = rem_bh->b_blocknr;
86 offset = affs_hash_name(sb, AFFS_TAIL(sb, rem_bh)->name+1, AFFS_TAIL(sb, rem_bh)->name[0]);
87 pr_debug("AFFS: remove_hash(dir=%d, ino=%d, hashval=%d)\n", (u32)dir->i_ino, rem_ino, offset);
88
89 bh = affs_bread(sb, dir->i_ino);
90 if (!bh)
91 return -EIO;
92
93 retval = -ENOENT;
94 hash_ino = be32_to_cpu(AFFS_HEAD(bh)->table[offset]);
95 while (hash_ino) {
96 if (hash_ino == rem_ino) {
97 ino = AFFS_TAIL(sb, rem_bh)->hash_chain;
98 if (dir->i_ino == bh->b_blocknr)
99 AFFS_HEAD(bh)->table[offset] = ino;
100 else
101 AFFS_TAIL(sb, bh)->hash_chain = ino;
102 affs_adjust_checksum(bh, be32_to_cpu(ino) - hash_ino);
103 mark_buffer_dirty_inode(bh, dir);
104 AFFS_TAIL(sb, rem_bh)->parent = 0;
105 retval = 0;
106 break;
107 }
108 affs_brelse(bh);
109 bh = affs_bread(sb, hash_ino);
110 if (!bh)
111 return -EIO;
112 hash_ino = be32_to_cpu(AFFS_TAIL(sb, bh)->hash_chain);
113 }
114
115 affs_brelse(bh);
116
117 dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
118 dir->i_version++;
119 mark_inode_dirty(dir);
120
121 return retval;
122}
123
124static void
125affs_fix_dcache(struct dentry *dentry, u32 entry_ino)
126{
127 struct inode *inode = dentry->d_inode;
128 void *data = dentry->d_fsdata;
129 struct list_head *head, *next;
130
131 spin_lock(&dcache_lock);
132 head = &inode->i_dentry;
133 next = head->next;
134 while (next != head) {
135 dentry = list_entry(next, struct dentry, d_alias);
136 if (entry_ino == (u32)(long)dentry->d_fsdata) {
137 dentry->d_fsdata = data;
138 break;
139 }
140 next = next->next;
141 }
142 spin_unlock(&dcache_lock);
143}
144
145
146/* Remove header from link chain */
147
148static int
149affs_remove_link(struct dentry *dentry)
150{
151 struct inode *dir, *inode = dentry->d_inode;
152 struct super_block *sb = inode->i_sb;
153 struct buffer_head *bh = NULL, *link_bh = NULL;
154 u32 link_ino, ino;
155 int retval;
156
157 pr_debug("AFFS: remove_link(key=%ld)\n", inode->i_ino);
158 retval = -EIO;
159 bh = affs_bread(sb, inode->i_ino);
160 if (!bh)
161 goto done;
162
163 link_ino = (u32)(long)dentry->d_fsdata;
164 if (inode->i_ino == link_ino) {
165 /* we can't remove the head of the link, as its blocknr is still used as ino,
166 * so we remove the block of the first link instead.
167 */
168 link_ino = be32_to_cpu(AFFS_TAIL(sb, bh)->link_chain);
169 link_bh = affs_bread(sb, link_ino);
170 if (!link_bh)
171 goto done;
172
173 dir = iget(sb, be32_to_cpu(AFFS_TAIL(sb, link_bh)->parent));
174 if (!dir)
175 goto done;
176
177 affs_lock_dir(dir);
178 affs_fix_dcache(dentry, link_ino);
179 retval = affs_remove_hash(dir, link_bh);
180 if (retval)
181 goto done;
182 mark_buffer_dirty_inode(link_bh, inode);
183
184 memcpy(AFFS_TAIL(sb, bh)->name, AFFS_TAIL(sb, link_bh)->name, 32);
185 retval = affs_insert_hash(dir, bh);
186 if (retval)
187 goto done;
188 mark_buffer_dirty_inode(bh, inode);
189
190 affs_unlock_dir(dir);
191 iput(dir);
192 } else {
193 link_bh = affs_bread(sb, link_ino);
194 if (!link_bh)
195 goto done;
196 }
197
198 while ((ino = be32_to_cpu(AFFS_TAIL(sb, bh)->link_chain)) != 0) {
199 if (ino == link_ino) {
200 __be32 ino2 = AFFS_TAIL(sb, link_bh)->link_chain;
201 AFFS_TAIL(sb, bh)->link_chain = ino2;
202 affs_adjust_checksum(bh, be32_to_cpu(ino2) - link_ino);
203 mark_buffer_dirty_inode(bh, inode);
204 retval = 0;
205 /* Fix the link count, if bh is a normal header block without links */
206 switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) {
207 case ST_LINKDIR:
208 case ST_LINKFILE:
209 break;
210 default:
211 if (!AFFS_TAIL(sb, bh)->link_chain)
212 inode->i_nlink = 1;
213 }
214 affs_free_block(sb, link_ino);
215 goto done;
216 }
217 affs_brelse(bh);
218 bh = affs_bread(sb, ino);
219 if (!bh)
220 goto done;
221 }
222 retval = -ENOENT;
223done:
224 affs_brelse(link_bh);
225 affs_brelse(bh);
226 return retval;
227}
228
229
230static int
231affs_empty_dir(struct inode *inode)
232{
233 struct super_block *sb = inode->i_sb;
234 struct buffer_head *bh;
235 int retval, size;
236
237 retval = -EIO;
238 bh = affs_bread(sb, inode->i_ino);
239 if (!bh)
240 goto done;
241
242 retval = -ENOTEMPTY;
243 for (size = AFFS_SB(sb)->s_hashsize - 1; size >= 0; size--)
244 if (AFFS_HEAD(bh)->table[size])
245 goto not_empty;
246 retval = 0;
247not_empty:
248 affs_brelse(bh);
249done:
250 return retval;
251}
252
253
254/* Remove a filesystem object. If the object to be removed has
255 * links to it, one of the links must be changed to inherit
256 * the file or directory. As above, any inode will do.
257 * The buffer will not be freed. If the header is a link, the
258 * block will be marked as free.
259 * This function returns a negative error number in case of
260 * an error, else 0 if the inode is to be deleted or 1 if not.
261 */
262
263int
264affs_remove_header(struct dentry *dentry)
265{
266 struct super_block *sb;
267 struct inode *inode, *dir;
268 struct buffer_head *bh = NULL;
269 int retval;
270
271 dir = dentry->d_parent->d_inode;
272 sb = dir->i_sb;
273
274 retval = -ENOENT;
275 inode = dentry->d_inode;
276 if (!inode)
277 goto done;
278
279 pr_debug("AFFS: remove_header(key=%ld)\n", inode->i_ino);
280 retval = -EIO;
281 bh = affs_bread(sb, (u32)(long)dentry->d_fsdata);
282 if (!bh)
283 goto done;
284
285 affs_lock_link(inode);
286 affs_lock_dir(dir);
287 switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) {
288 case ST_USERDIR:
289 /* if we ever want to support links to dirs
290 * i_hash_lock of the inode must only be
291 * taken after some checks
292 */
293 affs_lock_dir(inode);
294 retval = affs_empty_dir(inode);
295 affs_unlock_dir(inode);
296 if (retval)
297 goto done_unlock;
298 break;
299 default:
300 break;
301 }
302
303 retval = affs_remove_hash(dir, bh);
304 if (retval)
305 goto done_unlock;
306 mark_buffer_dirty_inode(bh, inode);
307
308 affs_unlock_dir(dir);
309
310 if (inode->i_nlink > 1)
311 retval = affs_remove_link(dentry);
312 else
313 inode->i_nlink = 0;
314 affs_unlock_link(inode);
315 inode->i_ctime = CURRENT_TIME_SEC;
316 mark_inode_dirty(inode);
317
318done:
319 affs_brelse(bh);
320 return retval;
321
322done_unlock:
323 affs_unlock_dir(dir);
324 affs_unlock_link(inode);
325 goto done;
326}
327
328/* Checksum a block, do various consistency checks and optionally return
329 the blocks type number. DATA points to the block. If their pointers
330 are non-null, *PTYPE and *STYPE are set to the primary and secondary
331 block types respectively, *HASHSIZE is set to the size of the hashtable
332 (which lets us calculate the block size).
333 Returns non-zero if the block is not consistent. */
334
335u32
336affs_checksum_block(struct super_block *sb, struct buffer_head *bh)
337{
338 __be32 *ptr = (__be32 *)bh->b_data;
339 u32 sum;
340 int bsize;
341
342 sum = 0;
343 for (bsize = sb->s_blocksize / sizeof(__be32); bsize > 0; bsize--)
344 sum += be32_to_cpu(*ptr++);
345 return sum;
346}
347
348/*
349 * Calculate the checksum of a disk block and store it
350 * at the indicated position.
351 */
352
353void
354affs_fix_checksum(struct super_block *sb, struct buffer_head *bh)
355{
356 int cnt = sb->s_blocksize / sizeof(__be32);
357 __be32 *ptr = (__be32 *)bh->b_data;
358 u32 checksum;
359 __be32 *checksumptr;
360
361 checksumptr = ptr + 5;
362 *checksumptr = 0;
363 for (checksum = 0; cnt > 0; ptr++, cnt--)
364 checksum += be32_to_cpu(*ptr);
365 *checksumptr = cpu_to_be32(-checksum);
366}
367
368void
369secs_to_datestamp(time_t secs, struct affs_date *ds)
370{
371 u32 days;
372 u32 minute;
373
374 secs -= sys_tz.tz_minuteswest * 60 + ((8 * 365 + 2) * 24 * 60 * 60);
375 if (secs < 0)
376 secs = 0;
377 days = secs / 86400;
378 secs -= days * 86400;
379 minute = secs / 60;
380 secs -= minute * 60;
381
382 ds->days = cpu_to_be32(days);
383 ds->mins = cpu_to_be32(minute);
384 ds->ticks = cpu_to_be32(secs * 50);
385}
386
387mode_t
388prot_to_mode(u32 prot)
389{
390 int mode = 0;
391
392 if (!(prot & FIBF_NOWRITE))
393 mode |= S_IWUSR;
394 if (!(prot & FIBF_NOREAD))
395 mode |= S_IRUSR;
396 if (!(prot & FIBF_NOEXECUTE))
397 mode |= S_IXUSR;
398 if (prot & FIBF_GRP_WRITE)
399 mode |= S_IWGRP;
400 if (prot & FIBF_GRP_READ)
401 mode |= S_IRGRP;
402 if (prot & FIBF_GRP_EXECUTE)
403 mode |= S_IXGRP;
404 if (prot & FIBF_OTR_WRITE)
405 mode |= S_IWOTH;
406 if (prot & FIBF_OTR_READ)
407 mode |= S_IROTH;
408 if (prot & FIBF_OTR_EXECUTE)
409 mode |= S_IXOTH;
410
411 return mode;
412}
413
414void
415mode_to_prot(struct inode *inode)
416{
417 u32 prot = AFFS_I(inode)->i_protect;
418 mode_t mode = inode->i_mode;
419
420 if (!(mode & S_IXUSR))
421 prot |= FIBF_NOEXECUTE;
422 if (!(mode & S_IRUSR))
423 prot |= FIBF_NOREAD;
424 if (!(mode & S_IWUSR))
425 prot |= FIBF_NOWRITE;
426 if (mode & S_IXGRP)
427 prot |= FIBF_GRP_EXECUTE;
428 if (mode & S_IRGRP)
429 prot |= FIBF_GRP_READ;
430 if (mode & S_IWGRP)
431 prot |= FIBF_GRP_WRITE;
432 if (mode & S_IXOTH)
433 prot |= FIBF_OTR_EXECUTE;
434 if (mode & S_IROTH)
435 prot |= FIBF_OTR_READ;
436 if (mode & S_IWOTH)
437 prot |= FIBF_OTR_WRITE;
438
439 AFFS_I(inode)->i_protect = prot;
440}
441
442void
443affs_error(struct super_block *sb, const char *function, const char *fmt, ...)
444{
445 va_list args;
446
447 va_start(args,fmt);
448 vsprintf(ErrorBuffer,fmt,args);
449 va_end(args);
450
451 printk(KERN_CRIT "AFFS error (device %s): %s(): %s\n", sb->s_id,
452 function,ErrorBuffer);
453 if (!(sb->s_flags & MS_RDONLY))
454 printk(KERN_WARNING "AFFS: Remounting filesystem read-only\n");
455 sb->s_flags |= MS_RDONLY;
456}
457
458void
459affs_warning(struct super_block *sb, const char *function, const char *fmt, ...)
460{
461 va_list args;
462
463 va_start(args,fmt);
464 vsprintf(ErrorBuffer,fmt,args);
465 va_end(args);
466
467 printk(KERN_WARNING "AFFS warning (device %s): %s(): %s\n", sb->s_id,
468 function,ErrorBuffer);
469}
470
471/* Check if the name is valid for a affs object. */
472
473int
474affs_check_name(const unsigned char *name, int len)
475{
476 int i;
477
478 if (len > 30)
479#ifdef AFFS_NO_TRUNCATE
480 return -ENAMETOOLONG;
481#else
482 len = 30;
483#endif
484
485 for (i = 0; i < len; i++) {
486 if (name[i] < ' ' || name[i] == ':'
487 || (name[i] > 0x7e && name[i] < 0xa0))
488 return -EINVAL;
489 }
490
491 return 0;
492}
493
494/* This function copies name to bstr, with at most 30
495 * characters length. The bstr will be prepended by
496 * a length byte.
497 * NOTE: The name will must be already checked by
498 * affs_check_name()!
499 */
500
501int
502affs_copy_name(unsigned char *bstr, struct dentry *dentry)
503{
504 int len = min(dentry->d_name.len, 30u);
505
506 *bstr++ = len;
507 memcpy(bstr, dentry->d_name.name, len);
508 return len;
509}
diff --git a/fs/affs/bitmap.c b/fs/affs/bitmap.c
new file mode 100644
index 000000000000..b0b953683c1a
--- /dev/null
+++ b/fs/affs/bitmap.c
@@ -0,0 +1,390 @@
1/*
2 * linux/fs/affs/bitmap.c
3 *
4 * (c) 1996 Hans-Joachim Widmaier
5 *
6 * bitmap.c contains the code that handles all bitmap related stuff -
7 * block allocation, deallocation, calculation of free space.
8 */
9
10#include "affs.h"
11
12/* This is, of course, shamelessly stolen from fs/minix */
13
14static int nibblemap[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 };
15
16static u32
17affs_count_free_bits(u32 blocksize, const void *data)
18{
19 const u32 *map;
20 u32 free;
21 u32 tmp;
22
23 map = data;
24 free = 0;
25 for (blocksize /= 4; blocksize > 0; blocksize--) {
26 tmp = *map++;
27 while (tmp) {
28 free += nibblemap[tmp & 0xf];
29 tmp >>= 4;
30 }
31 }
32
33 return free;
34}
35
36u32
37affs_count_free_blocks(struct super_block *sb)
38{
39 struct affs_bm_info *bm;
40 u32 free;
41 int i;
42
43 pr_debug("AFFS: count_free_blocks()\n");
44
45 if (sb->s_flags & MS_RDONLY)
46 return 0;
47
48 down(&AFFS_SB(sb)->s_bmlock);
49
50 bm = AFFS_SB(sb)->s_bitmap;
51 free = 0;
52 for (i = AFFS_SB(sb)->s_bmap_count; i > 0; bm++, i--)
53 free += bm->bm_free;
54
55 up(&AFFS_SB(sb)->s_bmlock);
56
57 return free;
58}
59
60void
61affs_free_block(struct super_block *sb, u32 block)
62{
63 struct affs_sb_info *sbi = AFFS_SB(sb);
64 struct affs_bm_info *bm;
65 struct buffer_head *bh;
66 u32 blk, bmap, bit, mask, tmp;
67 __be32 *data;
68
69 pr_debug("AFFS: free_block(%u)\n", block);
70
71 if (block > sbi->s_partition_size)
72 goto err_range;
73
74 blk = block - sbi->s_reserved;
75 bmap = blk / sbi->s_bmap_bits;
76 bit = blk % sbi->s_bmap_bits;
77 bm = &sbi->s_bitmap[bmap];
78
79 down(&sbi->s_bmlock);
80
81 bh = sbi->s_bmap_bh;
82 if (sbi->s_last_bmap != bmap) {
83 affs_brelse(bh);
84 bh = affs_bread(sb, bm->bm_key);
85 if (!bh)
86 goto err_bh_read;
87 sbi->s_bmap_bh = bh;
88 sbi->s_last_bmap = bmap;
89 }
90
91 mask = 1 << (bit & 31);
92 data = (__be32 *)bh->b_data + bit / 32 + 1;
93
94 /* mark block free */
95 tmp = be32_to_cpu(*data);
96 if (tmp & mask)
97 goto err_free;
98 *data = cpu_to_be32(tmp | mask);
99
100 /* fix checksum */
101 tmp = be32_to_cpu(*(__be32 *)bh->b_data);
102 *(__be32 *)bh->b_data = cpu_to_be32(tmp - mask);
103
104 mark_buffer_dirty(bh);
105 sb->s_dirt = 1;
106 bm->bm_free++;
107
108 up(&sbi->s_bmlock);
109 return;
110
111err_free:
112 affs_warning(sb,"affs_free_block","Trying to free block %u which is already free", block);
113 up(&sbi->s_bmlock);
114 return;
115
116err_bh_read:
117 affs_error(sb,"affs_free_block","Cannot read bitmap block %u", bm->bm_key);
118 sbi->s_bmap_bh = NULL;
119 sbi->s_last_bmap = ~0;
120 up(&sbi->s_bmlock);
121 return;
122
123err_range:
124 affs_error(sb, "affs_free_block","Block %u outside partition", block);
125 return;
126}
127
128/*
129 * Allocate a block in the given allocation zone.
130 * Since we have to byte-swap the bitmap on little-endian
131 * machines, this is rather expensive. Therefor we will
132 * preallocate up to 16 blocks from the same word, if
133 * possible. We are not doing preallocations in the
134 * header zone, though.
135 */
136
137u32
138affs_alloc_block(struct inode *inode, u32 goal)
139{
140 struct super_block *sb;
141 struct affs_sb_info *sbi;
142 struct affs_bm_info *bm;
143 struct buffer_head *bh;
144 __be32 *data, *enddata;
145 u32 blk, bmap, bit, mask, mask2, tmp;
146 int i;
147
148 sb = inode->i_sb;
149 sbi = AFFS_SB(sb);
150
151 pr_debug("AFFS: balloc(inode=%lu,goal=%u): ", inode->i_ino, goal);
152
153 if (AFFS_I(inode)->i_pa_cnt) {
154 pr_debug("%d\n", AFFS_I(inode)->i_lastalloc+1);
155 AFFS_I(inode)->i_pa_cnt--;
156 return ++AFFS_I(inode)->i_lastalloc;
157 }
158
159 if (!goal || goal > sbi->s_partition_size) {
160 if (goal)
161 affs_warning(sb, "affs_balloc", "invalid goal %d", goal);
162 //if (!AFFS_I(inode)->i_last_block)
163 // affs_warning(sb, "affs_balloc", "no last alloc block");
164 goal = sbi->s_reserved;
165 }
166
167 blk = goal - sbi->s_reserved;
168 bmap = blk / sbi->s_bmap_bits;
169 bm = &sbi->s_bitmap[bmap];
170
171 down(&sbi->s_bmlock);
172
173 if (bm->bm_free)
174 goto find_bmap_bit;
175
176find_bmap:
177 /* search for the next bmap buffer with free bits */
178 i = sbi->s_bmap_count;
179 do {
180 if (--i < 0)
181 goto err_full;
182 bmap++;
183 bm++;
184 if (bmap < sbi->s_bmap_count)
185 continue;
186 /* restart search at zero */
187 bmap = 0;
188 bm = sbi->s_bitmap;
189 } while (!bm->bm_free);
190 blk = bmap * sbi->s_bmap_bits;
191
192find_bmap_bit:
193
194 bh = sbi->s_bmap_bh;
195 if (sbi->s_last_bmap != bmap) {
196 affs_brelse(bh);
197 bh = affs_bread(sb, bm->bm_key);
198 if (!bh)
199 goto err_bh_read;
200 sbi->s_bmap_bh = bh;
201 sbi->s_last_bmap = bmap;
202 }
203
204 /* find an unused block in this bitmap block */
205 bit = blk % sbi->s_bmap_bits;
206 data = (__be32 *)bh->b_data + bit / 32 + 1;
207 enddata = (__be32 *)((u8 *)bh->b_data + sb->s_blocksize);
208 mask = ~0UL << (bit & 31);
209 blk &= ~31UL;
210
211 tmp = be32_to_cpu(*data);
212 if (tmp & mask)
213 goto find_bit;
214
215 /* scan the rest of the buffer */
216 do {
217 blk += 32;
218 if (++data >= enddata)
219 /* didn't find something, can only happen
220 * if scan didn't start at 0, try next bmap
221 */
222 goto find_bmap;
223 } while (!*data);
224 tmp = be32_to_cpu(*data);
225 mask = ~0;
226
227find_bit:
228 /* finally look for a free bit in the word */
229 bit = ffs(tmp & mask) - 1;
230 blk += bit + sbi->s_reserved;
231 mask2 = mask = 1 << (bit & 31);
232 AFFS_I(inode)->i_lastalloc = blk;
233
234 /* prealloc as much as possible within this word */
235 while ((mask2 <<= 1)) {
236 if (!(tmp & mask2))
237 break;
238 AFFS_I(inode)->i_pa_cnt++;
239 mask |= mask2;
240 }
241 bm->bm_free -= AFFS_I(inode)->i_pa_cnt + 1;
242
243 *data = cpu_to_be32(tmp & ~mask);
244
245 /* fix checksum */
246 tmp = be32_to_cpu(*(__be32 *)bh->b_data);
247 *(__be32 *)bh->b_data = cpu_to_be32(tmp + mask);
248
249 mark_buffer_dirty(bh);
250 sb->s_dirt = 1;
251
252 up(&sbi->s_bmlock);
253
254 pr_debug("%d\n", blk);
255 return blk;
256
257err_bh_read:
258 affs_error(sb,"affs_read_block","Cannot read bitmap block %u", bm->bm_key);
259 sbi->s_bmap_bh = NULL;
260 sbi->s_last_bmap = ~0;
261err_full:
262 up(&sbi->s_bmlock);
263 pr_debug("failed\n");
264 return 0;
265}
266
267int affs_init_bitmap(struct super_block *sb, int *flags)
268{
269 struct affs_bm_info *bm;
270 struct buffer_head *bmap_bh = NULL, *bh = NULL;
271 __be32 *bmap_blk;
272 u32 size, blk, end, offset, mask;
273 int i, res = 0;
274 struct affs_sb_info *sbi = AFFS_SB(sb);
275
276 if (*flags & MS_RDONLY)
277 return 0;
278
279 if (!AFFS_ROOT_TAIL(sb, sbi->s_root_bh)->bm_flag) {
280 printk(KERN_NOTICE "AFFS: Bitmap invalid - mounting %s read only\n",
281 sb->s_id);
282 *flags |= MS_RDONLY;
283 return 0;
284 }
285
286 sbi->s_last_bmap = ~0;
287 sbi->s_bmap_bh = NULL;
288 sbi->s_bmap_bits = sb->s_blocksize * 8 - 32;
289 sbi->s_bmap_count = (sbi->s_partition_size - sbi->s_reserved +
290 sbi->s_bmap_bits - 1) / sbi->s_bmap_bits;
291 size = sbi->s_bmap_count * sizeof(*bm);
292 bm = sbi->s_bitmap = kmalloc(size, GFP_KERNEL);
293 if (!sbi->s_bitmap) {
294 printk(KERN_ERR "AFFS: Bitmap allocation failed\n");
295 return -ENOMEM;
296 }
297 memset(sbi->s_bitmap, 0, size);
298
299 bmap_blk = (__be32 *)sbi->s_root_bh->b_data;
300 blk = sb->s_blocksize / 4 - 49;
301 end = blk + 25;
302
303 for (i = sbi->s_bmap_count; i > 0; bm++, i--) {
304 affs_brelse(bh);
305
306 bm->bm_key = be32_to_cpu(bmap_blk[blk]);
307 bh = affs_bread(sb, bm->bm_key);
308 if (!bh) {
309 printk(KERN_ERR "AFFS: Cannot read bitmap\n");
310 res = -EIO;
311 goto out;
312 }
313 if (affs_checksum_block(sb, bh)) {
314 printk(KERN_WARNING "AFFS: Bitmap %u invalid - mounting %s read only.\n",
315 bm->bm_key, sb->s_id);
316 *flags |= MS_RDONLY;
317 goto out;
318 }
319 pr_debug("AFFS: read bitmap block %d: %d\n", blk, bm->bm_key);
320 bm->bm_free = affs_count_free_bits(sb->s_blocksize - 4, bh->b_data + 4);
321
322 /* Don't try read the extension if this is the last block,
323 * but we also need the right bm pointer below
324 */
325 if (++blk < end || i == 1)
326 continue;
327 if (bmap_bh)
328 affs_brelse(bmap_bh);
329 bmap_bh = affs_bread(sb, be32_to_cpu(bmap_blk[blk]));
330 if (!bmap_bh) {
331 printk(KERN_ERR "AFFS: Cannot read bitmap extension\n");
332 res = -EIO;
333 goto out;
334 }
335 bmap_blk = (__be32 *)bmap_bh->b_data;
336 blk = 0;
337 end = sb->s_blocksize / 4 - 1;
338 }
339
340 offset = (sbi->s_partition_size - sbi->s_reserved) % sbi->s_bmap_bits;
341 mask = ~(0xFFFFFFFFU << (offset & 31));
342 pr_debug("last word: %d %d %d\n", offset, offset / 32 + 1, mask);
343 offset = offset / 32 + 1;
344
345 if (mask) {
346 u32 old, new;
347
348 /* Mark unused bits in the last word as allocated */
349 old = be32_to_cpu(((__be32 *)bh->b_data)[offset]);
350 new = old & mask;
351 //if (old != new) {
352 ((__be32 *)bh->b_data)[offset] = cpu_to_be32(new);
353 /* fix checksum */
354 //new -= old;
355 //old = be32_to_cpu(*(__be32 *)bh->b_data);
356 //*(__be32 *)bh->b_data = cpu_to_be32(old - new);
357 //mark_buffer_dirty(bh);
358 //}
359 /* correct offset for the bitmap count below */
360 //offset++;
361 }
362 while (++offset < sb->s_blocksize / 4)
363 ((__be32 *)bh->b_data)[offset] = 0;
364 ((__be32 *)bh->b_data)[0] = 0;
365 ((__be32 *)bh->b_data)[0] = cpu_to_be32(-affs_checksum_block(sb, bh));
366 mark_buffer_dirty(bh);
367
368 /* recalculate bitmap count for last block */
369 bm--;
370 bm->bm_free = affs_count_free_bits(sb->s_blocksize - 4, bh->b_data + 4);
371
372out:
373 affs_brelse(bh);
374 affs_brelse(bmap_bh);
375 return res;
376}
377
378void affs_free_bitmap(struct super_block *sb)
379{
380 struct affs_sb_info *sbi = AFFS_SB(sb);
381
382 if (!sbi->s_bitmap)
383 return;
384
385 affs_brelse(sbi->s_bmap_bh);
386 sbi->s_bmap_bh = NULL;
387 sbi->s_last_bmap = ~0;
388 kfree(sbi->s_bitmap);
389 sbi->s_bitmap = NULL;
390}
diff --git a/fs/affs/dir.c b/fs/affs/dir.c
new file mode 100644
index 000000000000..548efd0ee98c
--- /dev/null
+++ b/fs/affs/dir.c
@@ -0,0 +1,155 @@
1/*
2 * linux/fs/affs/dir.c
3 *
4 * (c) 1996 Hans-Joachim Widmaier - Rewritten
5 *
6 * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem.
7 *
8 * (C) 1992 Eric Youngdale Modified for ISO 9660 filesystem.
9 *
10 * (C) 1991 Linus Torvalds - minix filesystem
11 *
12 * affs directory handling functions
13 *
14 */
15
16#include "affs.h"
17
18static int affs_readdir(struct file *, void *, filldir_t);
19
20struct file_operations affs_dir_operations = {
21 .read = generic_read_dir,
22 .readdir = affs_readdir,
23 .fsync = file_fsync,
24};
25
26/*
27 * directories can handle most operations...
28 */
29struct inode_operations affs_dir_inode_operations = {
30 .create = affs_create,
31 .lookup = affs_lookup,
32 .link = affs_link,
33 .unlink = affs_unlink,
34 .symlink = affs_symlink,
35 .mkdir = affs_mkdir,
36 .rmdir = affs_rmdir,
37 .rename = affs_rename,
38 .setattr = affs_notify_change,
39};
40
41static int
42affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
43{
44 struct inode *inode = filp->f_dentry->d_inode;
45 struct super_block *sb = inode->i_sb;
46 struct buffer_head *dir_bh;
47 struct buffer_head *fh_bh;
48 unsigned char *name;
49 int namelen;
50 u32 i;
51 int hash_pos;
52 int chain_pos;
53 u32 f_pos;
54 u32 ino;
55 int stored;
56 int res;
57
58 pr_debug("AFFS: readdir(ino=%lu,f_pos=%lx)\n",inode->i_ino,(unsigned long)filp->f_pos);
59
60 stored = 0;
61 res = -EIO;
62 dir_bh = NULL;
63 fh_bh = NULL;
64 f_pos = filp->f_pos;
65
66 if (f_pos == 0) {
67 filp->private_data = (void *)0;
68 if (filldir(dirent, ".", 1, f_pos, inode->i_ino, DT_DIR) < 0)
69 return 0;
70 filp->f_pos = f_pos = 1;
71 stored++;
72 }
73 if (f_pos == 1) {
74 if (filldir(dirent, "..", 2, f_pos, parent_ino(filp->f_dentry), DT_DIR) < 0)
75 return stored;
76 filp->f_pos = f_pos = 2;
77 stored++;
78 }
79
80 affs_lock_dir(inode);
81 chain_pos = (f_pos - 2) & 0xffff;
82 hash_pos = (f_pos - 2) >> 16;
83 if (chain_pos == 0xffff) {
84 affs_warning(sb, "readdir", "More than 65535 entries in chain");
85 chain_pos = 0;
86 hash_pos++;
87 filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
88 }
89 dir_bh = affs_bread(sb, inode->i_ino);
90 if (!dir_bh)
91 goto readdir_out;
92
93 /* If the directory hasn't changed since the last call to readdir(),
94 * we can jump directly to where we left off.
95 */
96 ino = (u32)(long)filp->private_data;
97 if (ino && filp->f_version == inode->i_version) {
98 pr_debug("AFFS: readdir() left off=%d\n", ino);
99 goto inside;
100 }
101
102 ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]);
103 for (i = 0; ino && i < chain_pos; i++) {
104 fh_bh = affs_bread(sb, ino);
105 if (!fh_bh) {
106 affs_error(sb, "readdir","Cannot read block %d", i);
107 goto readdir_out;
108 }
109 ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain);
110 affs_brelse(fh_bh);
111 fh_bh = NULL;
112 }
113 if (ino)
114 goto inside;
115 hash_pos++;
116
117 for (; hash_pos < AFFS_SB(sb)->s_hashsize; hash_pos++) {
118 ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]);
119 if (!ino)
120 continue;
121 f_pos = (hash_pos << 16) + 2;
122inside:
123 do {
124 fh_bh = affs_bread(sb, ino);
125 if (!fh_bh) {
126 affs_error(sb, "readdir","Cannot read block %d", ino);
127 goto readdir_done;
128 }
129
130 namelen = min(AFFS_TAIL(sb, fh_bh)->name[0], (u8)30);
131 name = AFFS_TAIL(sb, fh_bh)->name + 1;
132 pr_debug("AFFS: readdir(): filldir(\"%.*s\", ino=%u), hash=%d, f_pos=%x\n",
133 namelen, name, ino, hash_pos, f_pos);
134 if (filldir(dirent, name, namelen, f_pos, ino, DT_UNKNOWN) < 0)
135 goto readdir_done;
136 stored++;
137 f_pos++;
138 ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain);
139 affs_brelse(fh_bh);
140 fh_bh = NULL;
141 } while (ino);
142 }
143readdir_done:
144 filp->f_pos = f_pos;
145 filp->f_version = inode->i_version;
146 filp->private_data = (void *)(long)ino;
147 res = stored;
148
149readdir_out:
150 affs_brelse(dir_bh);
151 affs_brelse(fh_bh);
152 affs_unlock_dir(inode);
153 pr_debug("AFFS: readdir()=%d\n", stored);
154 return res;
155}
diff --git a/fs/affs/file.c b/fs/affs/file.c
new file mode 100644
index 000000000000..6744924b6905
--- /dev/null
+++ b/fs/affs/file.c
@@ -0,0 +1,920 @@
1/*
2 * linux/fs/affs/file.c
3 *
4 * (c) 1996 Hans-Joachim Widmaier - Rewritten
5 *
6 * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem.
7 *
8 * (C) 1992 Eric Youngdale Modified for ISO 9660 filesystem.
9 *
10 * (C) 1991 Linus Torvalds - minix filesystem
11 *
12 * affs regular file handling primitives
13 */
14
15#include "affs.h"
16
17#if PAGE_SIZE < 4096
18#error PAGE_SIZE must be at least 4096
19#endif
20
21static int affs_grow_extcache(struct inode *inode, u32 lc_idx);
22static struct buffer_head *affs_alloc_extblock(struct inode *inode, struct buffer_head *bh, u32 ext);
23static inline struct buffer_head *affs_get_extblock(struct inode *inode, u32 ext);
24static struct buffer_head *affs_get_extblock_slow(struct inode *inode, u32 ext);
25static ssize_t affs_file_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos);
26static int affs_file_open(struct inode *inode, struct file *filp);
27static int affs_file_release(struct inode *inode, struct file *filp);
28
29struct file_operations affs_file_operations = {
30 .llseek = generic_file_llseek,
31 .read = generic_file_read,
32 .write = affs_file_write,
33 .mmap = generic_file_mmap,
34 .open = affs_file_open,
35 .release = affs_file_release,
36 .fsync = file_fsync,
37 .sendfile = generic_file_sendfile,
38};
39
40struct inode_operations affs_file_inode_operations = {
41 .truncate = affs_truncate,
42 .setattr = affs_notify_change,
43};
44
45static int
46affs_file_open(struct inode *inode, struct file *filp)
47{
48 if (atomic_read(&filp->f_count) != 1)
49 return 0;
50 pr_debug("AFFS: open(%d)\n", AFFS_I(inode)->i_opencnt);
51 AFFS_I(inode)->i_opencnt++;
52 return 0;
53}
54
55static int
56affs_file_release(struct inode *inode, struct file *filp)
57{
58 if (atomic_read(&filp->f_count) != 0)
59 return 0;
60 pr_debug("AFFS: release(%d)\n", AFFS_I(inode)->i_opencnt);
61 AFFS_I(inode)->i_opencnt--;
62 if (!AFFS_I(inode)->i_opencnt)
63 affs_free_prealloc(inode);
64
65 return 0;
66}
67
68static int
69affs_grow_extcache(struct inode *inode, u32 lc_idx)
70{
71 struct super_block *sb = inode->i_sb;
72 struct buffer_head *bh;
73 u32 lc_max;
74 int i, j, key;
75
76 if (!AFFS_I(inode)->i_lc) {
77 char *ptr = (char *)get_zeroed_page(GFP_NOFS);
78 if (!ptr)
79 return -ENOMEM;
80 AFFS_I(inode)->i_lc = (u32 *)ptr;
81 AFFS_I(inode)->i_ac = (struct affs_ext_key *)(ptr + AFFS_CACHE_SIZE / 2);
82 }
83
84 lc_max = AFFS_LC_SIZE << AFFS_I(inode)->i_lc_shift;
85
86 if (AFFS_I(inode)->i_extcnt > lc_max) {
87 u32 lc_shift, lc_mask, tmp, off;
88
89 /* need to recalculate linear cache, start from old size */
90 lc_shift = AFFS_I(inode)->i_lc_shift;
91 tmp = (AFFS_I(inode)->i_extcnt / AFFS_LC_SIZE) >> lc_shift;
92 for (; tmp; tmp >>= 1)
93 lc_shift++;
94 lc_mask = (1 << lc_shift) - 1;
95
96 /* fix idx and old size to new shift */
97 lc_idx >>= (lc_shift - AFFS_I(inode)->i_lc_shift);
98 AFFS_I(inode)->i_lc_size >>= (lc_shift - AFFS_I(inode)->i_lc_shift);
99
100 /* first shrink old cache to make more space */
101 off = 1 << (lc_shift - AFFS_I(inode)->i_lc_shift);
102 for (i = 1, j = off; j < AFFS_LC_SIZE; i++, j += off)
103 AFFS_I(inode)->i_ac[i] = AFFS_I(inode)->i_ac[j];
104
105 AFFS_I(inode)->i_lc_shift = lc_shift;
106 AFFS_I(inode)->i_lc_mask = lc_mask;
107 }
108
109 /* fill cache to the needed index */
110 i = AFFS_I(inode)->i_lc_size;
111 AFFS_I(inode)->i_lc_size = lc_idx + 1;
112 for (; i <= lc_idx; i++) {
113 if (!i) {
114 AFFS_I(inode)->i_lc[0] = inode->i_ino;
115 continue;
116 }
117 key = AFFS_I(inode)->i_lc[i - 1];
118 j = AFFS_I(inode)->i_lc_mask + 1;
119 // unlock cache
120 for (; j > 0; j--) {
121 bh = affs_bread(sb, key);
122 if (!bh)
123 goto err;
124 key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);
125 affs_brelse(bh);
126 }
127 // lock cache
128 AFFS_I(inode)->i_lc[i] = key;
129 }
130
131 return 0;
132
133err:
134 // lock cache
135 return -EIO;
136}
137
138static struct buffer_head *
139affs_alloc_extblock(struct inode *inode, struct buffer_head *bh, u32 ext)
140{
141 struct super_block *sb = inode->i_sb;
142 struct buffer_head *new_bh;
143 u32 blocknr, tmp;
144
145 blocknr = affs_alloc_block(inode, bh->b_blocknr);
146 if (!blocknr)
147 return ERR_PTR(-ENOSPC);
148
149 new_bh = affs_getzeroblk(sb, blocknr);
150 if (!new_bh) {
151 affs_free_block(sb, blocknr);
152 return ERR_PTR(-EIO);
153 }
154
155 AFFS_HEAD(new_bh)->ptype = cpu_to_be32(T_LIST);
156 AFFS_HEAD(new_bh)->key = cpu_to_be32(blocknr);
157 AFFS_TAIL(sb, new_bh)->stype = cpu_to_be32(ST_FILE);
158 AFFS_TAIL(sb, new_bh)->parent = cpu_to_be32(inode->i_ino);
159 affs_fix_checksum(sb, new_bh);
160
161 mark_buffer_dirty_inode(new_bh, inode);
162
163 tmp = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);
164 if (tmp)
165 affs_warning(sb, "alloc_ext", "previous extension set (%x)", tmp);
166 AFFS_TAIL(sb, bh)->extension = cpu_to_be32(blocknr);
167 affs_adjust_checksum(bh, blocknr - tmp);
168 mark_buffer_dirty_inode(bh, inode);
169
170 AFFS_I(inode)->i_extcnt++;
171 mark_inode_dirty(inode);
172
173 return new_bh;
174}
175
176static inline struct buffer_head *
177affs_get_extblock(struct inode *inode, u32 ext)
178{
179 /* inline the simplest case: same extended block as last time */
180 struct buffer_head *bh = AFFS_I(inode)->i_ext_bh;
181 if (ext == AFFS_I(inode)->i_ext_last)
182 atomic_inc(&bh->b_count);
183 else
184 /* we have to do more (not inlined) */
185 bh = affs_get_extblock_slow(inode, ext);
186
187 return bh;
188}
189
190static struct buffer_head *
191affs_get_extblock_slow(struct inode *inode, u32 ext)
192{
193 struct super_block *sb = inode->i_sb;
194 struct buffer_head *bh;
195 u32 ext_key;
196 u32 lc_idx, lc_off, ac_idx;
197 u32 tmp, idx;
198
199 if (ext == AFFS_I(inode)->i_ext_last + 1) {
200 /* read the next extended block from the current one */
201 bh = AFFS_I(inode)->i_ext_bh;
202 ext_key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);
203 if (ext < AFFS_I(inode)->i_extcnt)
204 goto read_ext;
205 if (ext > AFFS_I(inode)->i_extcnt)
206 BUG();
207 bh = affs_alloc_extblock(inode, bh, ext);
208 if (IS_ERR(bh))
209 return bh;
210 goto store_ext;
211 }
212
213 if (ext == 0) {
214 /* we seek back to the file header block */
215 ext_key = inode->i_ino;
216 goto read_ext;
217 }
218
219 if (ext >= AFFS_I(inode)->i_extcnt) {
220 struct buffer_head *prev_bh;
221
222 /* allocate a new extended block */
223 if (ext > AFFS_I(inode)->i_extcnt)
224 BUG();
225
226 /* get previous extended block */
227 prev_bh = affs_get_extblock(inode, ext - 1);
228 if (IS_ERR(prev_bh))
229 return prev_bh;
230 bh = affs_alloc_extblock(inode, prev_bh, ext);
231 affs_brelse(prev_bh);
232 if (IS_ERR(bh))
233 return bh;
234 goto store_ext;
235 }
236
237again:
238 /* check if there is an extended cache and whether it's large enough */
239 lc_idx = ext >> AFFS_I(inode)->i_lc_shift;
240 lc_off = ext & AFFS_I(inode)->i_lc_mask;
241
242 if (lc_idx >= AFFS_I(inode)->i_lc_size) {
243 int err;
244
245 err = affs_grow_extcache(inode, lc_idx);
246 if (err)
247 return ERR_PTR(err);
248 goto again;
249 }
250
251 /* every n'th key we find in the linear cache */
252 if (!lc_off) {
253 ext_key = AFFS_I(inode)->i_lc[lc_idx];
254 goto read_ext;
255 }
256
257 /* maybe it's still in the associative cache */
258 ac_idx = (ext - lc_idx - 1) & AFFS_AC_MASK;
259 if (AFFS_I(inode)->i_ac[ac_idx].ext == ext) {
260 ext_key = AFFS_I(inode)->i_ac[ac_idx].key;
261 goto read_ext;
262 }
263
264 /* try to find one of the previous extended blocks */
265 tmp = ext;
266 idx = ac_idx;
267 while (--tmp, --lc_off > 0) {
268 idx = (idx - 1) & AFFS_AC_MASK;
269 if (AFFS_I(inode)->i_ac[idx].ext == tmp) {
270 ext_key = AFFS_I(inode)->i_ac[idx].key;
271 goto find_ext;
272 }
273 }
274
275 /* fall back to the linear cache */
276 ext_key = AFFS_I(inode)->i_lc[lc_idx];
277find_ext:
278 /* read all extended blocks until we find the one we need */
279 //unlock cache
280 do {
281 bh = affs_bread(sb, ext_key);
282 if (!bh)
283 goto err_bread;
284 ext_key = be32_to_cpu(AFFS_TAIL(sb, bh)->extension);
285 affs_brelse(bh);
286 tmp++;
287 } while (tmp < ext);
288 //lock cache
289
290 /* store it in the associative cache */
291 // recalculate ac_idx?
292 AFFS_I(inode)->i_ac[ac_idx].ext = ext;
293 AFFS_I(inode)->i_ac[ac_idx].key = ext_key;
294
295read_ext:
296 /* finally read the right extended block */
297 //unlock cache
298 bh = affs_bread(sb, ext_key);
299 if (!bh)
300 goto err_bread;
301 //lock cache
302
303store_ext:
304 /* release old cached extended block and store the new one */
305 affs_brelse(AFFS_I(inode)->i_ext_bh);
306 AFFS_I(inode)->i_ext_last = ext;
307 AFFS_I(inode)->i_ext_bh = bh;
308 atomic_inc(&bh->b_count);
309
310 return bh;
311
312err_bread:
313 affs_brelse(bh);
314 return ERR_PTR(-EIO);
315}
316
317static int
318affs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_result, int create)
319{
320 struct super_block *sb = inode->i_sb;
321 struct buffer_head *ext_bh;
322 u32 ext;
323
324 pr_debug("AFFS: get_block(%u, %lu)\n", (u32)inode->i_ino, (unsigned long)block);
325
326
327 if (block > (sector_t)0x7fffffffUL)
328 BUG();
329
330 if (block >= AFFS_I(inode)->i_blkcnt) {
331 if (block > AFFS_I(inode)->i_blkcnt || !create)
332 goto err_big;
333 } else
334 create = 0;
335
336 //lock cache
337 affs_lock_ext(inode);
338
339 ext = (u32)block / AFFS_SB(sb)->s_hashsize;
340 block -= ext * AFFS_SB(sb)->s_hashsize;
341 ext_bh = affs_get_extblock(inode, ext);
342 if (IS_ERR(ext_bh))
343 goto err_ext;
344 map_bh(bh_result, sb, (sector_t)be32_to_cpu(AFFS_BLOCK(sb, ext_bh, block)));
345
346 if (create) {
347 u32 blocknr = affs_alloc_block(inode, ext_bh->b_blocknr);
348 if (!blocknr)
349 goto err_alloc;
350 set_buffer_new(bh_result);
351 AFFS_I(inode)->mmu_private += AFFS_SB(sb)->s_data_blksize;
352 AFFS_I(inode)->i_blkcnt++;
353
354 /* store new block */
355 if (bh_result->b_blocknr)
356 affs_warning(sb, "get_block", "block already set (%x)", bh_result->b_blocknr);
357 AFFS_BLOCK(sb, ext_bh, block) = cpu_to_be32(blocknr);
358 AFFS_HEAD(ext_bh)->block_count = cpu_to_be32(block + 1);
359 affs_adjust_checksum(ext_bh, blocknr - bh_result->b_blocknr + 1);
360 bh_result->b_blocknr = blocknr;
361
362 if (!block) {
363 /* insert first block into header block */
364 u32 tmp = be32_to_cpu(AFFS_HEAD(ext_bh)->first_data);
365 if (tmp)
366 affs_warning(sb, "get_block", "first block already set (%d)", tmp);
367 AFFS_HEAD(ext_bh)->first_data = cpu_to_be32(blocknr);
368 affs_adjust_checksum(ext_bh, blocknr - tmp);
369 }
370 }
371
372 affs_brelse(ext_bh);
373 //unlock cache
374 affs_unlock_ext(inode);
375 return 0;
376
377err_big:
378 affs_error(inode->i_sb,"get_block","strange block request %d", block);
379 return -EIO;
380err_ext:
381 // unlock cache
382 affs_unlock_ext(inode);
383 return PTR_ERR(ext_bh);
384err_alloc:
385 brelse(ext_bh);
386 clear_buffer_mapped(bh_result);
387 bh_result->b_bdev = NULL;
388 // unlock cache
389 affs_unlock_ext(inode);
390 return -ENOSPC;
391}
392
393static int affs_writepage(struct page *page, struct writeback_control *wbc)
394{
395 return block_write_full_page(page, affs_get_block, wbc);
396}
397static int affs_readpage(struct file *file, struct page *page)
398{
399 return block_read_full_page(page, affs_get_block);
400}
401static int affs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
402{
403 return cont_prepare_write(page, from, to, affs_get_block,
404 &AFFS_I(page->mapping->host)->mmu_private);
405}
406static sector_t _affs_bmap(struct address_space *mapping, sector_t block)
407{
408 return generic_block_bmap(mapping,block,affs_get_block);
409}
410struct address_space_operations affs_aops = {
411 .readpage = affs_readpage,
412 .writepage = affs_writepage,
413 .sync_page = block_sync_page,
414 .prepare_write = affs_prepare_write,
415 .commit_write = generic_commit_write,
416 .bmap = _affs_bmap
417};
418
419static inline struct buffer_head *
420affs_bread_ino(struct inode *inode, int block, int create)
421{
422 struct buffer_head *bh, tmp_bh;
423 int err;
424
425 tmp_bh.b_state = 0;
426 err = affs_get_block(inode, block, &tmp_bh, create);
427 if (!err) {
428 bh = affs_bread(inode->i_sb, tmp_bh.b_blocknr);
429 if (bh) {
430 bh->b_state |= tmp_bh.b_state;
431 return bh;
432 }
433 err = -EIO;
434 }
435 return ERR_PTR(err);
436}
437
438static inline struct buffer_head *
439affs_getzeroblk_ino(struct inode *inode, int block)
440{
441 struct buffer_head *bh, tmp_bh;
442 int err;
443
444 tmp_bh.b_state = 0;
445 err = affs_get_block(inode, block, &tmp_bh, 1);
446 if (!err) {
447 bh = affs_getzeroblk(inode->i_sb, tmp_bh.b_blocknr);
448 if (bh) {
449 bh->b_state |= tmp_bh.b_state;
450 return bh;
451 }
452 err = -EIO;
453 }
454 return ERR_PTR(err);
455}
456
457static inline struct buffer_head *
458affs_getemptyblk_ino(struct inode *inode, int block)
459{
460 struct buffer_head *bh, tmp_bh;
461 int err;
462
463 tmp_bh.b_state = 0;
464 err = affs_get_block(inode, block, &tmp_bh, 1);
465 if (!err) {
466 bh = affs_getemptyblk(inode->i_sb, tmp_bh.b_blocknr);
467 if (bh) {
468 bh->b_state |= tmp_bh.b_state;
469 return bh;
470 }
471 err = -EIO;
472 }
473 return ERR_PTR(err);
474}
475
476static ssize_t
477affs_file_write(struct file *file, const char __user *buf,
478 size_t count, loff_t *ppos)
479{
480 ssize_t retval;
481
482 retval = generic_file_write (file, buf, count, ppos);
483 if (retval >0) {
484 struct inode *inode = file->f_dentry->d_inode;
485 inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
486 mark_inode_dirty(inode);
487 }
488 return retval;
489}
490
491static int
492affs_do_readpage_ofs(struct file *file, struct page *page, unsigned from, unsigned to)
493{
494 struct inode *inode = page->mapping->host;
495 struct super_block *sb = inode->i_sb;
496 struct buffer_head *bh;
497 char *data;
498 u32 bidx, boff, bsize;
499 u32 tmp;
500
501 pr_debug("AFFS: read_page(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to);
502 if (from > to || to > PAGE_CACHE_SIZE)
503 BUG();
504 kmap(page);
505 data = page_address(page);
506 bsize = AFFS_SB(sb)->s_data_blksize;
507 tmp = (page->index << PAGE_CACHE_SHIFT) + from;
508 bidx = tmp / bsize;
509 boff = tmp % bsize;
510
511 while (from < to) {
512 bh = affs_bread_ino(inode, bidx, 0);
513 if (IS_ERR(bh))
514 return PTR_ERR(bh);
515 tmp = min(bsize - boff, to - from);
516 if (from + tmp > to || tmp > bsize)
517 BUG();
518 memcpy(data + from, AFFS_DATA(bh) + boff, tmp);
519 affs_brelse(bh);
520 bidx++;
521 from += tmp;
522 boff = 0;
523 }
524 flush_dcache_page(page);
525 kunmap(page);
526 return 0;
527}
528
529static int
530affs_extent_file_ofs(struct inode *inode, u32 newsize)
531{
532 struct super_block *sb = inode->i_sb;
533 struct buffer_head *bh, *prev_bh;
534 u32 bidx, boff;
535 u32 size, bsize;
536 u32 tmp;
537
538 pr_debug("AFFS: extent_file(%u, %d)\n", (u32)inode->i_ino, newsize);
539 bsize = AFFS_SB(sb)->s_data_blksize;
540 bh = NULL;
541 size = AFFS_I(inode)->mmu_private;
542 bidx = size / bsize;
543 boff = size % bsize;
544 if (boff) {
545 bh = affs_bread_ino(inode, bidx, 0);
546 if (IS_ERR(bh))
547 return PTR_ERR(bh);
548 tmp = min(bsize - boff, newsize - size);
549 if (boff + tmp > bsize || tmp > bsize)
550 BUG();
551 memset(AFFS_DATA(bh) + boff, 0, tmp);
552 AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp);
553 affs_fix_checksum(sb, bh);
554 mark_buffer_dirty_inode(bh, inode);
555 size += tmp;
556 bidx++;
557 } else if (bidx) {
558 bh = affs_bread_ino(inode, bidx - 1, 0);
559 if (IS_ERR(bh))
560 return PTR_ERR(bh);
561 }
562
563 while (size < newsize) {
564 prev_bh = bh;
565 bh = affs_getzeroblk_ino(inode, bidx);
566 if (IS_ERR(bh))
567 goto out;
568 tmp = min(bsize, newsize - size);
569 if (tmp > bsize)
570 BUG();
571 AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
572 AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino);
573 AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
574 AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);
575 affs_fix_checksum(sb, bh);
576 bh->b_state &= ~(1UL << BH_New);
577 mark_buffer_dirty_inode(bh, inode);
578 if (prev_bh) {
579 u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
580 if (tmp)
581 affs_warning(sb, "extent_file_ofs", "next block already set for %d (%d)", bidx, tmp);
582 AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
583 affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp);
584 mark_buffer_dirty_inode(prev_bh, inode);
585 affs_brelse(prev_bh);
586 }
587 size += bsize;
588 bidx++;
589 }
590 affs_brelse(bh);
591 inode->i_size = AFFS_I(inode)->mmu_private = newsize;
592 return 0;
593
594out:
595 inode->i_size = AFFS_I(inode)->mmu_private = newsize;
596 return PTR_ERR(bh);
597}
598
599static int
600affs_readpage_ofs(struct file *file, struct page *page)
601{
602 struct inode *inode = page->mapping->host;
603 u32 to;
604 int err;
605
606 pr_debug("AFFS: read_page(%u, %ld)\n", (u32)inode->i_ino, page->index);
607 to = PAGE_CACHE_SIZE;
608 if (((page->index + 1) << PAGE_CACHE_SHIFT) > inode->i_size) {
609 to = inode->i_size & ~PAGE_CACHE_MASK;
610 memset(page_address(page) + to, 0, PAGE_CACHE_SIZE - to);
611 }
612
613 err = affs_do_readpage_ofs(file, page, 0, to);
614 if (!err)
615 SetPageUptodate(page);
616 unlock_page(page);
617 return err;
618}
619
620static int affs_prepare_write_ofs(struct file *file, struct page *page, unsigned from, unsigned to)
621{
622 struct inode *inode = page->mapping->host;
623 u32 size, offset;
624 u32 tmp;
625 int err = 0;
626
627 pr_debug("AFFS: prepare_write(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to);
628 offset = page->index << PAGE_CACHE_SHIFT;
629 if (offset + from > AFFS_I(inode)->mmu_private) {
630 err = affs_extent_file_ofs(inode, offset + from);
631 if (err)
632 return err;
633 }
634 size = inode->i_size;
635
636 if (PageUptodate(page))
637 return 0;
638
639 if (from) {
640 err = affs_do_readpage_ofs(file, page, 0, from);
641 if (err)
642 return err;
643 }
644 if (to < PAGE_CACHE_SIZE) {
645 char *kaddr = kmap_atomic(page, KM_USER0);
646
647 memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
648 flush_dcache_page(page);
649 kunmap_atomic(kaddr, KM_USER0);
650 if (size > offset + to) {
651 if (size < offset + PAGE_CACHE_SIZE)
652 tmp = size & ~PAGE_CACHE_MASK;
653 else
654 tmp = PAGE_CACHE_SIZE;
655 err = affs_do_readpage_ofs(file, page, to, tmp);
656 }
657 }
658 return err;
659}
660
661static int affs_commit_write_ofs(struct file *file, struct page *page, unsigned from, unsigned to)
662{
663 struct inode *inode = page->mapping->host;
664 struct super_block *sb = inode->i_sb;
665 struct buffer_head *bh, *prev_bh;
666 char *data;
667 u32 bidx, boff, bsize;
668 u32 tmp;
669 int written;
670
671 pr_debug("AFFS: commit_write(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to);
672 bsize = AFFS_SB(sb)->s_data_blksize;
673 data = page_address(page);
674
675 bh = NULL;
676 written = 0;
677 tmp = (page->index << PAGE_CACHE_SHIFT) + from;
678 bidx = tmp / bsize;
679 boff = tmp % bsize;
680 if (boff) {
681 bh = affs_bread_ino(inode, bidx, 0);
682 if (IS_ERR(bh))
683 return PTR_ERR(bh);
684 tmp = min(bsize - boff, to - from);
685 if (boff + tmp > bsize || tmp > bsize)
686 BUG();
687 memcpy(AFFS_DATA(bh) + boff, data + from, tmp);
688 AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp);
689 affs_fix_checksum(sb, bh);
690 mark_buffer_dirty_inode(bh, inode);
691 written += tmp;
692 from += tmp;
693 bidx++;
694 } else if (bidx) {
695 bh = affs_bread_ino(inode, bidx - 1, 0);
696 if (IS_ERR(bh))
697 return PTR_ERR(bh);
698 }
699 while (from + bsize <= to) {
700 prev_bh = bh;
701 bh = affs_getemptyblk_ino(inode, bidx);
702 if (IS_ERR(bh))
703 goto out;
704 memcpy(AFFS_DATA(bh), data + from, bsize);
705 if (buffer_new(bh)) {
706 AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
707 AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino);
708 AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
709 AFFS_DATA_HEAD(bh)->size = cpu_to_be32(bsize);
710 AFFS_DATA_HEAD(bh)->next = 0;
711 bh->b_state &= ~(1UL << BH_New);
712 if (prev_bh) {
713 u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
714 if (tmp)
715 affs_warning(sb, "commit_write_ofs", "next block already set for %d (%d)", bidx, tmp);
716 AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
717 affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp);
718 mark_buffer_dirty_inode(prev_bh, inode);
719 }
720 }
721 affs_brelse(prev_bh);
722 affs_fix_checksum(sb, bh);
723 mark_buffer_dirty_inode(bh, inode);
724 written += bsize;
725 from += bsize;
726 bidx++;
727 }
728 if (from < to) {
729 prev_bh = bh;
730 bh = affs_bread_ino(inode, bidx, 1);
731 if (IS_ERR(bh))
732 goto out;
733 tmp = min(bsize, to - from);
734 if (tmp > bsize)
735 BUG();
736 memcpy(AFFS_DATA(bh), data + from, tmp);
737 if (buffer_new(bh)) {
738 AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
739 AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino);
740 AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
741 AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);
742 AFFS_DATA_HEAD(bh)->next = 0;
743 bh->b_state &= ~(1UL << BH_New);
744 if (prev_bh) {
745 u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
746 if (tmp)
747 affs_warning(sb, "commit_write_ofs", "next block already set for %d (%d)", bidx, tmp);
748 AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
749 affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp);
750 mark_buffer_dirty_inode(prev_bh, inode);
751 }
752 } else if (be32_to_cpu(AFFS_DATA_HEAD(bh)->size) < tmp)
753 AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);
754 affs_brelse(prev_bh);
755 affs_fix_checksum(sb, bh);
756 mark_buffer_dirty_inode(bh, inode);
757 written += tmp;
758 from += tmp;
759 bidx++;
760 }
761 SetPageUptodate(page);
762
763done:
764 affs_brelse(bh);
765 tmp = (page->index << PAGE_CACHE_SHIFT) + from;
766 if (tmp > inode->i_size)
767 inode->i_size = AFFS_I(inode)->mmu_private = tmp;
768
769 return written;
770
771out:
772 bh = prev_bh;
773 if (!written)
774 written = PTR_ERR(bh);
775 goto done;
776}
777
778struct address_space_operations affs_aops_ofs = {
779 .readpage = affs_readpage_ofs,
780 //.writepage = affs_writepage_ofs,
781 //.sync_page = affs_sync_page_ofs,
782 .prepare_write = affs_prepare_write_ofs,
783 .commit_write = affs_commit_write_ofs
784};
785
786/* Free any preallocated blocks. */
787
788void
789affs_free_prealloc(struct inode *inode)
790{
791 struct super_block *sb = inode->i_sb;
792
793 pr_debug("AFFS: free_prealloc(ino=%lu)\n", inode->i_ino);
794
795 while (AFFS_I(inode)->i_pa_cnt) {
796 AFFS_I(inode)->i_pa_cnt--;
797 affs_free_block(sb, ++AFFS_I(inode)->i_lastalloc);
798 }
799}
800
801/* Truncate (or enlarge) a file to the requested size. */
802
803void
804affs_truncate(struct inode *inode)
805{
806 struct super_block *sb = inode->i_sb;
807 u32 ext, ext_key;
808 u32 last_blk, blkcnt, blk;
809 u32 size;
810 struct buffer_head *ext_bh;
811 int i;
812
813 pr_debug("AFFS: truncate(inode=%d, oldsize=%u, newsize=%u)\n",
814 (u32)inode->i_ino, (u32)AFFS_I(inode)->mmu_private, (u32)inode->i_size);
815
816 last_blk = 0;
817 ext = 0;
818 if (inode->i_size) {
819 last_blk = ((u32)inode->i_size - 1) / AFFS_SB(sb)->s_data_blksize;
820 ext = last_blk / AFFS_SB(sb)->s_hashsize;
821 }
822
823 if (inode->i_size > AFFS_I(inode)->mmu_private) {
824 struct address_space *mapping = inode->i_mapping;
825 struct page *page;
826 u32 size = inode->i_size - 1;
827 int res;
828
829 page = grab_cache_page(mapping, size >> PAGE_CACHE_SHIFT);
830 if (!page)
831 return;
832 size = (size & (PAGE_CACHE_SIZE - 1)) + 1;
833 res = mapping->a_ops->prepare_write(NULL, page, size, size);
834 if (!res)
835 res = mapping->a_ops->commit_write(NULL, page, size, size);
836 unlock_page(page);
837 page_cache_release(page);
838 mark_inode_dirty(inode);
839 return;
840 } else if (inode->i_size == AFFS_I(inode)->mmu_private)
841 return;
842
843 // lock cache
844 ext_bh = affs_get_extblock(inode, ext);
845 if (IS_ERR(ext_bh)) {
846 affs_warning(sb, "truncate", "unexpected read error for ext block %u (%d)",
847 ext, PTR_ERR(ext_bh));
848 return;
849 }
850 if (AFFS_I(inode)->i_lc) {
851 /* clear linear cache */
852 i = (ext + 1) >> AFFS_I(inode)->i_lc_shift;
853 if (AFFS_I(inode)->i_lc_size > i) {
854 AFFS_I(inode)->i_lc_size = i;
855 for (; i < AFFS_LC_SIZE; i++)
856 AFFS_I(inode)->i_lc[i] = 0;
857 }
858 /* clear associative cache */
859 for (i = 0; i < AFFS_AC_SIZE; i++)
860 if (AFFS_I(inode)->i_ac[i].ext >= ext)
861 AFFS_I(inode)->i_ac[i].ext = 0;
862 }
863 ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension);
864
865 blkcnt = AFFS_I(inode)->i_blkcnt;
866 i = 0;
867 blk = last_blk;
868 if (inode->i_size) {
869 i = last_blk % AFFS_SB(sb)->s_hashsize + 1;
870 blk++;
871 } else
872 AFFS_HEAD(ext_bh)->first_data = 0;
873 size = AFFS_SB(sb)->s_hashsize;
874 if (size > blkcnt - blk + i)
875 size = blkcnt - blk + i;
876 for (; i < size; i++, blk++) {
877 affs_free_block(sb, be32_to_cpu(AFFS_BLOCK(sb, ext_bh, i)));
878 AFFS_BLOCK(sb, ext_bh, i) = 0;
879 }
880 AFFS_TAIL(sb, ext_bh)->extension = 0;
881 affs_fix_checksum(sb, ext_bh);
882 mark_buffer_dirty_inode(ext_bh, inode);
883 affs_brelse(ext_bh);
884
885 if (inode->i_size) {
886 AFFS_I(inode)->i_blkcnt = last_blk + 1;
887 AFFS_I(inode)->i_extcnt = ext + 1;
888 if (AFFS_SB(sb)->s_flags & SF_OFS) {
889 struct buffer_head *bh = affs_bread_ino(inode, last_blk, 0);
890 u32 tmp;
891 if (IS_ERR(ext_bh)) {
892 affs_warning(sb, "truncate", "unexpected read error for last block %u (%d)",
893 ext, PTR_ERR(ext_bh));
894 return;
895 }
896 tmp = be32_to_cpu(AFFS_DATA_HEAD(bh)->next);
897 AFFS_DATA_HEAD(bh)->next = 0;
898 affs_adjust_checksum(bh, -tmp);
899 affs_brelse(bh);
900 }
901 } else {
902 AFFS_I(inode)->i_blkcnt = 0;
903 AFFS_I(inode)->i_extcnt = 1;
904 }
905 AFFS_I(inode)->mmu_private = inode->i_size;
906 // unlock cache
907
908 while (ext_key) {
909 ext_bh = affs_bread(sb, ext_key);
910 size = AFFS_SB(sb)->s_hashsize;
911 if (size > blkcnt - blk)
912 size = blkcnt - blk;
913 for (i = 0; i < size; i++, blk++)
914 affs_free_block(sb, be32_to_cpu(AFFS_BLOCK(sb, ext_bh, i)));
915 affs_free_block(sb, ext_key);
916 ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension);
917 affs_brelse(ext_bh);
918 }
919 affs_free_prealloc(inode);
920}
diff --git a/fs/affs/inode.c b/fs/affs/inode.c
new file mode 100644
index 000000000000..7aa6f2004536
--- /dev/null
+++ b/fs/affs/inode.c
@@ -0,0 +1,411 @@
1/*
2 * linux/fs/affs/inode.c
3 *
4 * (c) 1996 Hans-Joachim Widmaier - Rewritten
5 *
6 * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem.
7 *
8 * (C) 1992 Eric Youngdale Modified for ISO9660 filesystem.
9 *
10 * (C) 1991 Linus Torvalds - minix filesystem
11 */
12
13#include "affs.h"
14
15extern struct inode_operations affs_symlink_inode_operations;
16extern struct timezone sys_tz;
17
18void
19affs_read_inode(struct inode *inode)
20{
21 struct super_block *sb = inode->i_sb;
22 struct affs_sb_info *sbi = AFFS_SB(sb);
23 struct buffer_head *bh;
24 struct affs_head *head;
25 struct affs_tail *tail;
26 u32 block;
27 u32 size;
28 u32 prot;
29 u16 id;
30
31 pr_debug("AFFS: read_inode(%lu)\n",inode->i_ino);
32
33 block = inode->i_ino;
34 bh = affs_bread(sb, block);
35 if (!bh) {
36 affs_warning(sb, "read_inode", "Cannot read block %d", block);
37 goto bad_inode;
38 }
39 if (affs_checksum_block(sb, bh) || be32_to_cpu(AFFS_HEAD(bh)->ptype) != T_SHORT) {
40 affs_warning(sb,"read_inode",
41 "Checksum or type (ptype=%d) error on inode %d",
42 AFFS_HEAD(bh)->ptype, block);
43 goto bad_inode;
44 }
45
46 head = AFFS_HEAD(bh);
47 tail = AFFS_TAIL(sb, bh);
48 prot = be32_to_cpu(tail->protect);
49
50 inode->i_size = 0;
51 inode->i_nlink = 1;
52 inode->i_mode = 0;
53 AFFS_I(inode)->i_extcnt = 1;
54 AFFS_I(inode)->i_ext_last = ~1;
55 AFFS_I(inode)->i_protect = prot;
56 AFFS_I(inode)->i_opencnt = 0;
57 AFFS_I(inode)->i_blkcnt = 0;
58 AFFS_I(inode)->i_lc = NULL;
59 AFFS_I(inode)->i_lc_size = 0;
60 AFFS_I(inode)->i_lc_shift = 0;
61 AFFS_I(inode)->i_lc_mask = 0;
62 AFFS_I(inode)->i_ac = NULL;
63 AFFS_I(inode)->i_ext_bh = NULL;
64 AFFS_I(inode)->mmu_private = 0;
65 AFFS_I(inode)->i_lastalloc = 0;
66 AFFS_I(inode)->i_pa_cnt = 0;
67
68 if (sbi->s_flags & SF_SETMODE)
69 inode->i_mode = sbi->s_mode;
70 else
71 inode->i_mode = prot_to_mode(prot);
72
73 id = be16_to_cpu(tail->uid);
74 if (id == 0 || sbi->s_flags & SF_SETUID)
75 inode->i_uid = sbi->s_uid;
76 else if (id == 0xFFFF && sbi->s_flags & SF_MUFS)
77 inode->i_uid = 0;
78 else
79 inode->i_uid = id;
80
81 id = be16_to_cpu(tail->gid);
82 if (id == 0 || sbi->s_flags & SF_SETGID)
83 inode->i_gid = sbi->s_gid;
84 else if (id == 0xFFFF && sbi->s_flags & SF_MUFS)
85 inode->i_gid = 0;
86 else
87 inode->i_gid = id;
88
89 switch (be32_to_cpu(tail->stype)) {
90 case ST_ROOT:
91 inode->i_uid = sbi->s_uid;
92 inode->i_gid = sbi->s_gid;
93 /* fall through */
94 case ST_USERDIR:
95 if (be32_to_cpu(tail->stype) == ST_USERDIR ||
96 sbi->s_flags & SF_SETMODE) {
97 if (inode->i_mode & S_IRUSR)
98 inode->i_mode |= S_IXUSR;
99 if (inode->i_mode & S_IRGRP)
100 inode->i_mode |= S_IXGRP;
101 if (inode->i_mode & S_IROTH)
102 inode->i_mode |= S_IXOTH;
103 inode->i_mode |= S_IFDIR;
104 } else
105 inode->i_mode = S_IRUGO | S_IXUGO | S_IWUSR | S_IFDIR;
106 if (tail->link_chain)
107 inode->i_nlink = 2;
108 /* Maybe it should be controlled by mount parameter? */
109 //inode->i_mode |= S_ISVTX;
110 inode->i_op = &affs_dir_inode_operations;
111 inode->i_fop = &affs_dir_operations;
112 break;
113 case ST_LINKDIR:
114#if 0
115 affs_warning(sb, "read_inode", "inode is LINKDIR");
116 goto bad_inode;
117#else
118 inode->i_mode |= S_IFDIR;
119 inode->i_op = NULL;
120 inode->i_fop = NULL;
121 break;
122#endif
123 case ST_LINKFILE:
124 affs_warning(sb, "read_inode", "inode is LINKFILE");
125 goto bad_inode;
126 case ST_FILE:
127 size = be32_to_cpu(tail->size);
128 inode->i_mode |= S_IFREG;
129 AFFS_I(inode)->mmu_private = inode->i_size = size;
130 if (inode->i_size) {
131 AFFS_I(inode)->i_blkcnt = (size - 1) /
132 sbi->s_data_blksize + 1;
133 AFFS_I(inode)->i_extcnt = (AFFS_I(inode)->i_blkcnt - 1) /
134 sbi->s_hashsize + 1;
135 }
136 if (tail->link_chain)
137 inode->i_nlink = 2;
138 inode->i_mapping->a_ops = (sbi->s_flags & SF_OFS) ? &affs_aops_ofs : &affs_aops;
139 inode->i_op = &affs_file_inode_operations;
140 inode->i_fop = &affs_file_operations;
141 break;
142 case ST_SOFTLINK:
143 inode->i_mode |= S_IFLNK;
144 inode->i_op = &affs_symlink_inode_operations;
145 inode->i_data.a_ops = &affs_symlink_aops;
146 break;
147 }
148
149 inode->i_mtime.tv_sec = inode->i_atime.tv_sec = inode->i_ctime.tv_sec
150 = (be32_to_cpu(tail->change.days) * (24 * 60 * 60) +
151 be32_to_cpu(tail->change.mins) * 60 +
152 be32_to_cpu(tail->change.ticks) / 50 +
153 ((8 * 365 + 2) * 24 * 60 * 60)) +
154 sys_tz.tz_minuteswest * 60;
155 inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_atime.tv_nsec = 0;
156 affs_brelse(bh);
157 return;
158
159bad_inode:
160 make_bad_inode(inode);
161 affs_brelse(bh);
162 return;
163}
164
165int
166affs_write_inode(struct inode *inode, int unused)
167{
168 struct super_block *sb = inode->i_sb;
169 struct buffer_head *bh;
170 struct affs_tail *tail;
171 uid_t uid;
172 gid_t gid;
173
174 pr_debug("AFFS: write_inode(%lu)\n",inode->i_ino);
175
176 if (!inode->i_nlink)
177 // possibly free block
178 return 0;
179 bh = affs_bread(sb, inode->i_ino);
180 if (!bh) {
181 affs_error(sb,"write_inode","Cannot read block %lu",inode->i_ino);
182 return -EIO;
183 }
184 tail = AFFS_TAIL(sb, bh);
185 if (tail->stype == cpu_to_be32(ST_ROOT)) {
186 secs_to_datestamp(inode->i_mtime.tv_sec,&AFFS_ROOT_TAIL(sb, bh)->root_change);
187 } else {
188 tail->protect = cpu_to_be32(AFFS_I(inode)->i_protect);
189 tail->size = cpu_to_be32(inode->i_size);
190 secs_to_datestamp(inode->i_mtime.tv_sec,&tail->change);
191 if (!(inode->i_ino == AFFS_SB(sb)->s_root_block)) {
192 uid = inode->i_uid;
193 gid = inode->i_gid;
194 if (AFFS_SB(sb)->s_flags & SF_MUFS) {
195 if (inode->i_uid == 0 || inode->i_uid == 0xFFFF)
196 uid = inode->i_uid ^ ~0;
197 if (inode->i_gid == 0 || inode->i_gid == 0xFFFF)
198 gid = inode->i_gid ^ ~0;
199 }
200 if (!(AFFS_SB(sb)->s_flags & SF_SETUID))
201 tail->uid = cpu_to_be16(uid);
202 if (!(AFFS_SB(sb)->s_flags & SF_SETGID))
203 tail->gid = cpu_to_be16(gid);
204 }
205 }
206 affs_fix_checksum(sb, bh);
207 mark_buffer_dirty_inode(bh, inode);
208 affs_brelse(bh);
209 affs_free_prealloc(inode);
210 return 0;
211}
212
213int
214affs_notify_change(struct dentry *dentry, struct iattr *attr)
215{
216 struct inode *inode = dentry->d_inode;
217 int error;
218
219 pr_debug("AFFS: notify_change(%lu,0x%x)\n",inode->i_ino,attr->ia_valid);
220
221 error = inode_change_ok(inode,attr);
222 if (error)
223 goto out;
224
225 if (((attr->ia_valid & ATTR_UID) && (AFFS_SB(inode->i_sb)->s_flags & SF_SETUID)) ||
226 ((attr->ia_valid & ATTR_GID) && (AFFS_SB(inode->i_sb)->s_flags & SF_SETGID)) ||
227 ((attr->ia_valid & ATTR_MODE) &&
228 (AFFS_SB(inode->i_sb)->s_flags & (SF_SETMODE | SF_IMMUTABLE)))) {
229 if (!(AFFS_SB(inode->i_sb)->s_flags & SF_QUIET))
230 error = -EPERM;
231 goto out;
232 }
233
234 error = inode_setattr(inode, attr);
235 if (!error && (attr->ia_valid & ATTR_MODE))
236 mode_to_prot(inode);
237out:
238 return error;
239}
240
241void
242affs_put_inode(struct inode *inode)
243{
244 pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
245 affs_free_prealloc(inode);
246 if (atomic_read(&inode->i_count) == 1) {
247 down(&inode->i_sem);
248 if (inode->i_size != AFFS_I(inode)->mmu_private)
249 affs_truncate(inode);
250 up(&inode->i_sem);
251 }
252}
253
254void
255affs_delete_inode(struct inode *inode)
256{
257 pr_debug("AFFS: delete_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
258 inode->i_size = 0;
259 if (S_ISREG(inode->i_mode))
260 affs_truncate(inode);
261 clear_inode(inode);
262 affs_free_block(inode->i_sb, inode->i_ino);
263}
264
265void
266affs_clear_inode(struct inode *inode)
267{
268 unsigned long cache_page = (unsigned long) AFFS_I(inode)->i_lc;
269
270 pr_debug("AFFS: clear_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
271 if (cache_page) {
272 pr_debug("AFFS: freeing ext cache\n");
273 AFFS_I(inode)->i_lc = NULL;
274 AFFS_I(inode)->i_ac = NULL;
275 free_page(cache_page);
276 }
277 affs_brelse(AFFS_I(inode)->i_ext_bh);
278 AFFS_I(inode)->i_ext_last = ~1;
279 AFFS_I(inode)->i_ext_bh = NULL;
280}
281
282struct inode *
283affs_new_inode(struct inode *dir)
284{
285 struct super_block *sb = dir->i_sb;
286 struct inode *inode;
287 u32 block;
288 struct buffer_head *bh;
289
290 if (!(inode = new_inode(sb)))
291 goto err_inode;
292
293 if (!(block = affs_alloc_block(dir, dir->i_ino)))
294 goto err_block;
295
296 bh = affs_getzeroblk(sb, block);
297 if (!bh)
298 goto err_bh;
299 mark_buffer_dirty_inode(bh, inode);
300 affs_brelse(bh);
301
302 inode->i_uid = current->fsuid;
303 inode->i_gid = current->fsgid;
304 inode->i_ino = block;
305 inode->i_nlink = 1;
306 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
307 AFFS_I(inode)->i_opencnt = 0;
308 AFFS_I(inode)->i_blkcnt = 0;
309 AFFS_I(inode)->i_lc = NULL;
310 AFFS_I(inode)->i_lc_size = 0;
311 AFFS_I(inode)->i_lc_shift = 0;
312 AFFS_I(inode)->i_lc_mask = 0;
313 AFFS_I(inode)->i_ac = NULL;
314 AFFS_I(inode)->i_ext_bh = NULL;
315 AFFS_I(inode)->mmu_private = 0;
316 AFFS_I(inode)->i_protect = 0;
317 AFFS_I(inode)->i_lastalloc = 0;
318 AFFS_I(inode)->i_pa_cnt = 0;
319 AFFS_I(inode)->i_extcnt = 1;
320 AFFS_I(inode)->i_ext_last = ~1;
321
322 insert_inode_hash(inode);
323
324 return inode;
325
326err_bh:
327 affs_free_block(sb, block);
328err_block:
329 iput(inode);
330err_inode:
331 return NULL;
332}
333
334/*
335 * Add an entry to a directory. Create the header block
336 * and insert it into the hash table.
337 */
338
339int
340affs_add_entry(struct inode *dir, struct inode *inode, struct dentry *dentry, s32 type)
341{
342 struct super_block *sb = dir->i_sb;
343 struct buffer_head *inode_bh = NULL;
344 struct buffer_head *bh = NULL;
345 u32 block = 0;
346 int retval;
347
348 pr_debug("AFFS: add_entry(dir=%u, inode=%u, \"%*s\", type=%d)\n", (u32)dir->i_ino,
349 (u32)inode->i_ino, (int)dentry->d_name.len, dentry->d_name.name, type);
350
351 retval = -EIO;
352 bh = affs_bread(sb, inode->i_ino);
353 if (!bh)
354 goto done;
355
356 affs_lock_link(inode);
357 switch (type) {
358 case ST_LINKFILE:
359 case ST_LINKDIR:
360 inode_bh = bh;
361 retval = -ENOSPC;
362 block = affs_alloc_block(dir, dir->i_ino);
363 if (!block)
364 goto err;
365 retval = -EIO;
366 bh = affs_getzeroblk(sb, block);
367 if (!bh)
368 goto err;
369 break;
370 default:
371 break;
372 }
373
374 AFFS_HEAD(bh)->ptype = cpu_to_be32(T_SHORT);
375 AFFS_HEAD(bh)->key = cpu_to_be32(bh->b_blocknr);
376 affs_copy_name(AFFS_TAIL(sb, bh)->name, dentry);
377 AFFS_TAIL(sb, bh)->stype = cpu_to_be32(type);
378 AFFS_TAIL(sb, bh)->parent = cpu_to_be32(dir->i_ino);
379
380 if (inode_bh) {
381 __be32 chain;
382 chain = AFFS_TAIL(sb, inode_bh)->link_chain;
383 AFFS_TAIL(sb, bh)->original = cpu_to_be32(inode->i_ino);
384 AFFS_TAIL(sb, bh)->link_chain = chain;
385 AFFS_TAIL(sb, inode_bh)->link_chain = cpu_to_be32(block);
386 affs_adjust_checksum(inode_bh, block - be32_to_cpu(chain));
387 mark_buffer_dirty_inode(inode_bh, inode);
388 inode->i_nlink = 2;
389 atomic_inc(&inode->i_count);
390 }
391 affs_fix_checksum(sb, bh);
392 mark_buffer_dirty_inode(bh, inode);
393 dentry->d_fsdata = (void *)(long)bh->b_blocknr;
394
395 affs_lock_dir(dir);
396 retval = affs_insert_hash(dir, bh);
397 mark_buffer_dirty_inode(bh, inode);
398 affs_unlock_dir(dir);
399 affs_unlock_link(inode);
400
401 d_instantiate(dentry, inode);
402done:
403 affs_brelse(inode_bh);
404 affs_brelse(bh);
405 return retval;
406err:
407 if (block)
408 affs_free_block(sb, block);
409 affs_unlock_link(inode);
410 goto done;
411}
diff --git a/fs/affs/namei.c b/fs/affs/namei.c
new file mode 100644
index 000000000000..d4c2d636c479
--- /dev/null
+++ b/fs/affs/namei.c
@@ -0,0 +1,443 @@
1/*
2 * linux/fs/affs/namei.c
3 *
4 * (c) 1996 Hans-Joachim Widmaier - Rewritten
5 *
6 * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem.
7 *
8 * (C) 1991 Linus Torvalds - minix filesystem
9 */
10
11#include "affs.h"
12
13typedef int (*toupper_t)(int);
14
15static int affs_toupper(int ch);
16static int affs_hash_dentry(struct dentry *, struct qstr *);
17static int affs_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
18static int affs_intl_toupper(int ch);
19static int affs_intl_hash_dentry(struct dentry *, struct qstr *);
20static int affs_intl_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
21
22struct dentry_operations affs_dentry_operations = {
23 .d_hash = affs_hash_dentry,
24 .d_compare = affs_compare_dentry,
25};
26
27static struct dentry_operations affs_intl_dentry_operations = {
28 .d_hash = affs_intl_hash_dentry,
29 .d_compare = affs_intl_compare_dentry,
30};
31
32
33/* Simple toupper() for DOS\1 */
34
35static int
36affs_toupper(int ch)
37{
38 return ch >= 'a' && ch <= 'z' ? ch -= ('a' - 'A') : ch;
39}
40
41/* International toupper() for DOS\3 ("international") */
42
43static int
44affs_intl_toupper(int ch)
45{
46 return (ch >= 'a' && ch <= 'z') || (ch >= 0xE0
47 && ch <= 0xFE && ch != 0xF7) ?
48 ch - ('a' - 'A') : ch;
49}
50
51static inline toupper_t
52affs_get_toupper(struct super_block *sb)
53{
54 return AFFS_SB(sb)->s_flags & SF_INTL ? affs_intl_toupper : affs_toupper;
55}
56
57/*
58 * Note: the dentry argument is the parent dentry.
59 */
60static inline int
61__affs_hash_dentry(struct dentry *dentry, struct qstr *qstr, toupper_t toupper)
62{
63 const u8 *name = qstr->name;
64 unsigned long hash;
65 int i;
66
67 i = affs_check_name(qstr->name,qstr->len);
68 if (i)
69 return i;
70
71 hash = init_name_hash();
72 i = min(qstr->len, 30u);
73 for (; i > 0; name++, i--)
74 hash = partial_name_hash(toupper(*name), hash);
75 qstr->hash = end_name_hash(hash);
76
77 return 0;
78}
79
80static int
81affs_hash_dentry(struct dentry *dentry, struct qstr *qstr)
82{
83 return __affs_hash_dentry(dentry, qstr, affs_toupper);
84}
85static int
86affs_intl_hash_dentry(struct dentry *dentry, struct qstr *qstr)
87{
88 return __affs_hash_dentry(dentry, qstr, affs_intl_toupper);
89}
90
91static inline int
92__affs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b, toupper_t toupper)
93{
94 const u8 *aname = a->name;
95 const u8 *bname = b->name;
96 int len;
97
98 /* 'a' is the qstr of an already existing dentry, so the name
99 * must be valid. 'b' must be validated first.
100 */
101
102 if (affs_check_name(b->name,b->len))
103 return 1;
104
105 /* If the names are longer than the allowed 30 chars,
106 * the excess is ignored, so their length may differ.
107 */
108 len = a->len;
109 if (len >= 30) {
110 if (b->len < 30)
111 return 1;
112 len = 30;
113 } else if (len != b->len)
114 return 1;
115
116 for (; len > 0; len--)
117 if (toupper(*aname++) != toupper(*bname++))
118 return 1;
119
120 return 0;
121}
122
123static int
124affs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
125{
126 return __affs_compare_dentry(dentry, a, b, affs_toupper);
127}
128static int
129affs_intl_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
130{
131 return __affs_compare_dentry(dentry, a, b, affs_intl_toupper);
132}
133
134/*
135 * NOTE! unlike strncmp, affs_match returns 1 for success, 0 for failure.
136 */
137
138static inline int
139affs_match(struct dentry *dentry, const u8 *name2, toupper_t toupper)
140{
141 const u8 *name = dentry->d_name.name;
142 int len = dentry->d_name.len;
143
144 if (len >= 30) {
145 if (*name2 < 30)
146 return 0;
147 len = 30;
148 } else if (len != *name2)
149 return 0;
150
151 for (name2++; len > 0; len--)
152 if (toupper(*name++) != toupper(*name2++))
153 return 0;
154 return 1;
155}
156
157int
158affs_hash_name(struct super_block *sb, const u8 *name, unsigned int len)
159{
160 toupper_t toupper = affs_get_toupper(sb);
161 int hash;
162
163 hash = len = min(len, 30u);
164 for (; len > 0; len--)
165 hash = (hash * 13 + toupper(*name++)) & 0x7ff;
166
167 return hash % AFFS_SB(sb)->s_hashsize;
168}
169
170static struct buffer_head *
171affs_find_entry(struct inode *dir, struct dentry *dentry)
172{
173 struct super_block *sb = dir->i_sb;
174 struct buffer_head *bh;
175 toupper_t toupper = affs_get_toupper(sb);
176 u32 key;
177
178 pr_debug("AFFS: find_entry(\"%.*s\")\n", (int)dentry->d_name.len, dentry->d_name.name);
179
180 bh = affs_bread(sb, dir->i_ino);
181 if (!bh)
182 return ERR_PTR(-EIO);
183
184 key = be32_to_cpu(AFFS_HEAD(bh)->table[affs_hash_name(sb, dentry->d_name.name, dentry->d_name.len)]);
185
186 for (;;) {
187 affs_brelse(bh);
188 if (key == 0)
189 return NULL;
190 bh = affs_bread(sb, key);
191 if (!bh)
192 return ERR_PTR(-EIO);
193 if (affs_match(dentry, AFFS_TAIL(sb, bh)->name, toupper))
194 return bh;
195 key = be32_to_cpu(AFFS_TAIL(sb, bh)->hash_chain);
196 }
197}
198
199struct dentry *
200affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
201{
202 struct super_block *sb = dir->i_sb;
203 struct buffer_head *bh;
204 struct inode *inode = NULL;
205
206 pr_debug("AFFS: lookup(\"%.*s\")\n",(int)dentry->d_name.len,dentry->d_name.name);
207
208 affs_lock_dir(dir);
209 bh = affs_find_entry(dir, dentry);
210 affs_unlock_dir(dir);
211 if (IS_ERR(bh)) {
212 return ERR_PTR(PTR_ERR(bh));
213 }
214 if (bh) {
215 u32 ino = bh->b_blocknr;
216
217 /* store the real header ino in d_fsdata for faster lookups */
218 dentry->d_fsdata = (void *)(long)ino;
219 switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) {
220 //link to dirs disabled
221 //case ST_LINKDIR:
222 case ST_LINKFILE:
223 ino = be32_to_cpu(AFFS_TAIL(sb, bh)->original);
224 }
225 affs_brelse(bh);
226 inode = iget(sb, ino);
227 if (!inode) {
228 return ERR_PTR(-EACCES);
229 }
230 }
231 dentry->d_op = AFFS_SB(sb)->s_flags & SF_INTL ? &affs_intl_dentry_operations : &affs_dentry_operations;
232 d_add(dentry, inode);
233 return NULL;
234}
235
236int
237affs_unlink(struct inode *dir, struct dentry *dentry)
238{
239 pr_debug("AFFS: unlink(dir=%d, \"%.*s\")\n", (u32)dir->i_ino,
240 (int)dentry->d_name.len, dentry->d_name.name);
241
242 return affs_remove_header(dentry);
243}
244
245int
246affs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd)
247{
248 struct super_block *sb = dir->i_sb;
249 struct inode *inode;
250 int error;
251
252 pr_debug("AFFS: create(%lu,\"%.*s\",0%o)\n",dir->i_ino,(int)dentry->d_name.len,
253 dentry->d_name.name,mode);
254
255 inode = affs_new_inode(dir);
256 if (!inode)
257 return -ENOSPC;
258
259 inode->i_mode = mode;
260 mode_to_prot(inode);
261 mark_inode_dirty(inode);
262
263 inode->i_op = &affs_file_inode_operations;
264 inode->i_fop = &affs_file_operations;
265 inode->i_mapping->a_ops = (AFFS_SB(sb)->s_flags & SF_OFS) ? &affs_aops_ofs : &affs_aops;
266 error = affs_add_entry(dir, inode, dentry, ST_FILE);
267 if (error) {
268 inode->i_nlink = 0;
269 iput(inode);
270 return error;
271 }
272 return 0;
273}
274
275int
276affs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
277{
278 struct inode *inode;
279 int error;
280
281 pr_debug("AFFS: mkdir(%lu,\"%.*s\",0%o)\n",dir->i_ino,
282 (int)dentry->d_name.len,dentry->d_name.name,mode);
283
284 inode = affs_new_inode(dir);
285 if (!inode)
286 return -ENOSPC;
287
288 inode->i_mode = S_IFDIR | mode;
289 mode_to_prot(inode);
290
291 inode->i_op = &affs_dir_inode_operations;
292 inode->i_fop = &affs_dir_operations;
293
294 error = affs_add_entry(dir, inode, dentry, ST_USERDIR);
295 if (error) {
296 inode->i_nlink = 0;
297 mark_inode_dirty(inode);
298 iput(inode);
299 return error;
300 }
301 return 0;
302}
303
304int
305affs_rmdir(struct inode *dir, struct dentry *dentry)
306{
307 pr_debug("AFFS: rmdir(dir=%u, \"%.*s\")\n", (u32)dir->i_ino,
308 (int)dentry->d_name.len, dentry->d_name.name);
309
310 return affs_remove_header(dentry);
311}
312
313int
314affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
315{
316 struct super_block *sb = dir->i_sb;
317 struct buffer_head *bh;
318 struct inode *inode;
319 char *p;
320 int i, maxlen, error;
321 char c, lc;
322
323 pr_debug("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,
324 (int)dentry->d_name.len,dentry->d_name.name,symname);
325
326 maxlen = AFFS_SB(sb)->s_hashsize * sizeof(u32) - 1;
327 inode = affs_new_inode(dir);
328 if (!inode)
329 return -ENOSPC;
330
331 inode->i_op = &affs_symlink_inode_operations;
332 inode->i_data.a_ops = &affs_symlink_aops;
333 inode->i_mode = S_IFLNK | 0777;
334 mode_to_prot(inode);
335
336 error = -EIO;
337 bh = affs_bread(sb, inode->i_ino);
338 if (!bh)
339 goto err;
340 i = 0;
341 p = (char *)AFFS_HEAD(bh)->table;
342 lc = '/';
343 if (*symname == '/') {
344 while (*symname == '/')
345 symname++;
346 while (AFFS_SB(sb)->s_volume[i]) /* Cannot overflow */
347 *p++ = AFFS_SB(sb)->s_volume[i++];
348 }
349 while (i < maxlen && (c = *symname++)) {
350 if (c == '.' && lc == '/' && *symname == '.' && symname[1] == '/') {
351 *p++ = '/';
352 i++;
353 symname += 2;
354 lc = '/';
355 } else if (c == '.' && lc == '/' && *symname == '/') {
356 symname++;
357 lc = '/';
358 } else {
359 *p++ = c;
360 lc = c;
361 i++;
362 }
363 if (lc == '/')
364 while (*symname == '/')
365 symname++;
366 }
367 *p = 0;
368 mark_buffer_dirty_inode(bh, inode);
369 affs_brelse(bh);
370 mark_inode_dirty(inode);
371
372 error = affs_add_entry(dir, inode, dentry, ST_SOFTLINK);
373 if (error)
374 goto err;
375
376 return 0;
377
378err:
379 inode->i_nlink = 0;
380 mark_inode_dirty(inode);
381 iput(inode);
382 return error;
383}
384
385int
386affs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
387{
388 struct inode *inode = old_dentry->d_inode;
389
390 pr_debug("AFFS: link(%u, %u, \"%.*s\")\n", (u32)inode->i_ino, (u32)dir->i_ino,
391 (int)dentry->d_name.len,dentry->d_name.name);
392
393 return affs_add_entry(dir, inode, dentry, ST_LINKFILE);
394}
395
396int
397affs_rename(struct inode *old_dir, struct dentry *old_dentry,
398 struct inode *new_dir, struct dentry *new_dentry)
399{
400 struct super_block *sb = old_dir->i_sb;
401 struct buffer_head *bh = NULL;
402 int retval;
403
404 pr_debug("AFFS: rename(old=%u,\"%*s\" to new=%u,\"%*s\")\n",
405 (u32)old_dir->i_ino, (int)old_dentry->d_name.len, old_dentry->d_name.name,
406 (u32)new_dir->i_ino, (int)new_dentry->d_name.len, new_dentry->d_name.name);
407
408 retval = affs_check_name(new_dentry->d_name.name,new_dentry->d_name.len);
409 if (retval)
410 return retval;
411
412 /* Unlink destination if it already exists */
413 if (new_dentry->d_inode) {
414 retval = affs_remove_header(new_dentry);
415 if (retval)
416 return retval;
417 }
418
419 retval = -EIO;
420 bh = affs_bread(sb, old_dentry->d_inode->i_ino);
421 if (!bh)
422 goto done;
423
424 /* Remove header from its parent directory. */
425 affs_lock_dir(old_dir);
426 retval = affs_remove_hash(old_dir, bh);
427 affs_unlock_dir(old_dir);
428 if (retval)
429 goto done;
430
431 /* And insert it into the new directory with the new name. */
432 affs_copy_name(AFFS_TAIL(sb, bh)->name, new_dentry);
433 affs_fix_checksum(sb, bh);
434 affs_lock_dir(new_dir);
435 retval = affs_insert_hash(new_dir, bh);
436 affs_unlock_dir(new_dir);
437 /* TODO: move it back to old_dir, if error? */
438
439done:
440 mark_buffer_dirty_inode(bh, retval ? old_dir : new_dir);
441 affs_brelse(bh);
442 return retval;
443}
diff --git a/fs/affs/super.c b/fs/affs/super.c
new file mode 100644
index 000000000000..9c3080716c92
--- /dev/null
+++ b/fs/affs/super.c
@@ -0,0 +1,569 @@
1/*
2 * linux/fs/affs/inode.c
3 *
4 * (c) 1996 Hans-Joachim Widmaier - Rewritten
5 *
6 * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem.
7 *
8 * (C) 1992 Eric Youngdale Modified for ISO 9660 filesystem.
9 *
10 * (C) 1991 Linus Torvalds - minix filesystem
11 */
12
13#include <linux/module.h>
14#include <linux/init.h>
15#include <linux/statfs.h>
16#include <linux/parser.h>
17#include "affs.h"
18
19extern struct timezone sys_tz;
20
21static int affs_statfs(struct super_block *sb, struct kstatfs *buf);
22static int affs_remount (struct super_block *sb, int *flags, char *data);
23
24static void
25affs_put_super(struct super_block *sb)
26{
27 struct affs_sb_info *sbi = AFFS_SB(sb);
28 pr_debug("AFFS: put_super()\n");
29
30 if (!(sb->s_flags & MS_RDONLY)) {
31 AFFS_ROOT_TAIL(sb, sbi->s_root_bh)->bm_flag = cpu_to_be32(1);
32 secs_to_datestamp(get_seconds(),
33 &AFFS_ROOT_TAIL(sb, sbi->s_root_bh)->disk_change);
34 affs_fix_checksum(sb, sbi->s_root_bh);
35 mark_buffer_dirty(sbi->s_root_bh);
36 }
37
38 if (sbi->s_prefix)
39 kfree(sbi->s_prefix);
40 affs_free_bitmap(sb);
41 affs_brelse(sbi->s_root_bh);
42 kfree(sbi);
43 sb->s_fs_info = NULL;
44 return;
45}
46
47static void
48affs_write_super(struct super_block *sb)
49{
50 int clean = 2;
51 struct affs_sb_info *sbi = AFFS_SB(sb);
52
53 if (!(sb->s_flags & MS_RDONLY)) {
54 // if (sbi->s_bitmap[i].bm_bh) {
55 // if (buffer_dirty(sbi->s_bitmap[i].bm_bh)) {
56 // clean = 0;
57 AFFS_ROOT_TAIL(sb, sbi->s_root_bh)->bm_flag = cpu_to_be32(clean);
58 secs_to_datestamp(get_seconds(),
59 &AFFS_ROOT_TAIL(sb, sbi->s_root_bh)->disk_change);
60 affs_fix_checksum(sb, sbi->s_root_bh);
61 mark_buffer_dirty(sbi->s_root_bh);
62 sb->s_dirt = !clean; /* redo until bitmap synced */
63 } else
64 sb->s_dirt = 0;
65
66 pr_debug("AFFS: write_super() at %lu, clean=%d\n", get_seconds(), clean);
67}
68
69static kmem_cache_t * affs_inode_cachep;
70
71static struct inode *affs_alloc_inode(struct super_block *sb)
72{
73 struct affs_inode_info *ei;
74 ei = (struct affs_inode_info *)kmem_cache_alloc(affs_inode_cachep, SLAB_KERNEL);
75 if (!ei)
76 return NULL;
77 ei->vfs_inode.i_version = 1;
78 return &ei->vfs_inode;
79}
80
81static void affs_destroy_inode(struct inode *inode)
82{
83 kmem_cache_free(affs_inode_cachep, AFFS_I(inode));
84}
85
86static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
87{
88 struct affs_inode_info *ei = (struct affs_inode_info *) foo;
89
90 if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
91 SLAB_CTOR_CONSTRUCTOR) {
92 init_MUTEX(&ei->i_link_lock);
93 init_MUTEX(&ei->i_ext_lock);
94 inode_init_once(&ei->vfs_inode);
95 }
96}
97
98static int init_inodecache(void)
99{
100 affs_inode_cachep = kmem_cache_create("affs_inode_cache",
101 sizeof(struct affs_inode_info),
102 0, SLAB_RECLAIM_ACCOUNT,
103 init_once, NULL);
104 if (affs_inode_cachep == NULL)
105 return -ENOMEM;
106 return 0;
107}
108
109static void destroy_inodecache(void)
110{
111 if (kmem_cache_destroy(affs_inode_cachep))
112 printk(KERN_INFO "affs_inode_cache: not all structures were freed\n");
113}
114
115static struct super_operations affs_sops = {
116 .alloc_inode = affs_alloc_inode,
117 .destroy_inode = affs_destroy_inode,
118 .read_inode = affs_read_inode,
119 .write_inode = affs_write_inode,
120 .put_inode = affs_put_inode,
121 .delete_inode = affs_delete_inode,
122 .clear_inode = affs_clear_inode,
123 .put_super = affs_put_super,
124 .write_super = affs_write_super,
125 .statfs = affs_statfs,
126 .remount_fs = affs_remount,
127};
128
129enum {
130 Opt_bs, Opt_mode, Opt_mufs, Opt_prefix, Opt_protect,
131 Opt_reserved, Opt_root, Opt_setgid, Opt_setuid,
132 Opt_verbose, Opt_volume, Opt_ignore, Opt_err,
133};
134
135static match_table_t tokens = {
136 {Opt_bs, "bs=%u"},
137 {Opt_mode, "mode=%o"},
138 {Opt_mufs, "mufs"},
139 {Opt_prefix, "prefix=%s"},
140 {Opt_protect, "protect"},
141 {Opt_reserved, "reserved=%u"},
142 {Opt_root, "root=%u"},
143 {Opt_setgid, "setgid=%u"},
144 {Opt_setuid, "setuid=%u"},
145 {Opt_verbose, "verbose"},
146 {Opt_volume, "volume=%s"},
147 {Opt_ignore, "grpquota"},
148 {Opt_ignore, "noquota"},
149 {Opt_ignore, "quota"},
150 {Opt_ignore, "usrquota"},
151 {Opt_err, NULL},
152};
153
154static int
155parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, s32 *root,
156 int *blocksize, char **prefix, char *volume, unsigned long *mount_opts)
157{
158 char *p;
159 substring_t args[MAX_OPT_ARGS];
160
161 /* Fill in defaults */
162
163 *uid = current->uid;
164 *gid = current->gid;
165 *reserved = 2;
166 *root = -1;
167 *blocksize = -1;
168 volume[0] = ':';
169 volume[1] = 0;
170 *mount_opts = 0;
171 if (!options)
172 return 1;
173
174 while ((p = strsep(&options, ",")) != NULL) {
175 int token, n, option;
176 if (!*p)
177 continue;
178
179 token = match_token(p, tokens, args);
180 switch (token) {
181 case Opt_bs:
182 if (match_int(&args[0], &n))
183 return -EINVAL;
184 if (n != 512 && n != 1024 && n != 2048
185 && n != 4096) {
186 printk ("AFFS: Invalid blocksize (512, 1024, 2048, 4096 allowed)\n");
187 return 0;
188 }
189 *blocksize = n;
190 break;
191 case Opt_mode:
192 if (match_octal(&args[0], &option))
193 return 1;
194 *mode = option & 0777;
195 *mount_opts |= SF_SETMODE;
196 break;
197 case Opt_mufs:
198 *mount_opts |= SF_MUFS;
199 break;
200 case Opt_prefix:
201 if (*prefix) { /* Free any previous prefix */
202 kfree(*prefix);
203 *prefix = NULL;
204 }
205 *prefix = match_strdup(&args[0]);
206 if (!*prefix)
207 return 0;
208 *mount_opts |= SF_PREFIX;
209 break;
210 case Opt_protect:
211 *mount_opts |= SF_IMMUTABLE;
212 break;
213 case Opt_reserved:
214 if (match_int(&args[0], reserved))
215 return 1;
216 break;
217 case Opt_root:
218 if (match_int(&args[0], root))
219 return 1;
220 break;
221 case Opt_setgid:
222 if (match_int(&args[0], &option))
223 return 1;
224 *gid = option;
225 *mount_opts |= SF_SETGID;
226 break;
227 case Opt_setuid:
228 if (match_int(&args[0], &option))
229 return -EINVAL;
230 *uid = option;
231 *mount_opts |= SF_SETUID;
232 break;
233 case Opt_verbose:
234 *mount_opts |= SF_VERBOSE;
235 break;
236 case Opt_volume: {
237 char *vol = match_strdup(&args[0]);
238 strlcpy(volume, vol, 32);
239 kfree(vol);
240 break;
241 }
242 case Opt_ignore:
243 /* Silently ignore the quota options */
244 break;
245 default:
246 printk("AFFS: Unrecognized mount option \"%s\" "
247 "or missing value\n", p);
248 return 0;
249 }
250 }
251 return 1;
252}
253
254/* This function definitely needs to be split up. Some fine day I'll
255 * hopefully have the guts to do so. Until then: sorry for the mess.
256 */
257
258static int affs_fill_super(struct super_block *sb, void *data, int silent)
259{
260 struct affs_sb_info *sbi;
261 struct buffer_head *root_bh = NULL;
262 struct buffer_head *boot_bh;
263 struct inode *root_inode = NULL;
264 s32 root_block;
265 int size, blocksize;
266 u32 chksum;
267 int num_bm;
268 int i, j;
269 s32 key;
270 uid_t uid;
271 gid_t gid;
272 int reserved;
273 unsigned long mount_flags;
274 int tmp_flags; /* fix remount prototype... */
275
276 pr_debug("AFFS: read_super(%s)\n",data ? (const char *)data : "no options");
277
278 sb->s_magic = AFFS_SUPER_MAGIC;
279 sb->s_op = &affs_sops;
280 sb->s_flags |= MS_NODIRATIME;
281
282 sbi = kmalloc(sizeof(struct affs_sb_info), GFP_KERNEL);
283 if (!sbi)
284 return -ENOMEM;
285 sb->s_fs_info = sbi;
286 memset(sbi, 0, sizeof(*sbi));
287 init_MUTEX(&sbi->s_bmlock);
288
289 if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block,
290 &blocksize,&sbi->s_prefix,
291 sbi->s_volume, &mount_flags)) {
292 printk(KERN_ERR "AFFS: Error parsing options\n");
293 return -EINVAL;
294 }
295 /* N.B. after this point s_prefix must be released */
296
297 sbi->s_flags = mount_flags;
298 sbi->s_mode = i;
299 sbi->s_uid = uid;
300 sbi->s_gid = gid;
301 sbi->s_reserved= reserved;
302
303 /* Get the size of the device in 512-byte blocks.
304 * If we later see that the partition uses bigger
305 * blocks, we will have to change it.
306 */
307
308 size = sb->s_bdev->bd_inode->i_size >> 9;
309 pr_debug("AFFS: initial blocksize=%d, #blocks=%d\n", 512, size);
310
311 affs_set_blocksize(sb, PAGE_SIZE);
312 /* Try to find root block. Its location depends on the block size. */
313
314 i = 512;
315 j = 4096;
316 if (blocksize > 0) {
317 i = j = blocksize;
318 size = size / (blocksize / 512);
319 }
320 for (blocksize = i, key = 0; blocksize <= j; blocksize <<= 1, size >>= 1) {
321 sbi->s_root_block = root_block;
322 if (root_block < 0)
323 sbi->s_root_block = (reserved + size - 1) / 2;
324 pr_debug("AFFS: setting blocksize to %d\n", blocksize);
325 affs_set_blocksize(sb, blocksize);
326 sbi->s_partition_size = size;
327
328 /* The root block location that was calculated above is not
329 * correct if the partition size is an odd number of 512-
330 * byte blocks, which will be rounded down to a number of
331 * 1024-byte blocks, and if there were an even number of
332 * reserved blocks. Ideally, all partition checkers should
333 * report the real number of blocks of the real blocksize,
334 * but since this just cannot be done, we have to try to
335 * find the root block anyways. In the above case, it is one
336 * block behind the calculated one. So we check this one, too.
337 */
338 for (num_bm = 0; num_bm < 2; num_bm++) {
339 pr_debug("AFFS: Dev %s, trying root=%u, bs=%d, "
340 "size=%d, reserved=%d\n",
341 sb->s_id,
342 sbi->s_root_block + num_bm,
343 blocksize, size, reserved);
344 root_bh = affs_bread(sb, sbi->s_root_block + num_bm);
345 if (!root_bh)
346 continue;
347 if (!affs_checksum_block(sb, root_bh) &&
348 be32_to_cpu(AFFS_ROOT_HEAD(root_bh)->ptype) == T_SHORT &&
349 be32_to_cpu(AFFS_ROOT_TAIL(sb, root_bh)->stype) == ST_ROOT) {
350 sbi->s_hashsize = blocksize / 4 - 56;
351 sbi->s_root_block += num_bm;
352 key = 1;
353 goto got_root;
354 }
355 affs_brelse(root_bh);
356 root_bh = NULL;
357 }
358 }
359 if (!silent)
360 printk(KERN_ERR "AFFS: No valid root block on device %s\n",
361 sb->s_id);
362 goto out_error;
363
364 /* N.B. after this point bh must be released */
365got_root:
366 root_block = sbi->s_root_block;
367
368 /* Find out which kind of FS we have */
369 boot_bh = sb_bread(sb, 0);
370 if (!boot_bh) {
371 printk(KERN_ERR "AFFS: Cannot read boot block\n");
372 goto out_error;
373 }
374 chksum = be32_to_cpu(*(__be32 *)boot_bh->b_data);
375 brelse(boot_bh);
376
377 /* Dircache filesystems are compatible with non-dircache ones
378 * when reading. As long as they aren't supported, writing is
379 * not recommended.
380 */
381 if ((chksum == FS_DCFFS || chksum == MUFS_DCFFS || chksum == FS_DCOFS
382 || chksum == MUFS_DCOFS) && !(sb->s_flags & MS_RDONLY)) {
383 printk(KERN_NOTICE "AFFS: Dircache FS - mounting %s read only\n",
384 sb->s_id);
385 sb->s_flags |= MS_RDONLY;
386 }
387 switch (chksum) {
388 case MUFS_FS:
389 case MUFS_INTLFFS:
390 case MUFS_DCFFS:
391 sbi->s_flags |= SF_MUFS;
392 /* fall thru */
393 case FS_INTLFFS:
394 case FS_DCFFS:
395 sbi->s_flags |= SF_INTL;
396 break;
397 case MUFS_FFS:
398 sbi->s_flags |= SF_MUFS;
399 break;
400 case FS_FFS:
401 break;
402 case MUFS_OFS:
403 sbi->s_flags |= SF_MUFS;
404 /* fall thru */
405 case FS_OFS:
406 sbi->s_flags |= SF_OFS;
407 sb->s_flags |= MS_NOEXEC;
408 break;
409 case MUFS_DCOFS:
410 case MUFS_INTLOFS:
411 sbi->s_flags |= SF_MUFS;
412 case FS_DCOFS:
413 case FS_INTLOFS:
414 sbi->s_flags |= SF_INTL | SF_OFS;
415 sb->s_flags |= MS_NOEXEC;
416 break;
417 default:
418 printk(KERN_ERR "AFFS: Unknown filesystem on device %s: %08X\n",
419 sb->s_id, chksum);
420 goto out_error;
421 }
422
423 if (mount_flags & SF_VERBOSE) {
424 chksum = cpu_to_be32(chksum);
425 printk(KERN_NOTICE "AFFS: Mounting volume \"%*s\": Type=%.3s\\%c, Blocksize=%d\n",
426 AFFS_ROOT_TAIL(sb, root_bh)->disk_name[0],
427 AFFS_ROOT_TAIL(sb, root_bh)->disk_name + 1,
428 (char *)&chksum,((char *)&chksum)[3] + '0',blocksize);
429 }
430
431 sb->s_flags |= MS_NODEV | MS_NOSUID;
432
433 sbi->s_data_blksize = sb->s_blocksize;
434 if (sbi->s_flags & SF_OFS)
435 sbi->s_data_blksize -= 24;
436
437 /* Keep super block in cache */
438 sbi->s_root_bh = root_bh;
439 /* N.B. after this point s_root_bh must be released */
440
441 tmp_flags = sb->s_flags;
442 if (affs_init_bitmap(sb, &tmp_flags))
443 goto out_error;
444 sb->s_flags = tmp_flags;
445
446 /* set up enough so that it can read an inode */
447
448 root_inode = iget(sb, root_block);
449 sb->s_root = d_alloc_root(root_inode);
450 if (!sb->s_root) {
451 printk(KERN_ERR "AFFS: Get root inode failed\n");
452 goto out_error;
453 }
454 sb->s_root->d_op = &affs_dentry_operations;
455
456 pr_debug("AFFS: s_flags=%lX\n",sb->s_flags);
457 return 0;
458
459 /*
460 * Begin the cascaded cleanup ...
461 */
462out_error:
463 if (root_inode)
464 iput(root_inode);
465 if (sbi->s_bitmap)
466 kfree(sbi->s_bitmap);
467 affs_brelse(root_bh);
468 if (sbi->s_prefix)
469 kfree(sbi->s_prefix);
470 kfree(sbi);
471 sb->s_fs_info = NULL;
472 return -EINVAL;
473}
474
475static int
476affs_remount(struct super_block *sb, int *flags, char *data)
477{
478 struct affs_sb_info *sbi = AFFS_SB(sb);
479 int blocksize;
480 uid_t uid;
481 gid_t gid;
482 int mode;
483 int reserved;
484 int root_block;
485 unsigned long mount_flags;
486 int res = 0;
487
488 pr_debug("AFFS: remount(flags=0x%x,opts=\"%s\")\n",*flags,data);
489
490 *flags |= MS_NODIRATIME;
491
492 if (!parse_options(data,&uid,&gid,&mode,&reserved,&root_block,
493 &blocksize,&sbi->s_prefix,sbi->s_volume,&mount_flags))
494 return -EINVAL;
495 sbi->s_flags = mount_flags;
496 sbi->s_mode = mode;
497 sbi->s_uid = uid;
498 sbi->s_gid = gid;
499
500 if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
501 return 0;
502 if (*flags & MS_RDONLY) {
503 sb->s_dirt = 1;
504 while (sb->s_dirt)
505 affs_write_super(sb);
506 affs_free_bitmap(sb);
507 } else
508 res = affs_init_bitmap(sb, flags);
509
510 return res;
511}
512
513static int
514affs_statfs(struct super_block *sb, struct kstatfs *buf)
515{
516 int free;
517
518 pr_debug("AFFS: statfs() partsize=%d, reserved=%d\n",AFFS_SB(sb)->s_partition_size,
519 AFFS_SB(sb)->s_reserved);
520
521 free = affs_count_free_blocks(sb);
522 buf->f_type = AFFS_SUPER_MAGIC;
523 buf->f_bsize = sb->s_blocksize;
524 buf->f_blocks = AFFS_SB(sb)->s_partition_size - AFFS_SB(sb)->s_reserved;
525 buf->f_bfree = free;
526 buf->f_bavail = free;
527 return 0;
528}
529
530static struct super_block *affs_get_sb(struct file_system_type *fs_type,
531 int flags, const char *dev_name, void *data)
532{
533 return get_sb_bdev(fs_type, flags, dev_name, data, affs_fill_super);
534}
535
536static struct file_system_type affs_fs_type = {
537 .owner = THIS_MODULE,
538 .name = "affs",
539 .get_sb = affs_get_sb,
540 .kill_sb = kill_block_super,
541 .fs_flags = FS_REQUIRES_DEV,
542};
543
544static int __init init_affs_fs(void)
545{
546 int err = init_inodecache();
547 if (err)
548 goto out1;
549 err = register_filesystem(&affs_fs_type);
550 if (err)
551 goto out;
552 return 0;
553out:
554 destroy_inodecache();
555out1:
556 return err;
557}
558
559static void __exit exit_affs_fs(void)
560{
561 unregister_filesystem(&affs_fs_type);
562 destroy_inodecache();
563}
564
565MODULE_DESCRIPTION("Amiga filesystem support for Linux");
566MODULE_LICENSE("GPL");
567
568module_init(init_affs_fs)
569module_exit(exit_affs_fs)
diff --git a/fs/affs/symlink.c b/fs/affs/symlink.c
new file mode 100644
index 000000000000..426f0f094f23
--- /dev/null
+++ b/fs/affs/symlink.c
@@ -0,0 +1,78 @@
1/*
2 * linux/fs/affs/symlink.c
3 *
4 * 1995 Hans-Joachim Widmaier - Modified for affs.
5 *
6 * Copyright (C) 1991, 1992 Linus Torvalds
7 *
8 * affs symlink handling code
9 */
10
11#include "affs.h"
12
13static int affs_symlink_readpage(struct file *file, struct page *page)
14{
15 struct buffer_head *bh;
16 struct inode *inode = page->mapping->host;
17 char *link = kmap(page);
18 struct slink_front *lf;
19 int err;
20 int i, j;
21 char c;
22 char lc;
23 char *pf;
24
25 pr_debug("AFFS: follow_link(ino=%lu)\n",inode->i_ino);
26
27 err = -EIO;
28 bh = affs_bread(inode->i_sb, inode->i_ino);
29 if (!bh)
30 goto fail;
31 i = 0;
32 j = 0;
33 lf = (struct slink_front *)bh->b_data;
34 lc = 0;
35 pf = AFFS_SB(inode->i_sb)->s_prefix ? AFFS_SB(inode->i_sb)->s_prefix : "/";
36
37 if (strchr(lf->symname,':')) { /* Handle assign or volume name */
38 while (i < 1023 && (c = pf[i]))
39 link[i++] = c;
40 while (i < 1023 && lf->symname[j] != ':')
41 link[i++] = lf->symname[j++];
42 if (i < 1023)
43 link[i++] = '/';
44 j++;
45 lc = '/';
46 }
47 while (i < 1023 && (c = lf->symname[j])) {
48 if (c == '/' && lc == '/' && i < 1020) { /* parent dir */
49 link[i++] = '.';
50 link[i++] = '.';
51 }
52 link[i++] = c;
53 lc = c;
54 j++;
55 }
56 link[i] = '\0';
57 affs_brelse(bh);
58 SetPageUptodate(page);
59 kunmap(page);
60 unlock_page(page);
61 return 0;
62fail:
63 SetPageError(page);
64 kunmap(page);
65 unlock_page(page);
66 return err;
67}
68
69struct address_space_operations affs_symlink_aops = {
70 .readpage = affs_symlink_readpage,
71};
72
73struct inode_operations affs_symlink_inode_operations = {
74 .readlink = generic_readlink,
75 .follow_link = page_follow_link_light,
76 .put_link = page_put_link,
77 .setattr = affs_notify_change,
78};