diff options
Diffstat (limited to 'fs/affs')
-rw-r--r-- | fs/affs/Changes | 343 | ||||
-rw-r--r-- | fs/affs/Makefile | 9 | ||||
-rw-r--r-- | fs/affs/affs.h | 304 | ||||
-rw-r--r-- | fs/affs/amigaffs.c | 509 | ||||
-rw-r--r-- | fs/affs/bitmap.c | 390 | ||||
-rw-r--r-- | fs/affs/dir.c | 155 | ||||
-rw-r--r-- | fs/affs/file.c | 920 | ||||
-rw-r--r-- | fs/affs/inode.c | 411 | ||||
-rw-r--r-- | fs/affs/namei.c | 443 | ||||
-rw-r--r-- | fs/affs/super.c | 569 | ||||
-rw-r--r-- | fs/affs/symlink.c | 78 |
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 | ||
2 | that I do not like numbers like 0.1 and the like for | ||
3 | things that can be used since quite some time. But | ||
4 | then, 3.1 doesn't mean 'perfectly stable', too.) | ||
5 | |||
6 | Known 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 | |||
29 | Please direct bug reports to: zippel@linux-m68k.org | ||
30 | |||
31 | Version 3.20 | ||
32 | ------------ | ||
33 | - kill kernel lock | ||
34 | - fix for a possible bitmap corruption | ||
35 | |||
36 | Version 3.19 | ||
37 | ------------ | ||
38 | |||
39 | - sizeof changes from Kernel Janitor Project | ||
40 | - several bug fixes found with fsx | ||
41 | |||
42 | Version 3.18 | ||
43 | ------------ | ||
44 | |||
45 | - change to global min macro + warning fixes | ||
46 | - add module tags | ||
47 | |||
48 | Version 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 | |||
56 | Version 3.16 | ||
57 | ------------ | ||
58 | |||
59 | - use mark_buffer_dirty_inode instead of mark_buffer_dirty. | ||
60 | - introduce affs_lock_{link|dir|ext}. | ||
61 | |||
62 | Version 3.15 | ||
63 | ------------ | ||
64 | |||
65 | - disable link to directories until we can properly support them. | ||
66 | - locking fixes for link creation/removal. | ||
67 | |||
68 | Version 3.14 | ||
69 | ------------ | ||
70 | |||
71 | - correctly cut off long file names for compares | ||
72 | - correctly initialize s_last_bmap | ||
73 | |||
74 | Version 3.13 | ||
75 | ------------ | ||
76 | |||
77 | Major 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 | |||
83 | Version 3.12 | ||
84 | ------------ | ||
85 | |||
86 | more 2.4 fixes: [Roman Zippel] | ||
87 | - s_lock changes | ||
88 | - increased getblock mess | ||
89 | - clear meta blocks | ||
90 | |||
91 | Version 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 | |||
97 | Version 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 | |||
106 | Version 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 | |||
126 | Version 3.8 | ||
127 | ----------- | ||
128 | Bill Hawes kindly reviewed the affs and sent me the | ||
129 | patches 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 | |||
164 | Version 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 | |||
183 | Version 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 | |||
259 | Version 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 | |||
269 | Version 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 | |||
276 | Version 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 | |||
293 | Version 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 | |||
313 | Version 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 | |||
324 | Version 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 | |||
333 | Version 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 | |||
342 | Let'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 | |||
7 | obj-$(CONFIG_AFFS_FS) += affs.o | ||
8 | |||
9 | affs-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 | |||
43 | struct 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 | */ | ||
51 | struct 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 */ | ||
73 | static 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 | |||
85 | struct affs_bm_info { | ||
86 | u32 bm_key; /* Disk block number */ | ||
87 | u32 bm_free; /* Free blocks in here */ | ||
88 | }; | ||
89 | |||
90 | struct 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 */ | ||
126 | static inline struct affs_sb_info *AFFS_SB(struct super_block *sb) | ||
127 | { | ||
128 | return sb->s_fs_info; | ||
129 | } | ||
130 | |||
131 | /* amigaffs.c */ | ||
132 | |||
133 | extern int affs_insert_hash(struct inode *inode, struct buffer_head *bh); | ||
134 | extern int affs_remove_hash(struct inode *dir, struct buffer_head *rem_bh); | ||
135 | extern int affs_remove_header(struct dentry *dentry); | ||
136 | extern u32 affs_checksum_block(struct super_block *sb, struct buffer_head *bh); | ||
137 | extern void affs_fix_checksum(struct super_block *sb, struct buffer_head *bh); | ||
138 | extern void secs_to_datestamp(time_t secs, struct affs_date *ds); | ||
139 | extern mode_t prot_to_mode(u32 prot); | ||
140 | extern void mode_to_prot(struct inode *inode); | ||
141 | extern void affs_error(struct super_block *sb, const char *function, const char *fmt, ...); | ||
142 | extern void affs_warning(struct super_block *sb, const char *function, const char *fmt, ...); | ||
143 | extern int affs_check_name(const unsigned char *name, int len); | ||
144 | extern int affs_copy_name(unsigned char *bstr, struct dentry *dentry); | ||
145 | |||
146 | /* bitmap. c */ | ||
147 | |||
148 | extern u32 affs_count_free_blocks(struct super_block *s); | ||
149 | extern void affs_free_block(struct super_block *sb, u32 block); | ||
150 | extern u32 affs_alloc_block(struct inode *inode, u32 goal); | ||
151 | extern int affs_init_bitmap(struct super_block *sb, int *flags); | ||
152 | extern void affs_free_bitmap(struct super_block *sb); | ||
153 | |||
154 | /* namei.c */ | ||
155 | |||
156 | extern int affs_hash_name(struct super_block *sb, const u8 *name, unsigned int len); | ||
157 | extern struct dentry *affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *); | ||
158 | extern int affs_unlink(struct inode *dir, struct dentry *dentry); | ||
159 | extern int affs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *); | ||
160 | extern int affs_mkdir(struct inode *dir, struct dentry *dentry, int mode); | ||
161 | extern int affs_rmdir(struct inode *dir, struct dentry *dentry); | ||
162 | extern int affs_link(struct dentry *olddentry, struct inode *dir, | ||
163 | struct dentry *dentry); | ||
164 | extern int affs_symlink(struct inode *dir, struct dentry *dentry, | ||
165 | const char *symname); | ||
166 | extern 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 | |||
171 | extern unsigned long affs_parent_ino(struct inode *dir); | ||
172 | extern struct inode *affs_new_inode(struct inode *dir); | ||
173 | extern int affs_notify_change(struct dentry *dentry, struct iattr *attr); | ||
174 | extern void affs_put_inode(struct inode *inode); | ||
175 | extern void affs_delete_inode(struct inode *inode); | ||
176 | extern void affs_clear_inode(struct inode *inode); | ||
177 | extern void affs_read_inode(struct inode *inode); | ||
178 | extern int affs_write_inode(struct inode *inode, int); | ||
179 | extern int affs_add_entry(struct inode *dir, struct inode *inode, struct dentry *dentry, s32 type); | ||
180 | |||
181 | /* file.c */ | ||
182 | |||
183 | void affs_free_prealloc(struct inode *inode); | ||
184 | extern void affs_truncate(struct inode *); | ||
185 | |||
186 | /* dir.c */ | ||
187 | |||
188 | extern void affs_dir_truncate(struct inode *); | ||
189 | |||
190 | /* jump tables */ | ||
191 | |||
192 | extern struct inode_operations affs_file_inode_operations; | ||
193 | extern struct inode_operations affs_dir_inode_operations; | ||
194 | extern struct inode_operations affs_symlink_inode_operations; | ||
195 | extern struct file_operations affs_file_operations; | ||
196 | extern struct file_operations affs_file_operations_ofs; | ||
197 | extern struct file_operations affs_dir_operations; | ||
198 | extern struct address_space_operations affs_symlink_aops; | ||
199 | extern struct address_space_operations affs_aops; | ||
200 | extern struct address_space_operations affs_aops_ofs; | ||
201 | |||
202 | extern struct dentry_operations affs_dentry_operations; | ||
203 | extern struct dentry_operations affs_dentry_operations_intl; | ||
204 | |||
205 | static inline void | ||
206 | affs_set_blocksize(struct super_block *sb, int size) | ||
207 | { | ||
208 | sb_set_blocksize(sb, size); | ||
209 | } | ||
210 | static inline struct buffer_head * | ||
211 | affs_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 | } | ||
218 | static inline struct buffer_head * | ||
219 | affs_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 | } | ||
226 | static inline struct buffer_head * | ||
227 | affs_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 | } | ||
241 | static inline struct buffer_head * | ||
242 | affs_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 | } | ||
254 | static inline void | ||
255 | affs_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 | |||
262 | static inline void | ||
263 | affs_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 | } | ||
268 | static inline void | ||
269 | affs_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 | |||
275 | static inline void | ||
276 | affs_lock_link(struct inode *inode) | ||
277 | { | ||
278 | down(&AFFS_I(inode)->i_link_lock); | ||
279 | } | ||
280 | static inline void | ||
281 | affs_unlock_link(struct inode *inode) | ||
282 | { | ||
283 | up(&AFFS_I(inode)->i_link_lock); | ||
284 | } | ||
285 | static inline void | ||
286 | affs_lock_dir(struct inode *inode) | ||
287 | { | ||
288 | down(&AFFS_I(inode)->i_hash_lock); | ||
289 | } | ||
290 | static inline void | ||
291 | affs_unlock_dir(struct inode *inode) | ||
292 | { | ||
293 | up(&AFFS_I(inode)->i_hash_lock); | ||
294 | } | ||
295 | static inline void | ||
296 | affs_lock_ext(struct inode *inode) | ||
297 | { | ||
298 | down(&AFFS_I(inode)->i_ext_lock); | ||
299 | } | ||
300 | static inline void | ||
301 | affs_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 | |||
13 | extern struct timezone sys_tz; | ||
14 | |||
15 | static 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 | |||
26 | int | ||
27 | affs_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 | |||
75 | int | ||
76 | affs_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 | |||
124 | static void | ||
125 | affs_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 | |||
148 | static int | ||
149 | affs_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; | ||
223 | done: | ||
224 | affs_brelse(link_bh); | ||
225 | affs_brelse(bh); | ||
226 | return retval; | ||
227 | } | ||
228 | |||
229 | |||
230 | static int | ||
231 | affs_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; | ||
247 | not_empty: | ||
248 | affs_brelse(bh); | ||
249 | done: | ||
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 | |||
263 | int | ||
264 | affs_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 | |||
318 | done: | ||
319 | affs_brelse(bh); | ||
320 | return retval; | ||
321 | |||
322 | done_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 | |||
335 | u32 | ||
336 | affs_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 | |||
353 | void | ||
354 | affs_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 | |||
368 | void | ||
369 | secs_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 | |||
387 | mode_t | ||
388 | prot_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 | |||
414 | void | ||
415 | mode_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 | |||
442 | void | ||
443 | affs_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 | |||
458 | void | ||
459 | affs_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 | |||
473 | int | ||
474 | affs_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 | |||
501 | int | ||
502 | affs_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 | |||
14 | static int nibblemap[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 }; | ||
15 | |||
16 | static u32 | ||
17 | affs_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 | |||
36 | u32 | ||
37 | affs_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 | |||
60 | void | ||
61 | affs_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 | |||
111 | err_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 | |||
116 | err_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 | |||
123 | err_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 | |||
137 | u32 | ||
138 | affs_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 | |||
176 | find_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 | |||
192 | find_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 | |||
227 | find_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 | |||
257 | err_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; | ||
261 | err_full: | ||
262 | up(&sbi->s_bmlock); | ||
263 | pr_debug("failed\n"); | ||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | int 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 | |||
372 | out: | ||
373 | affs_brelse(bh); | ||
374 | affs_brelse(bmap_bh); | ||
375 | return res; | ||
376 | } | ||
377 | |||
378 | void 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 | |||
18 | static int affs_readdir(struct file *, void *, filldir_t); | ||
19 | |||
20 | struct 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 | */ | ||
29 | struct 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 | |||
41 | static int | ||
42 | affs_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; | ||
122 | inside: | ||
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 | } | ||
143 | readdir_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 | |||
149 | readdir_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 | |||
21 | static int affs_grow_extcache(struct inode *inode, u32 lc_idx); | ||
22 | static struct buffer_head *affs_alloc_extblock(struct inode *inode, struct buffer_head *bh, u32 ext); | ||
23 | static inline struct buffer_head *affs_get_extblock(struct inode *inode, u32 ext); | ||
24 | static struct buffer_head *affs_get_extblock_slow(struct inode *inode, u32 ext); | ||
25 | static ssize_t affs_file_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos); | ||
26 | static int affs_file_open(struct inode *inode, struct file *filp); | ||
27 | static int affs_file_release(struct inode *inode, struct file *filp); | ||
28 | |||
29 | struct 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 | |||
40 | struct inode_operations affs_file_inode_operations = { | ||
41 | .truncate = affs_truncate, | ||
42 | .setattr = affs_notify_change, | ||
43 | }; | ||
44 | |||
45 | static int | ||
46 | affs_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 | |||
55 | static int | ||
56 | affs_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 | |||
68 | static int | ||
69 | affs_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 | |||
133 | err: | ||
134 | // lock cache | ||
135 | return -EIO; | ||
136 | } | ||
137 | |||
138 | static struct buffer_head * | ||
139 | affs_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 | |||
176 | static inline struct buffer_head * | ||
177 | affs_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 | |||
190 | static struct buffer_head * | ||
191 | affs_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 | |||
237 | again: | ||
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]; | ||
277 | find_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 | |||
295 | read_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 | |||
303 | store_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 | |||
312 | err_bread: | ||
313 | affs_brelse(bh); | ||
314 | return ERR_PTR(-EIO); | ||
315 | } | ||
316 | |||
317 | static int | ||
318 | affs_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 | |||
377 | err_big: | ||
378 | affs_error(inode->i_sb,"get_block","strange block request %d", block); | ||
379 | return -EIO; | ||
380 | err_ext: | ||
381 | // unlock cache | ||
382 | affs_unlock_ext(inode); | ||
383 | return PTR_ERR(ext_bh); | ||
384 | err_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 | |||
393 | static int affs_writepage(struct page *page, struct writeback_control *wbc) | ||
394 | { | ||
395 | return block_write_full_page(page, affs_get_block, wbc); | ||
396 | } | ||
397 | static int affs_readpage(struct file *file, struct page *page) | ||
398 | { | ||
399 | return block_read_full_page(page, affs_get_block); | ||
400 | } | ||
401 | static 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 | } | ||
406 | static sector_t _affs_bmap(struct address_space *mapping, sector_t block) | ||
407 | { | ||
408 | return generic_block_bmap(mapping,block,affs_get_block); | ||
409 | } | ||
410 | struct 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 | |||
419 | static inline struct buffer_head * | ||
420 | affs_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 | |||
438 | static inline struct buffer_head * | ||
439 | affs_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 | |||
457 | static inline struct buffer_head * | ||
458 | affs_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 | |||
476 | static ssize_t | ||
477 | affs_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 | |||
491 | static int | ||
492 | affs_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 | |||
529 | static int | ||
530 | affs_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 | |||
594 | out: | ||
595 | inode->i_size = AFFS_I(inode)->mmu_private = newsize; | ||
596 | return PTR_ERR(bh); | ||
597 | } | ||
598 | |||
599 | static int | ||
600 | affs_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 | |||
620 | static 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 | |||
661 | static 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 | |||
763 | done: | ||
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 | |||
771 | out: | ||
772 | bh = prev_bh; | ||
773 | if (!written) | ||
774 | written = PTR_ERR(bh); | ||
775 | goto done; | ||
776 | } | ||
777 | |||
778 | struct 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 | |||
788 | void | ||
789 | affs_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 | |||
803 | void | ||
804 | affs_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 | |||
15 | extern struct inode_operations affs_symlink_inode_operations; | ||
16 | extern struct timezone sys_tz; | ||
17 | |||
18 | void | ||
19 | affs_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 | |||
159 | bad_inode: | ||
160 | make_bad_inode(inode); | ||
161 | affs_brelse(bh); | ||
162 | return; | ||
163 | } | ||
164 | |||
165 | int | ||
166 | affs_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 | |||
213 | int | ||
214 | affs_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); | ||
237 | out: | ||
238 | return error; | ||
239 | } | ||
240 | |||
241 | void | ||
242 | affs_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 | |||
254 | void | ||
255 | affs_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 | |||
265 | void | ||
266 | affs_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 | |||
282 | struct inode * | ||
283 | affs_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 | |||
326 | err_bh: | ||
327 | affs_free_block(sb, block); | ||
328 | err_block: | ||
329 | iput(inode); | ||
330 | err_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 | |||
339 | int | ||
340 | affs_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); | ||
402 | done: | ||
403 | affs_brelse(inode_bh); | ||
404 | affs_brelse(bh); | ||
405 | return retval; | ||
406 | err: | ||
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 | |||
13 | typedef int (*toupper_t)(int); | ||
14 | |||
15 | static int affs_toupper(int ch); | ||
16 | static int affs_hash_dentry(struct dentry *, struct qstr *); | ||
17 | static int affs_compare_dentry(struct dentry *, struct qstr *, struct qstr *); | ||
18 | static int affs_intl_toupper(int ch); | ||
19 | static int affs_intl_hash_dentry(struct dentry *, struct qstr *); | ||
20 | static int affs_intl_compare_dentry(struct dentry *, struct qstr *, struct qstr *); | ||
21 | |||
22 | struct dentry_operations affs_dentry_operations = { | ||
23 | .d_hash = affs_hash_dentry, | ||
24 | .d_compare = affs_compare_dentry, | ||
25 | }; | ||
26 | |||
27 | static 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 | |||
35 | static int | ||
36 | affs_toupper(int ch) | ||
37 | { | ||
38 | return ch >= 'a' && ch <= 'z' ? ch -= ('a' - 'A') : ch; | ||
39 | } | ||
40 | |||
41 | /* International toupper() for DOS\3 ("international") */ | ||
42 | |||
43 | static int | ||
44 | affs_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 | |||
51 | static inline toupper_t | ||
52 | affs_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 | */ | ||
60 | static 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 | |||
80 | static int | ||
81 | affs_hash_dentry(struct dentry *dentry, struct qstr *qstr) | ||
82 | { | ||
83 | return __affs_hash_dentry(dentry, qstr, affs_toupper); | ||
84 | } | ||
85 | static int | ||
86 | affs_intl_hash_dentry(struct dentry *dentry, struct qstr *qstr) | ||
87 | { | ||
88 | return __affs_hash_dentry(dentry, qstr, affs_intl_toupper); | ||
89 | } | ||
90 | |||
91 | static 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 | |||
123 | static int | ||
124 | affs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b) | ||
125 | { | ||
126 | return __affs_compare_dentry(dentry, a, b, affs_toupper); | ||
127 | } | ||
128 | static int | ||
129 | affs_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 | |||
138 | static inline int | ||
139 | affs_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 | |||
157 | int | ||
158 | affs_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 | |||
170 | static struct buffer_head * | ||
171 | affs_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 | |||
199 | struct dentry * | ||
200 | affs_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 | |||
236 | int | ||
237 | affs_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 | |||
245 | int | ||
246 | affs_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 | |||
275 | int | ||
276 | affs_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 | |||
304 | int | ||
305 | affs_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 | |||
313 | int | ||
314 | affs_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 | |||
378 | err: | ||
379 | inode->i_nlink = 0; | ||
380 | mark_inode_dirty(inode); | ||
381 | iput(inode); | ||
382 | return error; | ||
383 | } | ||
384 | |||
385 | int | ||
386 | affs_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 | |||
396 | int | ||
397 | affs_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 | |||
439 | done: | ||
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 | |||
19 | extern struct timezone sys_tz; | ||
20 | |||
21 | static int affs_statfs(struct super_block *sb, struct kstatfs *buf); | ||
22 | static int affs_remount (struct super_block *sb, int *flags, char *data); | ||
23 | |||
24 | static void | ||
25 | affs_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 | |||
47 | static void | ||
48 | affs_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 | |||
69 | static kmem_cache_t * affs_inode_cachep; | ||
70 | |||
71 | static 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 | |||
81 | static void affs_destroy_inode(struct inode *inode) | ||
82 | { | ||
83 | kmem_cache_free(affs_inode_cachep, AFFS_I(inode)); | ||
84 | } | ||
85 | |||
86 | static 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 | |||
98 | static 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 | |||
109 | static 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 | |||
115 | static 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 | |||
129 | enum { | ||
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 | |||
135 | static 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 | |||
154 | static int | ||
155 | parse_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 | |||
258 | static 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 */ | ||
365 | got_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 | */ | ||
462 | out_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 | |||
475 | static int | ||
476 | affs_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 | |||
513 | static int | ||
514 | affs_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 | |||
530 | static 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 | |||
536 | static 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 | |||
544 | static 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; | ||
553 | out: | ||
554 | destroy_inodecache(); | ||
555 | out1: | ||
556 | return err; | ||
557 | } | ||
558 | |||
559 | static void __exit exit_affs_fs(void) | ||
560 | { | ||
561 | unregister_filesystem(&affs_fs_type); | ||
562 | destroy_inodecache(); | ||
563 | } | ||
564 | |||
565 | MODULE_DESCRIPTION("Amiga filesystem support for Linux"); | ||
566 | MODULE_LICENSE("GPL"); | ||
567 | |||
568 | module_init(init_affs_fs) | ||
569 | module_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 | |||
13 | static 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; | ||
62 | fail: | ||
63 | SetPageError(page); | ||
64 | kunmap(page); | ||
65 | unlock_page(page); | ||
66 | return err; | ||
67 | } | ||
68 | |||
69 | struct address_space_operations affs_symlink_aops = { | ||
70 | .readpage = affs_symlink_readpage, | ||
71 | }; | ||
72 | |||
73 | struct 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 | }; | ||