|
57 | 57 | #include <linux/minmax.h>
|
58 | 58 | #include <linux/module.h>
|
59 | 59 | #include <linux/nls.h>
|
| 60 | +#include <linux/proc_fs.h> |
60 | 61 | #include <linux/seq_file.h>
|
61 | 62 | #include <linux/statfs.h>
|
62 | 63 |
|
@@ -441,6 +442,103 @@ static int ntfs_fs_reconfigure(struct fs_context *fc)
|
441 | 442 | return 0;
|
442 | 443 | }
|
443 | 444 |
|
| 445 | +#ifdef CONFIG_PROC_FS |
| 446 | +static struct proc_dir_entry *proc_info_root; |
| 447 | + |
| 448 | +/* |
| 449 | + * ntfs3_volinfo: |
| 450 | + * |
| 451 | + * The content of /proc/fs/ntfs3/<dev>/volinfo |
| 452 | + * |
| 453 | + * ntfs3.1 |
| 454 | + * cluster size |
| 455 | + * number of clusters |
| 456 | +*/ |
| 457 | +static int ntfs3_volinfo(struct seq_file *m, void *o) |
| 458 | +{ |
| 459 | + struct super_block *sb = m->private; |
| 460 | + struct ntfs_sb_info *sbi = sb->s_fs_info; |
| 461 | + |
| 462 | + seq_printf(m, "ntfs%d.%d\n%u\n%zu\n", sbi->volume.major_ver, |
| 463 | + sbi->volume.minor_ver, sbi->cluster_size, |
| 464 | + sbi->used.bitmap.nbits); |
| 465 | + |
| 466 | + return 0; |
| 467 | +} |
| 468 | + |
| 469 | +static int ntfs3_volinfo_open(struct inode *inode, struct file *file) |
| 470 | +{ |
| 471 | + return single_open(file, ntfs3_volinfo, pde_data(inode)); |
| 472 | +} |
| 473 | + |
| 474 | +/* read /proc/fs/ntfs3/<dev>/label */ |
| 475 | +static int ntfs3_label_show(struct seq_file *m, void *o) |
| 476 | +{ |
| 477 | + struct super_block *sb = m->private; |
| 478 | + struct ntfs_sb_info *sbi = sb->s_fs_info; |
| 479 | + |
| 480 | + seq_printf(m, "%s\n", sbi->volume.label); |
| 481 | + |
| 482 | + return 0; |
| 483 | +} |
| 484 | + |
| 485 | +/* write /proc/fs/ntfs3/<dev>/label */ |
| 486 | +static ssize_t ntfs3_label_write(struct file *file, const char __user *buffer, |
| 487 | + size_t count, loff_t *ppos) |
| 488 | +{ |
| 489 | + int err; |
| 490 | + struct super_block *sb = pde_data(file_inode(file)); |
| 491 | + struct ntfs_sb_info *sbi = sb->s_fs_info; |
| 492 | + ssize_t ret = count; |
| 493 | + u8 *label = kmalloc(count, GFP_NOFS); |
| 494 | + |
| 495 | + if (!label) |
| 496 | + return -ENOMEM; |
| 497 | + |
| 498 | + if (copy_from_user(label, buffer, ret)) { |
| 499 | + ret = -EFAULT; |
| 500 | + goto out; |
| 501 | + } |
| 502 | + while (ret > 0 && label[ret - 1] == '\n') |
| 503 | + ret -= 1; |
| 504 | + |
| 505 | + err = ntfs_set_label(sbi, label, ret); |
| 506 | + |
| 507 | + if (err < 0) { |
| 508 | + ntfs_err(sb, "failed (%d) to write label", err); |
| 509 | + ret = err; |
| 510 | + goto out; |
| 511 | + } |
| 512 | + |
| 513 | + *ppos += count; |
| 514 | + ret = count; |
| 515 | +out: |
| 516 | + kfree(label); |
| 517 | + return ret; |
| 518 | +} |
| 519 | + |
| 520 | +static int ntfs3_label_open(struct inode *inode, struct file *file) |
| 521 | +{ |
| 522 | + return single_open(file, ntfs3_label_show, pde_data(inode)); |
| 523 | +} |
| 524 | + |
| 525 | +static const struct proc_ops ntfs3_volinfo_fops = { |
| 526 | + .proc_read = seq_read, |
| 527 | + .proc_lseek = seq_lseek, |
| 528 | + .proc_release = single_release, |
| 529 | + .proc_open = ntfs3_volinfo_open, |
| 530 | +}; |
| 531 | + |
| 532 | +static const struct proc_ops ntfs3_label_fops = { |
| 533 | + .proc_read = seq_read, |
| 534 | + .proc_lseek = seq_lseek, |
| 535 | + .proc_release = single_release, |
| 536 | + .proc_open = ntfs3_label_open, |
| 537 | + .proc_write = ntfs3_label_write, |
| 538 | +}; |
| 539 | + |
| 540 | +#endif |
| 541 | + |
444 | 542 | static struct kmem_cache *ntfs_inode_cachep;
|
445 | 543 |
|
446 | 544 | static struct inode *ntfs_alloc_inode(struct super_block *sb)
|
@@ -515,6 +613,16 @@ static void ntfs_put_super(struct super_block *sb)
|
515 | 613 | {
|
516 | 614 | struct ntfs_sb_info *sbi = sb->s_fs_info;
|
517 | 615 |
|
| 616 | +#ifdef CONFIG_PROC_FS |
| 617 | + // Remove /proc/fs/ntfs3/.. |
| 618 | + if (sbi->procdir) { |
| 619 | + remove_proc_entry("label", sbi->procdir); |
| 620 | + remove_proc_entry("volinfo", sbi->procdir); |
| 621 | + remove_proc_entry(sb->s_id, proc_info_root); |
| 622 | + sbi->procdir = NULL; |
| 623 | + } |
| 624 | +#endif |
| 625 | + |
518 | 626 | /* Mark rw ntfs as clear, if possible. */
|
519 | 627 | ntfs_set_state(sbi, NTFS_DIRTY_CLEAR);
|
520 | 628 |
|
@@ -1436,6 +1544,20 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
1436 | 1544 | kfree(boot2);
|
1437 | 1545 | }
|
1438 | 1546 |
|
| 1547 | +#ifdef CONFIG_PROC_FS |
| 1548 | + /* Create /proc/fs/ntfs3/.. */ |
| 1549 | + if (proc_info_root) { |
| 1550 | + struct proc_dir_entry *e = proc_mkdir(sb->s_id, proc_info_root); |
| 1551 | + if (e) { |
| 1552 | + proc_create_data("volinfo", S_IFREG | S_IRUGO, e, |
| 1553 | + &ntfs3_volinfo_fops, sb); |
| 1554 | + proc_create_data("label", S_IFREG | S_IRUGO | S_IWUGO, |
| 1555 | + e, &ntfs3_label_fops, sb); |
| 1556 | + sbi->procdir = e; |
| 1557 | + } |
| 1558 | + } |
| 1559 | +#endif |
| 1560 | + |
1439 | 1561 | return 0;
|
1440 | 1562 |
|
1441 | 1563 | put_inode_out:
|
@@ -1630,6 +1752,12 @@ static int __init init_ntfs_fs(void)
|
1630 | 1752 | if (IS_ENABLED(CONFIG_NTFS3_LZX_XPRESS))
|
1631 | 1753 | pr_info("ntfs3: Read-only LZX/Xpress compression included\n");
|
1632 | 1754 |
|
| 1755 | + |
| 1756 | +#ifdef CONFIG_PROC_FS |
| 1757 | + /* Create "/proc/fs/ntfs3" */ |
| 1758 | + proc_info_root = proc_mkdir("fs/ntfs3", NULL); |
| 1759 | +#endif |
| 1760 | + |
1633 | 1761 | err = ntfs3_init_bitmap();
|
1634 | 1762 | if (err)
|
1635 | 1763 | return err;
|
@@ -1661,6 +1789,12 @@ static void __exit exit_ntfs_fs(void)
|
1661 | 1789 | kmem_cache_destroy(ntfs_inode_cachep);
|
1662 | 1790 | unregister_filesystem(&ntfs_fs_type);
|
1663 | 1791 | ntfs3_exit_bitmap();
|
| 1792 | + |
| 1793 | +#ifdef CONFIG_PROC_FS |
| 1794 | + if (proc_info_root) |
| 1795 | + remove_proc_entry("fs/ntfs3", NULL); |
| 1796 | +#endif |
| 1797 | + |
1664 | 1798 | }
|
1665 | 1799 |
|
1666 | 1800 | MODULE_LICENSE("GPL");
|
|
0 commit comments