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/time.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>
21 #include <linux/pagemap.h>
23 extern struct dentry_operations umsdos_dentry_operations;
25 struct dentry *saved_root; /* Original root if changed */
26 struct inode *pseudo_root; /* Useful to simulate the pseudo DOS */
27 /* directory. See UMSDOS_readdir_x() */
29 static struct dentry *check_pseudo_root(struct super_block *);
32 void UMSDOS_put_inode (struct inode *inode)
35 "put inode %p (%lu) pos %lu count=%d\n"
38 ,atomic_read(&inode->i_count)));
40 if (inode == pseudo_root) {
41 Printk ((KERN_ERR "Umsdos: debug: releasing pseudo_root - ino=%lu count=%d\n", inode->i_ino, atomic_read(&inode->i_count)));
44 if (atomic_read(&inode->i_count) == 1)
45 UMSDOS_I(inode)->i_patched = 0;
49 void UMSDOS_put_super (struct super_block *sb)
51 Printk ((KERN_DEBUG "UMSDOS_put_super: entering\n"));
52 if (saved_root && pseudo_root && kdev_same(sb->s_dev, ROOT_DEV)) {
53 shrink_dcache_parent(saved_root);
63 * Complete the setup of a directory dentry based on its
64 * EMD/non-EMD status. If it has an EMD, then plug the
65 * umsdos function table. If not, use the msdos one.
67 void umsdos_setup_dir(struct dentry *dir)
69 struct inode *inode = dir->d_inode;
70 struct umsdos_inode_info *ui = UMSDOS_I(inode);
72 if (!S_ISDIR(inode->i_mode))
73 printk(KERN_ERR "umsdos_setup_dir: %s/%s not a dir!\n",
74 dir->d_parent->d_name.name, dir->d_name.name);
76 init_waitqueue_head (&ui->dir_info.p);
77 ui->dir_info.looking = 0;
78 ui->dir_info.creating = 0;
81 inode->i_op = &umsdos_rdir_inode_operations;
82 inode->i_fop = &umsdos_rdir_operations;
83 if (umsdos_have_emd(dir)) {
84 Printk((KERN_DEBUG "umsdos_setup_dir: %s/%s using EMD\n",
85 dir->d_parent->d_name.name, dir->d_name.name));
86 inode->i_op = &umsdos_dir_inode_operations;
87 inode->i_fop = &umsdos_dir_operations;
93 * Add some info into an inode so it can find its owner quickly
95 void umsdos_set_dirinfo_new (struct dentry *dentry, off_t f_pos)
97 struct inode *inode = dentry->d_inode;
100 UMSDOS_I(inode)->pos = f_pos;
102 /* now check the EMD file */
103 demd = umsdos_get_emd_dentry(dentry->d_parent);
110 static struct inode_operations umsdos_file_inode_operations = {
111 .truncate = fat_truncate,
112 .setattr = UMSDOS_notify_change,
115 static struct inode_operations umsdos_symlink_inode_operations = {
116 .readlink = page_readlink,
117 .follow_link = page_follow_link,
118 .setattr = UMSDOS_notify_change,
122 * Connect the proper tables in the inode and add some info.
124 /* #Specification: inode / umsdos info
125 * The first time an inode is seen (inode->i_count == 1),
126 * the inode number of the EMD file which controls this inode
127 * is tagged to this inode. It allows operations such as
128 * notify_change to be handled.
130 void umsdos_patch_dentry_inode(struct dentry *dentry, off_t f_pos)
132 struct inode *inode = dentry->d_inode;
134 PRINTK (("umsdos_patch_dentry_inode: inode=%lu\n", inode->i_ino));
137 * Classify the inode based on EMD/non-EMD status.
139 PRINTK (("umsdos_patch_inode: call umsdos_set_dirinfo_new(%p,%lu)\n",
141 umsdos_set_dirinfo_new(dentry, f_pos);
143 inode->i_op = &umsdos_file_inode_operations;
144 if (S_ISREG (inode->i_mode)) {
145 /* address_space operations already set */
146 } else if (S_ISDIR (inode->i_mode)) {
147 umsdos_setup_dir(dentry);
148 } else if (S_ISLNK (inode->i_mode)) {
149 /* address_space operations already set */
150 inode->i_op = &umsdos_symlink_inode_operations;
152 init_special_inode(inode, inode->i_mode,
153 kdev_t_to_nr(inode->i_rdev));
158 * lock the parent dir before starting ...
159 * also handles hardlink converting
161 int UMSDOS_notify_change (struct dentry *dentry, struct iattr *attr)
163 struct inode *dir, *inode;
164 struct umsdos_info info;
165 struct dentry *temp, *old_dentry = NULL;
170 ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len,
174 ret = umsdos_findentry (dentry->d_parent, &info, 0);
176 printk("UMSDOS_notify_change: %s/%s not in EMD, ret=%d\n",
177 dentry->d_parent->d_name.name, dentry->d_name.name, ret);
181 if (info.entry.flags & UMSDOS_HLINK) {
183 * In order to get the correct (real) inode, we just drop
184 * the original dentry.
187 Printk(("UMSDOS_notify_change: hard link %s/%s, fake=%s\n",
188 dentry->d_parent->d_name.name, dentry->d_name.name, info.fake.fname));
190 /* Do a real lookup to get the short name dentry */
191 temp = umsdos_covered(dentry->d_parent, info.fake.fname,
197 /* now resolve the link ... */
198 temp = umsdos_solve_hlink(temp);
203 dentry = temp; /* so umsdos_notify_change_locked will operate on that */
206 dir = dentry->d_parent->d_inode;
207 inode = dentry->d_inode;
209 ret = inode_change_ok (inode, attr);
213 ret = umsdos_notify_change_locked(dentry, attr);
215 ret = inode_setattr (inode, attr);
218 dput (dentry); /* if we had to use fake dentry for hardlinks, dput() it now */
225 * Must be called with the parent lock held.
227 int umsdos_notify_change_locked(struct dentry *dentry, struct iattr *attr)
229 struct inode *inode = dentry->d_inode;
231 struct address_space *mapping;
234 struct umsdos_dirent *entry;
237 Printk(("UMSDOS_notify_change: entering for %s/%s (%d)\n",
238 dentry->d_parent->d_name.name, dentry->d_name.name, UMSDOS_I(inode)->i_patched));
240 if (inode->i_nlink == 0)
242 if (inode->i_ino == UMSDOS_ROOT_INO)
245 /* get the EMD file dentry */
246 demd = umsdos_get_emd_dentry(dentry->d_parent);
251 /* don't do anything if directory is not promoted to umsdos yet */
252 if (!demd->d_inode) {
254 "UMSDOS_notify_change: no EMD file %s/%s\n",
255 demd->d_parent->d_name.name, demd->d_name.name));
259 /* don't do anything if this is the EMD itself */
260 if (inode == demd->d_inode)
263 /* This inode is not a EMD file nor an inode used internally
264 * by MSDOS, so we can update its status.
268 /* Read only the start of the entry since we don't touch the name */
269 mapping = demd->d_inode->i_mapping;
270 offs = UMSDOS_I(inode)->pos & ~PAGE_CACHE_MASK;
272 page=grab_cache_page(mapping,UMSDOS_I(inode)->pos>>PAGE_CACHE_SHIFT);
275 ret=mapping->a_ops->prepare_write(NULL,page,offs,offs+UMSDOS_REC_SIZE);
278 entry = (struct umsdos_dirent *) (page_address(page) + offs);
279 if (attr->ia_valid & ATTR_UID)
280 entry->uid = cpu_to_le16(attr->ia_uid);
281 if (attr->ia_valid & ATTR_GID)
282 entry->gid = cpu_to_le16(attr->ia_gid);
283 if (attr->ia_valid & ATTR_MODE)
284 entry->mode = cpu_to_le16(attr->ia_mode);
285 if (attr->ia_valid & ATTR_ATIME)
286 entry->atime = cpu_to_le32(attr->ia_atime);
287 if (attr->ia_valid & ATTR_MTIME)
288 entry->mtime = cpu_to_le32(attr->ia_mtime);
289 if (attr->ia_valid & ATTR_CTIME)
290 entry->ctime = cpu_to_le32(attr->ia_ctime);
291 entry->nlink = cpu_to_le16(inode->i_nlink);
292 ret=mapping->a_ops->commit_write(NULL,page,offs,offs+UMSDOS_REC_SIZE);
295 "umsdos_notify_change: %s/%s EMD write error, ret=%d\n",
296 dentry->d_parent->d_name.name, dentry->d_name.name,ret);
298 /* #Specification: notify_change / msdos fs
299 * notify_change operation are done only on the
300 * EMD file. The msdos fs is not even called.
304 page_cache_release(page);
313 * Update the disk with the inode content
315 int UMSDOS_write_inode (struct inode *inode, int wait)
317 struct iattr newattrs;
320 ret = fat_write_inode (inode, wait);
321 newattrs.ia_mtime = inode->i_mtime;
322 newattrs.ia_atime = inode->i_atime;
323 newattrs.ia_ctime = inode->i_ctime;
324 newattrs.ia_valid = ATTR_MTIME | ATTR_ATIME | ATTR_CTIME;
326 * UMSDOS_notify_change is convenient to call here
327 * to update the EMD entry associated with this inode.
328 * But it has the side effect to re"dirt" the inode.
331 * UMSDOS_notify_change (inode, &newattrs);
333 * 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 .write_inode = UMSDOS_write_inode,
341 .put_inode = UMSDOS_put_inode,
342 .delete_inode = fat_delete_inode,
343 .put_super = UMSDOS_put_super,
344 .statfs = UMSDOS_statfs,
345 .clear_inode = fat_clear_inode,
348 int UMSDOS_statfs(struct super_block *sb,struct statfs *buf)
351 ret = fat_statfs (sb, buf);
353 buf->f_namelen = UMSDOS_MAXNAME;
358 * Read the super block of an Extended MS-DOS FS.
360 struct super_block *UMSDOS_read_super (struct super_block *sb, void *data,
363 struct super_block *res;
364 struct dentry *new_root;
367 * Call msdos-fs to mount the disk.
368 * Note: this returns res == sb or NULL
370 MSDOS_SB(sb)->options.isvfat = 0;
371 res = fat_read_super(sb, data, silent, &umsdos_rdir_inode_operations);
377 printk(KERN_INFO "VFS: Can't find a valid "
378 "UMSDOS filesystem on dev %s.\n", sb->s_id);
382 printk (KERN_INFO "UMSDOS 0.86k "
383 "(compatibility level %d.%d, fast msdos)\n",
384 UMSDOS_VERSION, UMSDOS_RELEASE);
386 sb->s_op = &umsdos_sops;
387 MSDOS_SB(sb)->options.dotsOK = 0; /* disable hidden==dotfile */
389 /* install our dentry operations ... */
390 sb->s_root->d_op = &umsdos_dentry_operations;
392 umsdos_patch_dentry_inode(sb->s_root, 0);
394 /* Check whether to change to the /linux root */
395 new_root = check_pseudo_root(sb);
399 if (new_root->d_op != &umsdos_dentry_operations)
400 printk("umsdos_read_super: pseudo-root wrong ops!\n");
402 pseudo_root = new_root->d_inode;
403 saved_root = sb->s_root;
404 printk(KERN_INFO "UMSDOS: changed to alternate root\n");
405 dget (sb->s_root); sb->s_root = dget(new_root);
411 * Check for an alternate root if we're the root device.
414 extern kdev_t ROOT_DEV;
415 static struct dentry *check_pseudo_root(struct super_block *sb)
417 struct dentry *root, *sbin, *init;
420 * Check whether we're mounted as the root device.
421 * must check like this, because we can be used with initrd
424 if (!kdev_same(sb->s_dev, ROOT_DEV))
428 * lookup_dentry needs a (so far non-existent) root.
430 printk(KERN_INFO "check_pseudo_root: mounted as root\n");
431 root = lookup_one_len(UMSDOS_PSDROOT_NAME, sb->s_root,UMSDOS_PSDROOT_LEN);
435 if (!root->d_inode || !S_ISDIR(root->d_inode->i_mode))
438 printk(KERN_INFO "check_pseudo_root: found %s/%s\n",
439 root->d_parent->d_name.name, root->d_name.name);
441 /* look for /sbin/init */
442 sbin = lookup_one_len("sbin", root, 4);
445 if (!sbin->d_inode || !S_ISDIR(sbin->d_inode->i_mode))
447 init = lookup_one_len("init", sbin, 4);
452 printk(KERN_INFO "check_pseudo_root: found %s/%s, enabling pseudo-root\n", init->d_parent->d_name.name, init->d_name.name);
457 /* Alternate root not found ... */
469 static DECLARE_FSTYPE_DEV(umsdos_fs_type, "umsdos", UMSDOS_read_super);
471 static int __init init_umsdos_fs (void)
473 return register_filesystem (&umsdos_fs_type);
476 static void __exit exit_umsdos_fs (void)
478 unregister_filesystem (&umsdos_fs_type);
481 module_init(init_umsdos_fs)
482 module_exit(exit_umsdos_fs)
483 MODULE_LICENSE("GPL");