2 * linux/fs/umsdos/inode.c
4 * Written 1993 by Jacques Gelinas
5 * Inspired from linux/fs/msdos/... by Werner Almesberger
8 #include <linux/module.h>
10 #include <linux/init.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
)
39 printk(KERN_ERR
"fill_new_filp: NULL dentry!\n");
41 memset (filp
, 0, sizeof (struct file
));
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
)
53 "put inode %p (%lu) pos %lu count=%d\n"
55 ,inode
->u
.umsdos_i
.pos
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"));
72 shrink_dcache_parent(saved_root
);
73 printk("UMSDOS_put_super: freeing saved root, d_count=%d\n",
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
;
114 inode
->u
.umsdos_i
.pos
= f_pos
;
116 /* now check the EMD file */
117 demd
= umsdos_get_emd_dentry(dentry
->d_parent
);
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",
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
;
153 inode
->i_op
= &umsdos_file_inode_operations_no_bmap
;
156 if (inode
->i_op
->bmap
!= NULL
) {
157 inode
->i_op
= &umsdos_file_inode_operations
;
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
;
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
;
205 ret
= umsdos_notify_change_locked(dentry
, attr
);
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
;
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
);
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
);
231 if (inode
->i_nlink
== 0)
233 if (inode
->i_ino
== UMSDOS_ROOT_INO
)
236 /* get the EMD file dentry */
237 demd
= umsdos_get_emd_dentry(dentry
->d_parent
);
242 if (!demd
->d_inode
) {
244 "UMSDOS_notify_change: no EMD file %s/%s\n",
245 demd
->d_parent
->d_name
.name
, demd
->d_name
.name
);
250 /* don't do anything if this is the EMD itself */
251 if (inode
== demd
->d_inode
)
254 /* This inode is not a EMD file nor an inode used internally
255 * by MSDOS, so we can update its status.
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
);
268 "umsdos_notify_change: %s/%s EMD read error, ret=%d\n",
269 dentry
->d_parent
->d_name
.name
, dentry
->d_name
.name
,ret
);
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
);
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
);
309 inode_setattr (inode
, attr
);
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
,
357 struct super_block
*res
;
358 struct dentry
*new_root
;
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
);
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
);
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
);
406 printk(KERN_INFO
"UMSDOS: msdos_read_super failed, mount aborted.\n");
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
)
425 printk("check_pseudo_root: mounted as root\n");
427 root
= lookup_dentry(UMSDOS_PSDROOT_NAME
, dget(sb
->s_root
), 0);
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);
442 /* check for other files? */
446 printk("check_pseudo_root: found %s/%s, enabling pseudo-root\n",
447 init
->d_parent
->d_name
.name
, init
->d_name
.name
);
451 /* Alternate root not found ... */
459 static struct file_system_type umsdos_fs_type
=
467 __initfunc (int init_umsdos_fs (void))
469 return register_filesystem (&umsdos_fs_type
);
475 int init_module (void)
477 return init_umsdos_fs ();
480 void cleanup_module (void)
482 unregister_filesystem (&umsdos_fs_type
);