Import 2.3.1pre2
[davej-history.git] / fs / umsdos / inode.c
blobad3aff768343b5ddeb903cab48d552c2063f1ffb
1 /*
2 * linux/fs/umsdos/inode.c
4 * Written 1993 by Jacques Gelinas
5 * Inspired from linux/fs/msdos/... by Werner Almesberger
6 */
8 #include <linux/module.h>
10 #include <linux/init.h>
11 #include <linux/fs.h>
12 #include <linux/msdos_fs.h>
13 #include <linux/kernel.h>
14 #include <linux/sched.h>
15 #include <linux/errno.h>
16 #include <asm/uaccess.h>
17 #include <linux/string.h>
18 #include <linux/stat.h>
19 #include <linux/umsdos_fs.h>
20 #include <linux/list.h>
22 extern struct dentry_operations umsdos_dentry_operations;
23 extern struct inode_operations umsdos_rdir_inode_operations;
26 struct dentry *saved_root = NULL; /* Original root if changed */
27 struct inode *pseudo_root = NULL; /* Useful to simulate the pseudo DOS */
28 /* directory. See UMSDOS_readdir_x() */
30 static struct dentry *check_pseudo_root(struct super_block *);
34 * Initialize a private filp
36 void fill_new_filp (struct file *filp, struct dentry *dentry)
38 if (!dentry)
39 printk(KERN_ERR "fill_new_filp: NULL dentry!\n");
41 memset (filp, 0, sizeof (struct file));
42 filp->f_reada = 1;
43 filp->f_flags = O_RDWR;
44 filp->f_dentry = dentry;
45 filp->f_op = &umsdos_file_operations;
50 void UMSDOS_put_inode (struct inode *inode)
52 PRINTK ((KERN_DEBUG
53 "put inode %p (%lu) pos %lu count=%d\n"
54 ,inode, inode->i_ino
55 ,inode->u.umsdos_i.pos
56 ,inode->i_count));
58 if (inode == pseudo_root) {
59 printk (KERN_ERR "Umsdos: Oops releasing pseudo_root."
60 " Notify jacques@solucorp.qc.ca\n");
63 inode->u.umsdos_i.i_patched = 0;
64 fat_put_inode (inode);
68 void UMSDOS_put_super (struct super_block *sb)
70 Printk ((KERN_DEBUG "UMSDOS_put_super: entering\n"));
71 if (saved_root) {
72 shrink_dcache_parent(saved_root);
73 printk("UMSDOS_put_super: freeing saved root, d_count=%d\n",
74 saved_root->d_count);
75 dput(saved_root);
76 saved_root = NULL;
77 pseudo_root = NULL;
79 msdos_put_super (sb);
80 MOD_DEC_USE_COUNT;
85 * Complete the setup of a directory dentry based on its
86 * EMD/non-EMD status. If it has an EMD, then plug the
87 * umsdos function table. If not, use the msdos one.
89 void umsdos_setup_dir(struct dentry *dir)
91 struct inode *inode = dir->d_inode;
93 if (!S_ISDIR(inode->i_mode))
94 printk(KERN_ERR "umsdos_setup_dir: %s/%s not a dir!\n",
95 dir->d_parent->d_name.name, dir->d_name.name);
97 inode->i_op = &umsdos_rdir_inode_operations;
98 if (umsdos_have_emd(dir)) {
99 Printk((KERN_DEBUG "umsdos_setup_dir: %s/%s using EMD\n",
100 dir->d_parent->d_name.name, dir->d_name.name));
101 inode->i_op = &umsdos_dir_inode_operations;
107 * Add some info into an inode so it can find its owner quickly
109 void umsdos_set_dirinfo_new (struct dentry *dentry, off_t f_pos)
111 struct inode *inode = dentry->d_inode;
112 struct dentry *demd;
114 inode->u.umsdos_i.pos = f_pos;
116 /* now check the EMD file */
117 demd = umsdos_get_emd_dentry(dentry->d_parent);
118 if (!IS_ERR(demd)) {
119 dput(demd);
121 return;
127 * Connect the proper tables in the inode and add some info.
129 /* #Specification: inode / umsdos info
130 * The first time an inode is seen (inode->i_count == 1),
131 * the inode number of the EMD file which controls this inode
132 * is tagged to this inode. It allows operations such as
133 * notify_change to be handled.
135 void umsdos_patch_dentry_inode(struct dentry *dentry, off_t f_pos)
137 struct inode *inode = dentry->d_inode;
139 PRINTK (("umsdos_patch_dentry_inode: inode=%lu\n", inode->i_ino));
142 * Classify the inode based on EMD/non-EMD status.
144 PRINTK (("umsdos_patch_inode: call umsdos_set_dirinfo_new(%p,%lu)\n",
145 dentry, f_pos));
146 umsdos_set_dirinfo_new(dentry, f_pos);
148 if (S_ISREG (inode->i_mode)) {
149 if (MSDOS_SB (inode->i_sb)->cvf_format) {
150 if (MSDOS_SB (inode->i_sb)->cvf_format->flags & CVF_USE_READPAGE) {
151 inode->i_op = &umsdos_file_inode_operations_readpage;
152 } else {
153 inode->i_op = &umsdos_file_inode_operations_no_bmap;
155 } else {
156 if (inode->i_op->bmap != NULL) {
157 inode->i_op = &umsdos_file_inode_operations;
158 } else {
159 inode->i_op = &umsdos_file_inode_operations_no_bmap;
162 } else if (S_ISDIR (inode->i_mode)) {
163 umsdos_setup_dir(dentry);
164 } else if (S_ISLNK (inode->i_mode)) {
165 inode->i_op = &umsdos_symlink_inode_operations;
166 } else
167 init_special_inode(inode, inode->i_mode,
168 kdev_t_to_nr(inode->i_rdev));
173 * Load an inode from disk.
175 /* #Specification: Inode / post initialisation
176 * To completely initialise an inode, we need access to the owner
177 * directory, so we can locate more info in the EMD file. This is
178 * not available the first time the inode is accessed, so we use
179 * a value in the inode to tell if it has been finally initialised.
181 * New inodes are obtained by the lookup and create routines, and
182 * each of these must ensure that the inode gets patched.
184 void UMSDOS_read_inode (struct inode *inode)
186 Printk ((KERN_DEBUG "UMSDOS_read_inode %p ino = %lu ",
187 inode, inode->i_ino));
188 msdos_read_inode (inode);
190 /* inode needs patching */
191 inode->u.umsdos_i.i_patched = 0;
195 int umsdos_notify_change_locked(struct dentry *, struct iattr *);
197 * lock the parent dir before starting ...
199 int UMSDOS_notify_change (struct dentry *dentry, struct iattr *attr)
201 struct inode *dir = dentry->d_parent->d_inode;
202 int ret;
204 down(&dir->i_sem);
205 ret = umsdos_notify_change_locked(dentry, attr);
206 up(&dir->i_sem);
207 return ret;
211 * Must be called with the parent lock held.
213 int umsdos_notify_change_locked(struct dentry *dentry, struct iattr *attr)
215 struct inode *inode = dentry->d_inode;
216 struct dentry *demd;
217 int ret;
218 struct file filp;
219 struct umsdos_dirent entry;
221 Printk(("UMSDOS_notify_change: entering for %s/%s (%d)\n",
222 dentry->d_parent->d_name.name, dentry->d_name.name, inode->u.umsdos_i.i_patched));
224 ret = inode_change_ok (inode, attr);
225 if (ret) {
226 printk("UMSDOS_notify_change: %s/%s change not OK, ret=%d\n",
227 dentry->d_parent->d_name.name, dentry->d_name.name, ret);
228 goto out;
231 if (inode->i_nlink == 0)
232 goto out;
233 if (inode->i_ino == UMSDOS_ROOT_INO)
234 goto out;
236 /* get the EMD file dentry */
237 demd = umsdos_get_emd_dentry(dentry->d_parent);
238 ret = PTR_ERR(demd);
239 if (IS_ERR(demd))
240 goto out;
241 ret = -EPERM;
242 if (!demd->d_inode) {
243 printk(KERN_WARNING
244 "UMSDOS_notify_change: no EMD file %s/%s\n",
245 demd->d_parent->d_name.name, demd->d_name.name);
246 goto out_dput;
249 ret = 0;
250 /* don't do anything if this is the EMD itself */
251 if (inode == demd->d_inode)
252 goto out_dput;
254 /* This inode is not a EMD file nor an inode used internally
255 * by MSDOS, so we can update its status.
256 * See emd.c
259 fill_new_filp (&filp, demd);
260 filp.f_pos = inode->u.umsdos_i.pos;
261 Printk(("UMSDOS_notify_change: %s/%s reading at %d\n",
262 dentry->d_parent->d_name.name, dentry->d_name.name, (int) filp.f_pos));
264 /* Read only the start of the entry since we don't touch the name */
265 ret = umsdos_emd_dir_read (&filp, (char *) &entry, UMSDOS_REC_SIZE);
266 if (ret) {
267 printk(KERN_WARNING
268 "umsdos_notify_change: %s/%s EMD read error, ret=%d\n",
269 dentry->d_parent->d_name.name, dentry->d_name.name,ret);
270 goto out_dput;
272 if (attr->ia_valid & ATTR_UID)
273 entry.uid = attr->ia_uid;
274 if (attr->ia_valid & ATTR_GID)
275 entry.gid = attr->ia_gid;
276 if (attr->ia_valid & ATTR_MODE)
277 entry.mode = attr->ia_mode;
278 if (attr->ia_valid & ATTR_ATIME)
279 entry.atime = attr->ia_atime;
280 if (attr->ia_valid & ATTR_MTIME)
281 entry.mtime = attr->ia_mtime;
282 if (attr->ia_valid & ATTR_CTIME)
283 entry.ctime = attr->ia_ctime;
285 entry.nlink = inode->i_nlink;
286 filp.f_pos = inode->u.umsdos_i.pos;
287 ret = umsdos_emd_dir_write (&filp, (char *) &entry, UMSDOS_REC_SIZE);
288 if (ret)
289 printk(KERN_WARNING
290 "umsdos_notify_change: %s/%s EMD write error, ret=%d\n",
291 dentry->d_parent->d_name.name, dentry->d_name.name,ret);
293 Printk (("notify pos %lu ret %d nlink %d ",
294 inode->u.umsdos_i.pos, ret, entry.nlink));
295 /* #Specification: notify_change / msdos fs
296 * notify_change operation are done only on the
297 * EMD file. The msdos fs is not even called.
299 #ifdef UMSDOS_DEBUG_VERBOSE
300 if (entry.flags & UMSDOS_HIDDEN)
301 printk("umsdos_notify_change: %s/%s hidden, nlink=%d, ret=%d\n",
302 dentry->d_parent->d_name.name, dentry->d_name.name, entry.nlink, ret);
303 #endif
305 out_dput:
306 dput(demd);
307 out:
308 if (ret == 0)
309 inode_setattr (inode, attr);
310 return ret;
315 * Update the disk with the inode content
317 void UMSDOS_write_inode (struct inode *inode)
319 struct iattr newattrs;
321 fat_write_inode (inode);
322 newattrs.ia_mtime = inode->i_mtime;
323 newattrs.ia_atime = inode->i_atime;
324 newattrs.ia_ctime = inode->i_ctime;
325 newattrs.ia_valid = ATTR_MTIME | ATTR_ATIME | ATTR_CTIME;
327 * UMSDOS_notify_change is convenient to call here
328 * to update the EMD entry associated with this inode.
329 * But it has the side effect to re"dirt" the inode.
332 * UMSDOS_notify_change (inode, &newattrs);
334 * inode->i_state &= ~I_DIRTY; / * FIXME: this doesn't work. We need to remove ourselves from list on dirty inodes. /mn/ */
338 static struct super_operations umsdos_sops =
340 UMSDOS_read_inode, /* read_inode */
341 UMSDOS_write_inode, /* write_inode */
342 UMSDOS_put_inode, /* put_inode */
343 fat_delete_inode, /* delete_inode */
344 UMSDOS_notify_change, /* notify_change */
345 UMSDOS_put_super, /* put_super */
346 NULL, /* write_super */
347 fat_statfs, /* statfs */
348 NULL /* remount_fs */
352 * Read the super block of an Extended MS-DOS FS.
354 struct super_block *UMSDOS_read_super (struct super_block *sb, void *data,
355 int silent)
357 struct super_block *res;
358 struct dentry *new_root;
360 MOD_INC_USE_COUNT;
361 MSDOS_SB(sb)->options.isvfat = 0;
363 * Call msdos-fs to mount the disk.
364 * Note: this returns res == sb or NULL
366 res = msdos_read_super (sb, data, silent);
367 if (!res)
368 goto out_fail;
370 printk (KERN_INFO "UMSDOS dentry-pre 0.84 "
371 "(compatibility level %d.%d, fast msdos)\n",
372 UMSDOS_VERSION, UMSDOS_RELEASE);
374 sb->s_op = &umsdos_sops;
375 MSDOS_SB(sb)->options.dotsOK = 0; /* disable hidden==dotfile */
377 /* install our dentry operations ... */
378 sb->s_root->d_op = &umsdos_dentry_operations;
379 umsdos_patch_dentry_inode(sb->s_root, 0);
381 /* Check whether to change to the /linux root */
382 new_root = check_pseudo_root(sb);
384 if (new_root) {
385 /* sanity check */
386 if (new_root->d_op != &umsdos_dentry_operations)
387 printk("umsdos_read_super: pseudo-root wrong ops!\n");
389 pseudo_root = new_root->d_inode;
391 saved_root = sb->s_root;
392 sb->s_root = new_root;
393 printk(KERN_INFO "UMSDOS: changed to alternate root\n");
396 /* if d_count is not 1, mount will fail with -EBUSY! */
397 if (sb->s_root->d_count > 1) {
398 shrink_dcache_sb(sb);
399 if (sb->s_root->d_count > 1) {
400 printk(KERN_ERR "UMSDOS: root count %d > 1 !", sb->s_root->d_count);
403 return sb;
405 out_fail:
406 printk(KERN_INFO "UMSDOS: msdos_read_super failed, mount aborted.\n");
407 sb->s_dev = 0;
408 MOD_DEC_USE_COUNT;
409 return NULL;
413 * Check for an alternate root if we're the root device.
415 static struct dentry *check_pseudo_root(struct super_block *sb)
417 struct dentry *root, *init;
420 * Check whether we're mounted as the root device.
421 * If so, this should be the only superblock.
423 if (sb->s_list.next->next != &sb->s_list)
424 goto out_noroot;
425 printk("check_pseudo_root: mounted as root\n");
427 root = lookup_dentry(UMSDOS_PSDROOT_NAME, dget(sb->s_root), 0);
428 if (IS_ERR(root))
429 goto out_noroot;
430 if (!root->d_inode)
431 goto out_dput;
432 printk("check_pseudo_root: found %s/%s\n",
433 root->d_parent->d_name.name, root->d_name.name);
435 /* look for /sbin/init */
436 init = lookup_dentry("sbin/init", dget(root), 0);
437 if (!IS_ERR(init)) {
438 if (init->d_inode)
439 goto root_ok;
440 dput(init);
442 /* check for other files? */
443 goto out_dput;
445 root_ok:
446 printk("check_pseudo_root: found %s/%s, enabling pseudo-root\n",
447 init->d_parent->d_name.name, init->d_name.name);
448 dput(init);
449 return root;
451 /* Alternate root not found ... */
452 out_dput:
453 dput(root);
454 out_noroot:
455 return NULL;
459 static struct file_system_type umsdos_fs_type =
461 "umsdos",
462 FS_REQUIRES_DEV,
463 UMSDOS_read_super,
464 NULL
467 __initfunc (int init_umsdos_fs (void))
469 return register_filesystem (&umsdos_fs_type);
472 #ifdef MODULE
473 EXPORT_NO_SYMBOLS;
475 int init_module (void)
477 return init_umsdos_fs ();
480 void cleanup_module (void)
482 unregister_filesystem (&umsdos_fs_type);
485 #endif