super.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:16k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/fs/hpfs/super.c
  3.  *
  4.  *  Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999
  5.  *
  6.  *  mounting, unmounting, error handling
  7.  */
  8. #include <linux/string.h>
  9. #include "hpfs_fn.h"
  10. #include <linux/module.h>
  11. #include <linux/init.h>
  12. /* Mark the filesystem dirty, so that chkdsk checks it when os/2 booted */
  13. static void mark_dirty(struct super_block *s)
  14. {
  15. if (s->s_hpfs_chkdsk && !(s->s_flags & MS_RDONLY)) {
  16. struct buffer_head *bh;
  17. struct hpfs_spare_block *sb;
  18. if ((sb = hpfs_map_sector(s, 17, &bh, 0))) {
  19. sb->dirty = 1;
  20. sb->old_wrote = 0;
  21. mark_buffer_dirty(bh);
  22. brelse(bh);
  23. }
  24. }
  25. }
  26. /* Mark the filesystem clean (mark it dirty for chkdsk if chkdsk==2 or if there
  27.    were errors) */
  28. static void unmark_dirty(struct super_block *s)
  29. {
  30. struct buffer_head *bh;
  31. struct hpfs_spare_block *sb;
  32. if (s->s_flags & MS_RDONLY) return;
  33. if ((sb = hpfs_map_sector(s, 17, &bh, 0))) {
  34. sb->dirty = s->s_hpfs_chkdsk > 1 - s->s_hpfs_was_error;
  35. sb->old_wrote = s->s_hpfs_chkdsk >= 2 && !s->s_hpfs_was_error;
  36. mark_buffer_dirty(bh);
  37. brelse(bh);
  38. }
  39. }
  40. /* Filesystem error... */
  41. #define ERR_BUF_SIZE 1024
  42. void hpfs_error(struct super_block *s, char *m,...)
  43. {
  44. char *buf;
  45. va_list l;
  46. va_start(l, m);
  47. if (!(buf = kmalloc(ERR_BUF_SIZE, GFP_KERNEL)))
  48. printk("HPFS: No memory for error message '%s'n",m);
  49. else if (vsprintf(buf, m, l) >= ERR_BUF_SIZE)
  50. printk("HPFS: Grrrr... Kernel memory corrupted ... going on, but it'll crash very soon :-(n");
  51. printk("HPFS: filesystem error: ");
  52. if (buf) printk("%s", buf);
  53. else printk("%sn",m);
  54. if (!s->s_hpfs_was_error) {
  55. if (s->s_hpfs_err == 2) {
  56. printk("; crashing the system because you wanted itn");
  57. mark_dirty(s);
  58. panic("HPFS panic");
  59. } else if (s->s_hpfs_err == 1) {
  60. if (s->s_flags & MS_RDONLY) printk("; already mounted read-onlyn");
  61. else {
  62. printk("; remounting read-onlyn");
  63. mark_dirty(s);
  64. s->s_flags |= MS_RDONLY;
  65. }
  66. } else if (s->s_flags & MS_RDONLY) printk("; going on - but anything won't be destroyed because it's read-onlyn");
  67. else printk("; corrupted filesystem mounted read/write - your computer will explode within 20 seconds ... but you wanted it so!n");
  68. } else printk("n");
  69. if (buf) kfree(buf);
  70. s->s_hpfs_was_error = 1;
  71. }
  72. /* 
  73.  * A little trick to detect cycles in many hpfs structures and don't let the
  74.  * kernel crash on corrupted filesystem. When first called, set c2 to 0.
  75.  *
  76.  * BTW. chkdsk doesn't detect cycles correctly. When I had 2 lost directories
  77.  * nested each in other, chkdsk locked up happilly.
  78.  */
  79. int hpfs_stop_cycles(struct super_block *s, int key, int *c1, int *c2,
  80. char *msg)
  81. {
  82. if (*c2 && *c1 == key) {
  83. hpfs_error(s, "cycle detected on key %08x in %s", key, msg);
  84. return 1;
  85. }
  86. (*c2)++;
  87. if (!((*c2 - 1) & *c2)) *c1 = key;
  88. return 0;
  89. }
  90. void hpfs_put_super(struct super_block *s)
  91. {
  92. if (s->s_hpfs_cp_table) kfree(s->s_hpfs_cp_table);
  93. if (s->s_hpfs_bmp_dir) kfree(s->s_hpfs_bmp_dir);
  94. unmark_dirty(s);
  95. }
  96. unsigned hpfs_count_one_bitmap(struct super_block *s, secno secno)
  97. {
  98. struct quad_buffer_head qbh;
  99. unsigned *bits;
  100. unsigned i, count;
  101. if (!(bits = hpfs_map_4sectors(s, secno, &qbh, 4))) return 0;
  102. count = 0;
  103. for (i = 0; i < 2048 / sizeof(unsigned); i++) {
  104. unsigned b; 
  105. if (!bits[i]) continue;
  106. for (b = bits[i]; b; b>>=1) count += b & 1;
  107. }
  108. hpfs_brelse4(&qbh);
  109. return count;
  110. }
  111. static unsigned count_bitmaps(struct super_block *s)
  112. {
  113. unsigned n, count, n_bands;
  114. n_bands = (s->s_hpfs_fs_size + 0x3fff) >> 14;
  115. count = 0;
  116. for (n = 0; n < n_bands; n++)
  117. count += hpfs_count_one_bitmap(s, s->s_hpfs_bmp_dir[n]);
  118. return count;
  119. }
  120. int hpfs_statfs(struct super_block *s, struct statfs *buf)
  121. {
  122. /*if (s->s_hpfs_n_free == -1) {*/
  123. s->s_hpfs_n_free = count_bitmaps(s);
  124. s->s_hpfs_n_free_dnodes = hpfs_count_one_bitmap(s, s->s_hpfs_dmap);
  125. /*}*/
  126. buf->f_type = s->s_magic;
  127. buf->f_bsize = 512;
  128. buf->f_blocks = s->s_hpfs_fs_size;
  129. buf->f_bfree = s->s_hpfs_n_free;
  130. buf->f_bavail = s->s_hpfs_n_free;
  131. buf->f_files = s->s_hpfs_dirband_size / 4;
  132. buf->f_ffree = s->s_hpfs_n_free_dnodes;
  133. buf->f_namelen = 254;
  134. return 0;
  135. }
  136. /* Super operations */
  137. static struct super_operations hpfs_sops =
  138. {
  139.         read_inode: hpfs_read_inode,
  140. delete_inode: hpfs_delete_inode,
  141. put_super: hpfs_put_super,
  142. statfs: hpfs_statfs,
  143. remount_fs: hpfs_remount_fs,
  144. };
  145. /*
  146.  * A tiny parser for option strings, stolen from dosfs.
  147.  *
  148.  * Stolen again from read-only hpfs.
  149.  */
  150. int parse_opts(char *opts, uid_t *uid, gid_t *gid, umode_t *umask,
  151.        int *lowercase, int *conv, int *eas, int *chk, int *errs,
  152.        int *chkdsk, int *timeshift)
  153. {
  154. char *p, *rhs;
  155. if (!opts)
  156. return 1;
  157. /*printk("Parsing opts: '%s'n",opts);*/
  158. for (p = strtok(opts, ","); p != 0; p = strtok(0, ",")) {
  159. if ((rhs = strchr(p, '=')) != 0)
  160. *rhs++ = '';
  161. if (!strcmp(p, "help")) return 2;
  162. if (!strcmp(p, "uid")) {
  163. if (!rhs || !*rhs)
  164. return 0;
  165. *uid = simple_strtoul(rhs, &rhs, 0);
  166. if (*rhs)
  167. return 0;
  168. }
  169. else if (!strcmp(p, "gid")) {
  170. if (!rhs || !*rhs)
  171. return 0;
  172. *gid = simple_strtoul(rhs, &rhs, 0);
  173. if (*rhs)
  174. return 0;
  175. }
  176. else if (!strcmp(p, "umask")) {
  177. if (!rhs || !*rhs)
  178. return 0;
  179. *umask = simple_strtoul(rhs, &rhs, 8);
  180. if (*rhs)
  181. return 0;
  182. }
  183. else if (!strcmp(p, "timeshift")) {
  184. int m = 1;
  185. if (!rhs || !*rhs)
  186. return 0;
  187. if (*rhs == '-') m = -1;
  188. if (*rhs == '+' || *rhs == '-') rhs++;
  189. *timeshift = simple_strtoul(rhs, &rhs, 0) * m;
  190. if (*rhs)
  191. return 0;
  192. }
  193. else if (!strcmp(p, "case")) {
  194. if (!rhs || !*rhs)
  195. return 0;
  196. if (!strcmp(rhs, "lower"))
  197. *lowercase = 1;
  198. else if (!strcmp(rhs, "asis"))
  199. *lowercase = 0;
  200. else
  201. return 0;
  202. }
  203. else if (!strcmp(p, "conv")) {
  204. if (!rhs || !*rhs)
  205. return 0;
  206. if (!strcmp(rhs, "binary"))
  207. *conv = CONV_BINARY;
  208. else if (!strcmp(rhs, "text"))
  209. *conv = CONV_TEXT;
  210. else if (!strcmp(rhs, "auto"))
  211. *conv = CONV_AUTO;
  212. else
  213. return 0;
  214. }
  215. else if (!strcmp(p, "check")) {
  216. if (!rhs || !*rhs)
  217. return 0;
  218. if (!strcmp(rhs, "none"))
  219. *chk = 0;
  220. else if (!strcmp(rhs, "normal"))
  221. *chk = 1;
  222. else if (!strcmp(rhs, "strict"))
  223. *chk = 2;
  224. else
  225. return 0;
  226. }
  227. else if (!strcmp(p, "errors")) {
  228. if (!rhs || !*rhs)
  229. return 0;
  230. if (!strcmp(rhs, "continue"))
  231. *errs = 0;
  232. else if (!strcmp(rhs, "remount-ro"))
  233. *errs = 1;
  234. else if (!strcmp(rhs, "panic"))
  235. *errs = 2;
  236. else
  237. return 0;
  238. }
  239. else if (!strcmp(p, "eas")) {
  240. if (!rhs || !*rhs)
  241. return 0;
  242. if (!strcmp(rhs, "no"))
  243. *eas = 0;
  244. else if (!strcmp(rhs, "ro"))
  245. *eas = 1;
  246. else if (!strcmp(rhs, "rw"))
  247. *eas = 2;
  248. else
  249. return 0;
  250. }
  251. else if (!strcmp(p, "chkdsk")) {
  252. if (!rhs || !*rhs)
  253. return 0;
  254. if (!strcmp(rhs, "no"))
  255. *chkdsk = 0;
  256. else if (!strcmp(rhs, "errors"))
  257. *chkdsk = 1;
  258. else if (!strcmp(rhs, "always"))
  259. *chkdsk = 2;
  260. else
  261. return 0;
  262. }
  263. else
  264. return 0;
  265. }
  266. return 1;
  267. }
  268. static inline void hpfs_help(void)
  269. {
  270. printk("n
  271. HPFS filesystem options:n
  272.       help              do not mount and display this textn
  273.       uid=xxx           set uid of files that don't have uid specified in easn
  274.       gid=xxx           set gid of files that don't have gid specified in easn
  275.       umask=xxx         set mode of files that don't have mode specified in easn
  276.       case=lower        lowercase all filesn
  277.       case=asis         do not lowercase files (default)n
  278.       conv=binary       do not convert CR/LF -> LF (default)n
  279.       conv=auto         convert only files with known text extensionsn
  280.       conv=text         convert all filesn
  281.       check=none        no fs checks - kernel may crash on corrupted filesystemn
  282.       check=normal      do some checks - it should not crash (default)n
  283.       check=strict      do extra time-consuming checks, used for debuggingn
  284.       errors=continue   continue on errorsn
  285.       errors=remount-ro remount read-only if errors found (default)n
  286.       errors=panic      panic on errorsn
  287.       chkdsk=no         do not mark fs for chkdsking even if there were errorsn
  288.       chkdsk=errors     mark fs dirty if errors found (default)n
  289.       chkdsk=always     always mark fs dirty - used for debuggingn
  290.       eas=no            ignore extended attributesn
  291.       eas=ro            read but do not write extended attributesn
  292.       eas=rw            r/w eas => enables chmod, chown, mknod, ln -s (default)n
  293.       timeshift=nnn add nnn seconds to file timesn
  294. n");
  295. }
  296. int hpfs_remount_fs(struct super_block *s, int *flags, char *data)
  297. {
  298. uid_t uid;
  299. gid_t gid;
  300. umode_t umask;
  301. int lowercase, conv, eas, chk, errs, chkdsk, timeshift;
  302. int o;
  303. *flags |= MS_NOATIME;
  304. uid = s->s_hpfs_uid; gid = s->s_hpfs_gid;
  305. umask = 0777 & ~s->s_hpfs_mode;
  306. lowercase = s->s_hpfs_lowercase; conv = s->s_hpfs_conv;
  307. eas = s->s_hpfs_eas; chk = s->s_hpfs_chk; chkdsk = s->s_hpfs_chkdsk;
  308. errs = s->s_hpfs_err; timeshift = s->s_hpfs_timeshift;
  309. if (!(o = parse_opts(data, &uid, &gid, &umask, &lowercase, &conv,
  310.     &eas, &chk, &errs, &chkdsk, &timeshift))) {
  311. printk("HPFS: bad mount options.n");
  312.      return 1;
  313. }
  314. if (o == 2) {
  315. hpfs_help();
  316. return 1;
  317. }
  318. if (timeshift != s->s_hpfs_timeshift) {
  319. printk("HPFS: timeshift can't be changed using remount.n");
  320. return 1;
  321. }
  322. unmark_dirty(s);
  323. s->s_hpfs_uid = uid; s->s_hpfs_gid = gid;
  324. s->s_hpfs_mode = 0777 & ~umask;
  325. s->s_hpfs_lowercase = lowercase; s->s_hpfs_conv = conv;
  326. s->s_hpfs_eas = eas; s->s_hpfs_chk = chk; s->s_hpfs_chkdsk = chkdsk;
  327. s->s_hpfs_err = errs; s->s_hpfs_timeshift = timeshift;
  328. if (!(*flags & MS_RDONLY)) mark_dirty(s);
  329. return 0;
  330. }
  331. struct super_block *hpfs_read_super(struct super_block *s, void *options,
  332.     int silent)
  333. {
  334. kdev_t dev;
  335. struct buffer_head *bh0, *bh1, *bh2;
  336. struct hpfs_boot_block *bootblock;
  337. struct hpfs_super_block *superblock;
  338. struct hpfs_spare_block *spareblock;
  339. uid_t uid;
  340. gid_t gid;
  341. umode_t umask;
  342. int lowercase, conv, eas, chk, errs, chkdsk, timeshift;
  343. dnode_secno root_dno;
  344. struct hpfs_dirent *de = NULL;
  345. struct quad_buffer_head qbh;
  346. int o;
  347. s->s_hpfs_bmp_dir = NULL;
  348. s->s_hpfs_cp_table = NULL;
  349. s->s_hpfs_creation_de_lock = s->s_hpfs_rd_inode = 0;
  350. init_waitqueue_head(&s->s_hpfs_creation_de);
  351. init_waitqueue_head(&s->s_hpfs_iget_q);
  352. uid = current->uid;
  353. gid = current->gid;
  354. umask = current->fs->umask;
  355. lowercase = 0;
  356. conv = CONV_BINARY;
  357. eas = 2;
  358. chk = 1;
  359. errs = 1;
  360. chkdsk = 1;
  361. timeshift = 0;
  362. if (!(o = parse_opts(options, &uid, &gid, &umask, &lowercase, &conv,
  363.     &eas, &chk, &errs, &chkdsk, &timeshift))) {
  364. printk("HPFS: bad mount options.n");
  365. goto bail0;
  366. }
  367. if (o==2) {
  368. hpfs_help();
  369. goto bail0;
  370. }
  371. /*s->s_hpfs_mounting = 1;*/
  372. dev = s->s_dev;
  373. set_blocksize(dev, 512);
  374. s->s_hpfs_fs_size = -1;
  375. if (!(bootblock = hpfs_map_sector(s, 0, &bh0, 0))) goto bail1;
  376. if (!(superblock = hpfs_map_sector(s, 16, &bh1, 1))) goto bail2;
  377. if (!(spareblock = hpfs_map_sector(s, 17, &bh2, 0))) goto bail3;
  378. /* Check magics */
  379. if (/*bootblock->magic != BB_MAGIC
  380.     ||*/ superblock->magic != SB_MAGIC
  381.     || spareblock->magic != SP_MAGIC) {
  382. if (!silent) printk("HPFS: Bad magic ... probably not HPFSn");
  383. goto bail4;
  384. }
  385. /* Check version */
  386. if (!(s->s_flags & MS_RDONLY) &&
  387.       superblock->funcversion != 2 && superblock->funcversion != 3) {
  388. printk("HPFS: Bad version %d,%d. Mount readonly to go aroundn",
  389. (int)superblock->version, (int)superblock->funcversion);
  390. printk("HPFS: please try recent version of HPFS driver at http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi and if it still can't understand this format, contact author - mikulas@artax.karlin.mff.cuni.czn");
  391. goto bail4;
  392. }
  393. s->s_flags |= MS_NOATIME;
  394. /* Fill superblock stuff */
  395. s->s_magic = HPFS_SUPER_MAGIC;
  396. s->s_blocksize = 512;
  397. s->s_blocksize_bits = 9;
  398. s->s_op = &hpfs_sops;
  399. s->s_hpfs_root = superblock->root;
  400. s->s_hpfs_fs_size = superblock->n_sectors;
  401. s->s_hpfs_bitmaps = superblock->bitmaps;
  402. s->s_hpfs_dirband_start = superblock->dir_band_start;
  403. s->s_hpfs_dirband_size = superblock->n_dir_band;
  404. s->s_hpfs_dmap = superblock->dir_band_bitmap;
  405. s->s_hpfs_uid = uid;
  406. s->s_hpfs_gid = gid;
  407. s->s_hpfs_mode = 0777 & ~umask;
  408. s->s_hpfs_n_free = -1;
  409. s->s_hpfs_n_free_dnodes = -1;
  410. s->s_hpfs_lowercase = lowercase;
  411. s->s_hpfs_conv = conv;
  412. s->s_hpfs_eas = eas;
  413. s->s_hpfs_chk = chk;
  414. s->s_hpfs_chkdsk = chkdsk;
  415. s->s_hpfs_err = errs;
  416. s->s_hpfs_timeshift = timeshift;
  417. s->s_hpfs_was_error = 0;
  418. s->s_hpfs_cp_table = NULL;
  419. s->s_hpfs_c_bitmap = -1;
  420. /* Load bitmap directory */
  421. if (!(s->s_hpfs_bmp_dir = hpfs_load_bitmap_directory(s, superblock->bitmaps)))
  422. goto bail4;
  423. /* Check for general fs errors*/
  424. if (spareblock->dirty && !spareblock->old_wrote) {
  425. if (errs == 2) {
  426. printk("HPFS: Improperly stopped, not mountedn");
  427. goto bail4;
  428. }
  429. hpfs_error(s, "improperly stopped");
  430. }
  431. if (!(s->s_flags & MS_RDONLY)) {
  432. spareblock->dirty = 1;
  433. spareblock->old_wrote = 0;
  434. mark_buffer_dirty(bh2);
  435. }
  436. if (spareblock->hotfixes_used || spareblock->n_spares_used) {
  437. if (errs >= 2) {
  438. printk("HPFS: Hotfixes not supported here, try chkdskn");
  439. mark_dirty(s);
  440. goto bail4;
  441. }
  442. hpfs_error(s, "hotfixes not supported here, try chkdsk");
  443. if (errs == 0) printk("HPFS: Proceeding, but your filesystem will be probably corrupted by this driver...n");
  444. else printk("HPFS: This driver may read bad files or crash when operating on disk with hotfixes.n");
  445. }
  446. if (spareblock->n_dnode_spares != spareblock->n_dnode_spares_free) {
  447. if (errs >= 2) {
  448. printk("HPFS: Spare dnodes used, try chkdskn");
  449. mark_dirty(s);
  450. goto bail4;
  451. }
  452. hpfs_error(s, "warning: spare dnodes used, try chkdsk");
  453. if (errs == 0) printk("HPFS: Proceeding, but your filesystem could be corrupted if you delete files or directoriesn");
  454. }
  455. if (chk) {
  456. unsigned a;
  457. if (superblock->dir_band_end - superblock->dir_band_start + 1 != superblock->n_dir_band ||
  458.     superblock->dir_band_end < superblock->dir_band_start || superblock->n_dir_band > 0x4000) {
  459. hpfs_error(s, "dir band size mismatch: dir_band_start==%08x, dir_band_end==%08x, n_dir_band==%08x",
  460. superblock->dir_band_start, superblock->dir_band_end, superblock->n_dir_band);
  461. goto bail4;
  462. }
  463. a = s->s_hpfs_dirband_size;
  464. s->s_hpfs_dirband_size = 0;
  465. if (hpfs_chk_sectors(s, superblock->dir_band_start, superblock->n_dir_band, "dir_band") ||
  466.     hpfs_chk_sectors(s, superblock->dir_band_bitmap, 4, "dir_band_bitmap") ||
  467.     hpfs_chk_sectors(s, superblock->bitmaps, 4, "bitmaps")) {
  468. mark_dirty(s);
  469. goto bail4;
  470. }
  471. s->s_hpfs_dirband_size = a;
  472. } else printk("HPFS: You really don't want any checks? You are crazy...n");
  473. /* Load code page table */
  474. if (spareblock->n_code_pages)
  475. if (!(s->s_hpfs_cp_table = hpfs_load_code_page(s, spareblock->code_page_dir)))
  476. printk("HPFS: Warning: code page support is disabledn");
  477. brelse(bh2);
  478. brelse(bh1);
  479. brelse(bh0);
  480. hpfs_lock_iget(s, 1);
  481. s->s_root = d_alloc_root(iget(s, s->s_hpfs_root));
  482. hpfs_unlock_iget(s);
  483. if (!s->s_root || !s->s_root->d_inode) {
  484. printk("HPFS: iget failed. Why???n");
  485. goto bail0;
  486. }
  487. hpfs_set_dentry_operations(s->s_root);
  488. /*
  489.  * find the root directory's . pointer & finish filling in the inode
  490.  */
  491. root_dno = hpfs_fnode_dno(s, s->s_hpfs_root);
  492. if (root_dno)
  493. de = map_dirent(s->s_root->d_inode, root_dno, "0101", 2, NULL, &qbh);
  494. if (!root_dno || !de) hpfs_error(s, "unable to find root dir");
  495. else {
  496. s->s_root->d_inode->i_atime = local_to_gmt(s, de->read_date);
  497. s->s_root->d_inode->i_mtime = local_to_gmt(s, de->write_date);
  498. s->s_root->d_inode->i_ctime = local_to_gmt(s, de->creation_date);
  499. s->s_root->d_inode->i_hpfs_ea_size = de->ea_size;
  500. s->s_root->d_inode->i_hpfs_parent_dir = s->s_root->d_inode->i_ino;
  501. if (s->s_root->d_inode->i_size == -1) s->s_root->d_inode->i_size = 2048;
  502. if (s->s_root->d_inode->i_blocks == -1) s->s_root->d_inode->i_blocks = 5;
  503. }
  504. if (de) hpfs_brelse4(&qbh);
  505. return s;
  506. bail4: brelse(bh2);
  507. bail3: brelse(bh1);
  508. bail2: brelse(bh0);
  509. bail1:
  510. bail0:
  511. if (s->s_hpfs_bmp_dir) kfree(s->s_hpfs_bmp_dir);
  512. if (s->s_hpfs_cp_table) kfree(s->s_hpfs_cp_table);
  513. return NULL;
  514. }
  515. DECLARE_FSTYPE_DEV(hpfs_fs_type, "hpfs", hpfs_read_super);
  516. static int __init init_hpfs_fs(void)
  517. {
  518. return register_filesystem(&hpfs_fs_type);
  519. }
  520. static void __exit exit_hpfs_fs(void)
  521. {
  522. unregister_filesystem(&hpfs_fs_type);
  523. }
  524. EXPORT_NO_SYMBOLS;
  525. module_init(init_hpfs_fs)
  526. module_exit(exit_hpfs_fs)