1 /*
2  *  linux/fs/umsdos/inode.c
3  *
4  *      Written 1993 by Jacques Gelinas
5  *      Inspired from linux/fs/msdos/... by Werner Almesberger
6  */
7 
8 #include <linux/module.h>
9 
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>
21 #include <linux/pagemap.h>
22 
23 extern struct dentry_operations umsdos_dentry_operations;
24 
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() */
28 
29 static struct dentry *check_pseudo_root(struct super_block *);
30 
31 
UMSDOS_put_inode(struct inode * inode)32 void UMSDOS_put_inode (struct inode *inode)
33 {
34 	PRINTK ((KERN_DEBUG
35 		"put inode %p (%lu) pos %lu count=%d\n"
36 		 ,inode, inode->i_ino
37 		 ,inode->u.umsdos_i.pos
38 		 ,atomic_read(&inode->i_count)));
39 
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)));
42 	}
43 
44 	if (atomic_read(&inode->i_count) == 1)
45 		inode->u.umsdos_i.i_patched = 0;
46 }
47 
48 
UMSDOS_put_super(struct super_block * sb)49 void UMSDOS_put_super (struct super_block *sb)
50 {
51 	Printk ((KERN_DEBUG "UMSDOS_put_super: entering\n"));
52 	if (saved_root && pseudo_root && sb->s_dev == ROOT_DEV) {
53 		shrink_dcache_parent(saved_root);
54 		dput(saved_root);
55 		saved_root = NULL;
56 		pseudo_root = NULL;
57 	}
58 	msdos_put_super (sb);
59 }
60 
61 
62 /*
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.
66  */
umsdos_setup_dir(struct dentry * dir)67 void umsdos_setup_dir(struct dentry *dir)
68 {
69 	struct inode *inode = dir->d_inode;
70 
71 	if (!S_ISDIR(inode->i_mode))
72 		printk(KERN_ERR "umsdos_setup_dir: %s/%s not a dir!\n",
73 			dir->d_parent->d_name.name, dir->d_name.name);
74 
75 	init_waitqueue_head (&inode->u.umsdos_i.dir_info.p);
76 	inode->u.umsdos_i.dir_info.looking = 0;
77 	inode->u.umsdos_i.dir_info.creating = 0;
78 	inode->u.umsdos_i.dir_info.pid = 0;
79 
80 	inode->i_op = &umsdos_rdir_inode_operations;
81 	inode->i_fop = &umsdos_rdir_operations;
82 	if (umsdos_have_emd(dir)) {
83 Printk((KERN_DEBUG "umsdos_setup_dir: %s/%s using EMD\n",
84 dir->d_parent->d_name.name, dir->d_name.name));
85 		inode->i_op = &umsdos_dir_inode_operations;
86 		inode->i_fop = &umsdos_dir_operations;
87 	}
88 }
89 
90 
91 /*
92  * Add some info into an inode so it can find its owner quickly
93  */
umsdos_set_dirinfo_new(struct dentry * dentry,off_t f_pos)94 void umsdos_set_dirinfo_new (struct dentry *dentry, off_t f_pos)
95 {
96 	struct inode *inode = dentry->d_inode;
97 	struct dentry *demd;
98 
99 	inode->u.umsdos_i.pos = f_pos;
100 
101 	/* now check the EMD file */
102 	demd = umsdos_get_emd_dentry(dentry->d_parent);
103 	if (!IS_ERR(demd)) {
104 		dput(demd);
105 	}
106 	return;
107 }
108 
109 static struct inode_operations umsdos_file_inode_operations = {
110 	truncate:	fat_truncate,
111 	setattr:	UMSDOS_notify_change,
112 };
113 
114 static struct inode_operations umsdos_symlink_inode_operations = {
115 	readlink:	page_readlink,
116 	follow_link:	page_follow_link,
117 	setattr:	UMSDOS_notify_change,
118 };
119 
120 /*
121  * Connect the proper tables in the inode and add some info.
122  */
123 /* #Specification: inode / umsdos info
124  * The first time an inode is seen (inode->i_count == 1),
125  * the inode number of the EMD file which controls this inode
126  * is tagged to this inode. It allows operations such as
127  * notify_change to be handled.
128  */
umsdos_patch_dentry_inode(struct dentry * dentry,off_t f_pos)129 void umsdos_patch_dentry_inode(struct dentry *dentry, off_t f_pos)
130 {
131 	struct inode *inode = dentry->d_inode;
132 
133 PRINTK (("umsdos_patch_dentry_inode: inode=%lu\n", inode->i_ino));
134 
135 	/*
136 	 * Classify the inode based on EMD/non-EMD status.
137 	 */
138 PRINTK (("umsdos_patch_inode: call umsdos_set_dirinfo_new(%p,%lu)\n",
139 dentry, f_pos));
140 	umsdos_set_dirinfo_new(dentry, f_pos);
141 
142 	inode->i_op = &umsdos_file_inode_operations;
143 	if (S_ISREG (inode->i_mode)) {
144 		/* address_space operations already set */
145 	} else if (S_ISDIR (inode->i_mode)) {
146 		umsdos_setup_dir(dentry);
147 	} else if (S_ISLNK (inode->i_mode)) {
148 		/* address_space operations already set */
149 		inode->i_op = &umsdos_symlink_inode_operations;
150 	} else
151 		init_special_inode(inode, inode->i_mode,
152 					kdev_t_to_nr(inode->i_rdev));
153 }
154 
155 
156 /*
157  * lock the parent dir before starting ...
158  * also handles hardlink converting
159  */
UMSDOS_notify_change(struct dentry * dentry,struct iattr * attr)160 int UMSDOS_notify_change (struct dentry *dentry, struct iattr *attr)
161 {
162 	struct inode *dir, *inode;
163 	struct umsdos_info info;
164 	struct dentry *temp, *old_dentry = NULL;
165 	int ret;
166 
167 	ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len,
168 				&info);
169 	if (ret)
170 		goto out;
171 	ret = umsdos_findentry (dentry->d_parent, &info, 0);
172 	if (ret) {
173 printk("UMSDOS_notify_change: %s/%s not in EMD, ret=%d\n",
174 dentry->d_parent->d_name.name, dentry->d_name.name, ret);
175 		goto out;
176 	}
177 
178 	if (info.entry.flags & UMSDOS_HLINK) {
179 		/*
180 		 * In order to get the correct (real) inode, we just drop
181 		 * the original dentry.
182 		 */
183 		d_drop(dentry);
184 Printk(("UMSDOS_notify_change: hard link %s/%s, fake=%s\n",
185 dentry->d_parent->d_name.name, dentry->d_name.name, info.fake.fname));
186 
187 		/* Do a real lookup to get the short name dentry */
188 		temp = umsdos_covered(dentry->d_parent, info.fake.fname,
189 						info.fake.len);
190 		ret = PTR_ERR(temp);
191 		if (IS_ERR(temp))
192 			goto out;
193 
194 		/* now resolve the link ... */
195 		temp = umsdos_solve_hlink(temp);
196 		ret = PTR_ERR(temp);
197 		if (IS_ERR(temp))
198 			goto out;
199 		old_dentry = dentry;
200 		dentry = temp;	/* so umsdos_notify_change_locked will operate on that */
201 	}
202 
203 	dir = dentry->d_parent->d_inode;
204 	inode = dentry->d_inode;
205 
206 	ret = inode_change_ok (inode, attr);
207 	if (ret)
208 		goto out;
209 
210 	down(&dir->i_sem);
211 	ret = umsdos_notify_change_locked(dentry, attr);
212 	up(&dir->i_sem);
213 	if (ret == 0)
214 		ret = inode_setattr (inode, attr);
215 out:
216 	if (old_dentry)
217 		dput (dentry);	/* if we had to use fake dentry for hardlinks, dput() it now */
218 	return ret;
219 }
220 
221 
222 /*
223  * Must be called with the parent lock held.
224  */
umsdos_notify_change_locked(struct dentry * dentry,struct iattr * attr)225 int umsdos_notify_change_locked(struct dentry *dentry, struct iattr *attr)
226 {
227 	struct inode *inode = dentry->d_inode;
228 	struct dentry *demd;
229 	struct address_space *mapping;
230 	struct page *page;
231 	int ret = 0;
232 	struct umsdos_dirent *entry;
233 	int offs;
234 
235 Printk(("UMSDOS_notify_change: entering for %s/%s (%d)\n",
236 dentry->d_parent->d_name.name, dentry->d_name.name, inode->u.umsdos_i.i_patched));
237 
238 	if (inode->i_nlink == 0)
239 		goto out;
240 	if (inode->i_ino == UMSDOS_ROOT_INO)
241 		goto out;
242 
243 	/* get the EMD file dentry */
244 	demd = umsdos_get_emd_dentry(dentry->d_parent);
245 	ret = PTR_ERR(demd);
246 	if (IS_ERR(demd))
247 		goto out;
248 	ret = 0;
249 	/* don't do anything if directory is not promoted to umsdos yet */
250 	if (!demd->d_inode) {
251 		Printk((KERN_DEBUG
252 			"UMSDOS_notify_change: no EMD file %s/%s\n",
253 			demd->d_parent->d_name.name, demd->d_name.name));
254 		goto out_dput;
255 	}
256 
257 	/* don't do anything if this is the EMD itself */
258 	if (inode == demd->d_inode)
259 		goto out_dput;
260 
261 	/* This inode is not a EMD file nor an inode used internally
262 	 * by MSDOS, so we can update its status.
263 	 * See emd.c
264 	 */
265 
266 	/* Read only the start of the entry since we don't touch the name */
267 	mapping = demd->d_inode->i_mapping;
268 	offs = inode->u.umsdos_i.pos & ~PAGE_CACHE_MASK;
269 	ret = -ENOMEM;
270 	page=grab_cache_page(mapping,inode->u.umsdos_i.pos>>PAGE_CACHE_SHIFT);
271 	if (!page)
272 		goto out_dput;
273 	ret=mapping->a_ops->prepare_write(NULL,page,offs,offs+UMSDOS_REC_SIZE);
274 	if (ret)
275 		goto out_unlock;
276 	entry = (struct umsdos_dirent *) (page_address(page) + offs);
277 	if (attr->ia_valid & ATTR_UID)
278 		entry->uid = cpu_to_le16(attr->ia_uid);
279 	if (attr->ia_valid & ATTR_GID)
280 		entry->gid = cpu_to_le16(attr->ia_gid);
281 	if (attr->ia_valid & ATTR_MODE)
282 		entry->mode = cpu_to_le16(attr->ia_mode);
283 	if (attr->ia_valid & ATTR_ATIME)
284 		entry->atime = cpu_to_le32(attr->ia_atime);
285 	if (attr->ia_valid & ATTR_MTIME)
286 		entry->mtime = cpu_to_le32(attr->ia_mtime);
287 	if (attr->ia_valid & ATTR_CTIME)
288 		entry->ctime = cpu_to_le32(attr->ia_ctime);
289 	entry->nlink = cpu_to_le16(inode->i_nlink);
290 	ret=mapping->a_ops->commit_write(NULL,page,offs,offs+UMSDOS_REC_SIZE);
291 	if (ret)
292 		printk(KERN_WARNING
293 			"umsdos_notify_change: %s/%s EMD write error, ret=%d\n",
294 			dentry->d_parent->d_name.name, dentry->d_name.name,ret);
295 
296 	/* #Specification: notify_change / msdos fs
297 	 * notify_change operation are done only on the
298 	 * EMD file. The msdos fs is not even called.
299 	 */
300 out_unlock:
301 	UnlockPage(page);
302 	page_cache_release(page);
303 out_dput:
304 	dput(demd);
305 out:
306 	return ret;
307 }
308 
309 
310 /*
311  * Update the disk with the inode content
312  */
UMSDOS_write_inode(struct inode * inode,int wait)313 void UMSDOS_write_inode (struct inode *inode, int wait)
314 {
315 	struct iattr newattrs;
316 
317 	fat_write_inode (inode, wait);
318 	newattrs.ia_mtime = inode->i_mtime;
319 	newattrs.ia_atime = inode->i_atime;
320 	newattrs.ia_ctime = inode->i_ctime;
321 	newattrs.ia_valid = ATTR_MTIME | ATTR_ATIME | ATTR_CTIME;
322 	/*
323 	 * UMSDOS_notify_change is convenient to call here
324 	 * to update the EMD entry associated with this inode.
325 	 * But it has the side effect to re"dirt" the inode.
326 	 */
327 /*
328  * UMSDOS_notify_change (inode, &newattrs);
329 
330  * inode->i_state &= ~I_DIRTY; / * FIXME: this doesn't work.  We need to remove ourselves from list on dirty inodes. /mn/ */
331 }
332 
333 
334 static struct super_operations umsdos_sops =
335 {
336 	write_inode:	UMSDOS_write_inode,
337 	put_inode:	UMSDOS_put_inode,
338 	delete_inode:	fat_delete_inode,
339 	put_super:	UMSDOS_put_super,
340 	statfs:		UMSDOS_statfs,
341 	clear_inode:	fat_clear_inode,
342 };
343 
UMSDOS_statfs(struct super_block * sb,struct statfs * buf)344 int UMSDOS_statfs(struct super_block *sb,struct statfs *buf)
345 {
346 	int ret;
347 	ret = fat_statfs (sb, buf);
348 	if (!ret)
349 		buf->f_namelen = UMSDOS_MAXNAME;
350 	return ret;
351 }
352 
353 /*
354  * Read the super block of an Extended MS-DOS FS.
355  */
UMSDOS_read_super(struct super_block * sb,void * data,int silent)356 struct super_block *UMSDOS_read_super (struct super_block *sb, void *data,
357 				      int silent)
358 {
359 	struct super_block *res;
360 	struct dentry *new_root;
361 
362 	/*
363 	 * Call msdos-fs to mount the disk.
364 	 * Note: this returns res == sb or NULL
365 	 */
366 	res = msdos_read_super (sb, data, silent);
367 
368 	if (!res)
369 		goto out_fail;
370 
371 	printk (KERN_INFO "UMSDOS 0.86k "
372 		"(compatibility level %d.%d, fast msdos)\n",
373 		UMSDOS_VERSION, UMSDOS_RELEASE);
374 
375 	sb->s_op = &umsdos_sops;
376 	MSDOS_SB(sb)->options.dotsOK = 0;	/* disable hidden==dotfile */
377 
378 	/* install our dentry operations ... */
379 	sb->s_root->d_op = &umsdos_dentry_operations;
380 
381 	umsdos_patch_dentry_inode(sb->s_root, 0);
382 
383 	/* Check whether to change to the /linux root */
384 	new_root = check_pseudo_root(sb);
385 
386 	if (new_root) {
387 		/* sanity check */
388 		if (new_root->d_op != &umsdos_dentry_operations)
389 			printk("umsdos_read_super: pseudo-root wrong ops!\n");
390 
391 		pseudo_root = new_root->d_inode;
392 		saved_root = sb->s_root;
393 		printk(KERN_INFO "UMSDOS: changed to alternate root\n");
394 		dget (sb->s_root); sb->s_root = dget(new_root);
395 	}
396 	return sb;
397 
398 out_fail:
399 	printk(KERN_INFO "UMSDOS: msdos_read_super failed, mount aborted.\n");
400 	return NULL;
401 }
402 
403 /*
404  * Check for an alternate root if we're the root device.
405  */
406 
407 extern kdev_t ROOT_DEV;
check_pseudo_root(struct super_block * sb)408 static struct dentry *check_pseudo_root(struct super_block *sb)
409 {
410 	struct dentry *root, *sbin, *init;
411 
412 	/*
413 	 * Check whether we're mounted as the root device.
414 	 * must check like this, because we can be used with initrd
415 	 */
416 
417 	if (sb->s_dev != ROOT_DEV)
418 		goto out_noroot;
419 
420 	/*
421 	 * lookup_dentry needs a (so far non-existent) root.
422 	 */
423 	printk(KERN_INFO "check_pseudo_root: mounted as root\n");
424 	root = lookup_one_len(UMSDOS_PSDROOT_NAME, sb->s_root,UMSDOS_PSDROOT_LEN);
425 	if (IS_ERR(root))
426 		goto out_noroot;
427 
428 	if (!root->d_inode || !S_ISDIR(root->d_inode->i_mode))
429 		goto out_dput;
430 
431 printk(KERN_INFO "check_pseudo_root: found %s/%s\n",
432 root->d_parent->d_name.name, root->d_name.name);
433 
434 	/* look for /sbin/init */
435 	sbin = lookup_one_len("sbin", root, 4);
436 	if (IS_ERR(sbin))
437 		goto out_dput;
438 	if (!sbin->d_inode || !S_ISDIR(sbin->d_inode->i_mode))
439 		goto out_dput_sbin;
440 	init = lookup_one_len("init", sbin, 4);
441 	if (IS_ERR(init))
442 		goto out_dput_sbin;
443 	if (!init->d_inode)
444 		goto out_dput_init;
445 	printk(KERN_INFO "check_pseudo_root: found %s/%s, enabling pseudo-root\n", init->d_parent->d_name.name, init->d_name.name);
446 	dput(sbin);
447 	dput(init);
448 	return root;
449 
450 	/* Alternate root not found ... */
451 out_dput_init:
452 	dput(init);
453 out_dput_sbin:
454 	dput(sbin);
455 out_dput:
456 	dput(root);
457 out_noroot:
458 	return NULL;
459 }
460 
461 
462 static DECLARE_FSTYPE_DEV(umsdos_fs_type, "umsdos", UMSDOS_read_super);
463 
init_umsdos_fs(void)464 static int __init init_umsdos_fs (void)
465 {
466 	return register_filesystem (&umsdos_fs_type);
467 }
468 
exit_umsdos_fs(void)469 static void __exit exit_umsdos_fs (void)
470 {
471 	unregister_filesystem (&umsdos_fs_type);
472 }
473 
474 EXPORT_NO_SYMBOLS;
475 
476 module_init(init_umsdos_fs)
477 module_exit(exit_umsdos_fs)
478 MODULE_LICENSE("GPL");
479