Linux 2.2.0
[davej-history.git] / fs / umsdos / inode.c
blobef6e56dc3d7a23cee8c2ce040a32955501ffe6c8
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) owner %lu pos %lu dir %lu count=%d\n"
54 ,inode, inode->i_ino
55 ,inode->u.umsdos_i.i_emd_owner, inode->u.umsdos_i.pos
56 ,inode->u.umsdos_i.i_emd_dir, 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->u.umsdos_i.i_emd_dir = 0;
98 inode->i_op = &umsdos_rdir_inode_operations;
99 if (umsdos_have_emd(dir)) {
100 Printk((KERN_DEBUG "umsdos_setup_dir: %s/%s using EMD\n",
101 dir->d_parent->d_name.name, dir->d_name.name));
102 inode->i_op = &umsdos_dir_inode_operations;
108 * Add some info into an inode so it can find its owner quickly
110 void umsdos_set_dirinfo_new (struct dentry *dentry, off_t f_pos)
112 struct inode *inode = dentry->d_inode;
113 struct dentry *demd;
115 inode->u.umsdos_i.i_emd_owner = 0;
116 inode->u.umsdos_i.pos = f_pos;
118 /* now check the EMD file */
119 demd = umsdos_get_emd_dentry(dentry->d_parent);
120 if (!IS_ERR(demd)) {
121 if (demd->d_inode)
122 inode->u.umsdos_i.i_emd_owner = demd->d_inode->i_ino;
123 dput(demd);
125 return;
131 * Connect the proper tables in the inode and add some info.
133 /* #Specification: inode / umsdos info
134 * The first time an inode is seen (inode->i_count == 1),
135 * the inode number of the EMD file which controls this inode
136 * is tagged to this inode. It allows operations such as
137 * notify_change to be handled.
139 void umsdos_patch_dentry_inode(struct dentry *dentry, off_t f_pos)
141 struct inode *inode = dentry->d_inode;
143 PRINTK (("umsdos_patch_dentry_inode: inode=%lu\n", inode->i_ino));
146 * Classify the inode based on EMD/non-EMD status.
148 PRINTK (("umsdos_patch_inode: call umsdos_set_dirinfo_new(%p,%lu)\n",
149 dentry, f_pos));
150 umsdos_set_dirinfo_new(dentry, f_pos);
152 inode->u.umsdos_i.i_emd_dir = 0;
153 if (S_ISREG (inode->i_mode)) {
154 if (MSDOS_SB (inode->i_sb)->cvf_format) {
155 if (MSDOS_SB (inode->i_sb)->cvf_format->flags & CVF_USE_READPAGE) {
156 inode->i_op = &umsdos_file_inode_operations_readpage;
157 } else {
158 inode->i_op = &umsdos_file_inode_operations_no_bmap;
160 } else {
161 if (inode->i_op->bmap != NULL) {
162 inode->i_op = &umsdos_file_inode_operations;
163 } else {
164 inode->i_op = &umsdos_file_inode_operations_no_bmap;
167 } else if (S_ISDIR (inode->i_mode)) {
168 umsdos_setup_dir(dentry);
169 } else if (S_ISLNK (inode->i_mode)) {
170 inode->i_op = &umsdos_symlink_inode_operations;
171 } else if (S_ISCHR (inode->i_mode)) {
172 inode->i_op = &chrdev_inode_operations;
173 } else if (S_ISBLK (inode->i_mode)) {
174 inode->i_op = &blkdev_inode_operations;
175 } else if (S_ISFIFO (inode->i_mode)) {
176 init_fifo (inode);
182 * Load an inode from disk.
184 /* #Specification: Inode / post initialisation
185 * To completely initialise an inode, we need access to the owner
186 * directory, so we can locate more info in the EMD file. This is
187 * not available the first time the inode is accessed, so we use
188 * a value in the inode to tell if it has been finally initialised.
190 * New inodes are obtained by the lookup and create routines, and
191 * each of these must ensure that the inode gets patched.
193 void UMSDOS_read_inode (struct inode *inode)
195 Printk ((KERN_DEBUG "UMSDOS_read_inode %p ino = %lu ",
196 inode, inode->i_ino));
197 msdos_read_inode (inode);
199 /* inode needs patching */
200 inode->u.umsdos_i.i_patched = 0;
204 int umsdos_notify_change_locked(struct dentry *, struct iattr *);
206 * lock the parent dir before starting ...
208 int UMSDOS_notify_change (struct dentry *dentry, struct iattr *attr)
210 struct inode *dir = dentry->d_parent->d_inode;
211 int ret;
213 down(&dir->i_sem);
214 ret = umsdos_notify_change_locked(dentry, attr);
215 up(&dir->i_sem);
216 return ret;
220 * Must be called with the parent lock held.
222 int umsdos_notify_change_locked(struct dentry *dentry, struct iattr *attr)
224 struct inode *inode = dentry->d_inode;
225 struct dentry *demd;
226 int ret;
227 struct file filp;
228 struct umsdos_dirent entry;
230 Printk(("UMSDOS_notify_change: entering for %s/%s (%d)\n",
231 dentry->d_parent->d_name.name, dentry->d_name.name, inode->u.umsdos_i.i_patched));
233 ret = inode_change_ok (inode, attr);
234 if (ret) {
235 printk("UMSDOS_notify_change: %s/%s change not OK, ret=%d\n",
236 dentry->d_parent->d_name.name, dentry->d_name.name, ret);
237 goto out;
240 if (inode->i_nlink == 0)
241 goto out;
242 if (inode->i_ino == UMSDOS_ROOT_INO)
243 goto out;
245 /* get the EMD file dentry */
246 demd = umsdos_get_emd_dentry(dentry->d_parent);
247 ret = PTR_ERR(demd);
248 if (IS_ERR(demd))
249 goto out;
250 ret = -EPERM;
251 if (!demd->d_inode) {
252 printk(KERN_WARNING
253 "UMSDOS_notify_change: no EMD file %s/%s\n",
254 demd->d_parent->d_name.name, demd->d_name.name);
255 goto out_dput;
258 ret = 0;
259 /* don't do anything if this is the EMD itself */
260 if (inode == demd->d_inode)
261 goto out_dput;
263 /* This inode is not a EMD file nor an inode used internally
264 * by MSDOS, so we can update its status.
265 * See emd.c
268 fill_new_filp (&filp, demd);
269 filp.f_pos = inode->u.umsdos_i.pos;
270 Printk(("UMSDOS_notify_change: %s/%s reading at %d\n",
271 dentry->d_parent->d_name.name, dentry->d_name.name, (int) filp.f_pos));
273 /* Read only the start of the entry since we don't touch the name */
274 ret = umsdos_emd_dir_read (&filp, (char *) &entry, UMSDOS_REC_SIZE);
275 if (ret) {
276 printk(KERN_WARNING
277 "umsdos_notify_change: %s/%s EMD read error, ret=%d\n",
278 dentry->d_parent->d_name.name, dentry->d_name.name,ret);
279 goto out_dput;
281 if (attr->ia_valid & ATTR_UID)
282 entry.uid = attr->ia_uid;
283 if (attr->ia_valid & ATTR_GID)
284 entry.gid = attr->ia_gid;
285 if (attr->ia_valid & ATTR_MODE)
286 entry.mode = attr->ia_mode;
287 if (attr->ia_valid & ATTR_ATIME)
288 entry.atime = attr->ia_atime;
289 if (attr->ia_valid & ATTR_MTIME)
290 entry.mtime = attr->ia_mtime;
291 if (attr->ia_valid & ATTR_CTIME)
292 entry.ctime = attr->ia_ctime;
294 entry.nlink = inode->i_nlink;
295 filp.f_pos = inode->u.umsdos_i.pos;
296 ret = umsdos_emd_dir_write (&filp, (char *) &entry, UMSDOS_REC_SIZE);
297 if (ret)
298 printk(KERN_WARNING
299 "umsdos_notify_change: %s/%s EMD write error, ret=%d\n",
300 dentry->d_parent->d_name.name, dentry->d_name.name,ret);
302 Printk (("notify pos %lu ret %d nlink %d ",
303 inode->u.umsdos_i.pos, ret, entry.nlink));
304 /* #Specification: notify_change / msdos fs
305 * notify_change operation are done only on the
306 * EMD file. The msdos fs is not even called.
308 #ifdef UMSDOS_DEBUG_VERBOSE
309 if (entry.flags & UMSDOS_HIDDEN)
310 printk("umsdos_notify_change: %s/%s hidden, nlink=%d, ret=%d\n",
311 dentry->d_parent->d_name.name, dentry->d_name.name, entry.nlink, ret);
312 #endif
314 out_dput:
315 dput(demd);
316 out:
317 if (ret == 0)
318 inode_setattr (inode, attr);
319 return ret;
324 * Update the disk with the inode content
326 void UMSDOS_write_inode (struct inode *inode)
328 struct iattr newattrs;
330 PRINTK (("UMSDOS_write_inode emd %d (FIXME: missing notify_change)\n",
331 inode->u.umsdos_i.i_emd_owner));
332 fat_write_inode (inode);
333 newattrs.ia_mtime = inode->i_mtime;
334 newattrs.ia_atime = inode->i_atime;
335 newattrs.ia_ctime = inode->i_ctime;
336 newattrs.ia_valid = ATTR_MTIME | ATTR_ATIME | ATTR_CTIME;
338 * UMSDOS_notify_change is convenient to call here
339 * to update the EMD entry associated with this inode.
340 * But it has the side effect to re"dirt" the inode.
343 * UMSDOS_notify_change (inode, &newattrs);
345 * inode->i_state &= ~I_DIRTY; / * FIXME: this doesn't work. We need to remove ourselves from list on dirty inodes. /mn/ */
349 static struct super_operations umsdos_sops =
351 UMSDOS_read_inode, /* read_inode */
352 UMSDOS_write_inode, /* write_inode */
353 UMSDOS_put_inode, /* put_inode */
354 fat_delete_inode, /* delete_inode */
355 UMSDOS_notify_change, /* notify_change */
356 UMSDOS_put_super, /* put_super */
357 NULL, /* write_super */
358 fat_statfs, /* statfs */
359 NULL /* remount_fs */
363 * Read the super block of an Extended MS-DOS FS.
365 struct super_block *UMSDOS_read_super (struct super_block *sb, void *data,
366 int silent)
368 struct super_block *res;
369 struct dentry *new_root;
371 MOD_INC_USE_COUNT;
372 MSDOS_SB(sb)->options.isvfat = 0;
374 * Call msdos-fs to mount the disk.
375 * Note: this returns res == sb or NULL
377 res = msdos_read_super (sb, data, silent);
378 if (!res)
379 goto out_fail;
381 printk (KERN_INFO "UMSDOS dentry-pre 0.84 "
382 "(compatibility level %d.%d, fast msdos)\n",
383 UMSDOS_VERSION, UMSDOS_RELEASE);
385 sb->s_op = &umsdos_sops;
386 MSDOS_SB(sb)->options.dotsOK = 0; /* disable hidden==dotfile */
388 /* install our dentry operations ... */
389 sb->s_root->d_op = &umsdos_dentry_operations;
390 umsdos_patch_dentry_inode(sb->s_root, 0);
392 /* Check whether to change to the /linux root */
393 new_root = check_pseudo_root(sb);
395 if (new_root) {
396 /* sanity check */
397 if (new_root->d_op != &umsdos_dentry_operations)
398 printk("umsdos_read_super: pseudo-root wrong ops!\n");
400 pseudo_root = new_root->d_inode;
402 saved_root = sb->s_root;
403 sb->s_root = new_root;
404 printk(KERN_INFO "UMSDOS: changed to alternate root\n");
407 /* if d_count is not 1, mount will fail with -EBUSY! */
408 if (sb->s_root->d_count > 1) {
409 shrink_dcache_sb(sb);
410 if (sb->s_root->d_count > 1) {
411 printk(KERN_ERR "UMSDOS: root count %d > 1 !", sb->s_root->d_count);
414 return sb;
416 out_fail:
417 printk(KERN_INFO "UMSDOS: msdos_read_super failed, mount aborted.\n");
418 sb->s_dev = 0;
419 MOD_DEC_USE_COUNT;
420 return NULL;
424 * Check for an alternate root if we're the root device.
426 static struct dentry *check_pseudo_root(struct super_block *sb)
428 struct dentry *root, *init;
431 * Check whether we're mounted as the root device.
432 * If so, this should be the only superblock.
434 if (sb->s_list.next->next != &sb->s_list)
435 goto out_noroot;
436 printk("check_pseudo_root: mounted as root\n");
438 root = lookup_dentry(UMSDOS_PSDROOT_NAME, dget(sb->s_root), 0);
439 if (IS_ERR(root))
440 goto out_noroot;
441 if (!root->d_inode)
442 goto out_dput;
443 printk("check_pseudo_root: found %s/%s\n",
444 root->d_parent->d_name.name, root->d_name.name);
446 /* look for /sbin/init */
447 init = lookup_dentry("sbin/init", dget(root), 0);
448 if (!IS_ERR(init)) {
449 if (init->d_inode)
450 goto root_ok;
451 dput(init);
453 /* check for other files? */
454 goto out_dput;
456 root_ok:
457 printk("check_pseudo_root: found %s/%s, enabling pseudo-root\n",
458 init->d_parent->d_name.name, init->d_name.name);
459 dput(init);
460 return root;
462 /* Alternate root not found ... */
463 out_dput:
464 dput(root);
465 out_noroot:
466 return NULL;
470 static struct file_system_type umsdos_fs_type =
472 "umsdos",
473 FS_REQUIRES_DEV,
474 UMSDOS_read_super,
475 NULL
478 __initfunc (int init_umsdos_fs (void))
480 return register_filesystem (&umsdos_fs_type);
483 #ifdef MODULE
484 EXPORT_NO_SYMBOLS;
486 int init_module (void)
488 return init_umsdos_fs ();
491 void cleanup_module (void)
493 unregister_filesystem (&umsdos_fs_type);
496 #endif