inode.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:12k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

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