aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-04-19 19:36:18 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-04-19 19:36:18 -0400
commit9a0e3eea25d3ab267aff9d4eaed83fbe46d989d0 (patch)
treeecd334957a0c62bcd4fe2fe9feea53ba9a6905cf
parent12566cc35d0e68308bde7aad615743d560cb097b (diff)
parent67245ff332064c01b760afa7a384ccda024bfd24 (diff)
Merge branch 'ptmx-cleanup'
Merge the ptmx internal interface cleanup branch. This doesn't change semantics, but it should be a sane basis for eventually getting the multi-instance devpts code into some sane shape where we can get rid of the kernel config option. Which we can hopefully get done next merge window.. * ptmx-cleanup: devpts: clean up interface to pty drivers
-rw-r--r--drivers/tty/pty.c63
-rw-r--r--fs/devpts/inode.c49
-rw-r--r--include/linux/devpts_fs.h34
3 files changed, 64 insertions, 82 deletions
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index e16a49b507ef..0058d9fbf931 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -663,14 +663,14 @@ static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
663/* this is called once with whichever end is closed last */ 663/* this is called once with whichever end is closed last */
664static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty) 664static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
665{ 665{
666 struct inode *ptmx_inode; 666 struct pts_fs_info *fsi;
667 667
668 if (tty->driver->subtype == PTY_TYPE_MASTER) 668 if (tty->driver->subtype == PTY_TYPE_MASTER)
669 ptmx_inode = tty->driver_data; 669 fsi = tty->driver_data;
670 else 670 else
671 ptmx_inode = tty->link->driver_data; 671 fsi = tty->link->driver_data;
672 devpts_kill_index(ptmx_inode, tty->index); 672 devpts_kill_index(fsi, tty->index);
673 devpts_del_ref(ptmx_inode); 673 devpts_put_ref(fsi);
674} 674}
675 675
676static const struct tty_operations ptm_unix98_ops = { 676static const struct tty_operations ptm_unix98_ops = {
@@ -720,6 +720,7 @@ static const struct tty_operations pty_unix98_ops = {
720 720
721static int ptmx_open(struct inode *inode, struct file *filp) 721static int ptmx_open(struct inode *inode, struct file *filp)
722{ 722{
723 struct pts_fs_info *fsi;
723 struct tty_struct *tty; 724 struct tty_struct *tty;
724 struct inode *slave_inode; 725 struct inode *slave_inode;
725 int retval; 726 int retval;
@@ -734,47 +735,41 @@ static int ptmx_open(struct inode *inode, struct file *filp)
734 if (retval) 735 if (retval)
735 return retval; 736 return retval;
736 737
738 fsi = devpts_get_ref(inode, filp);
739 retval = -ENODEV;
740 if (!fsi)
741 goto out_free_file;
742
737 /* find a device that is not in use. */ 743 /* find a device that is not in use. */
738 mutex_lock(&devpts_mutex); 744 mutex_lock(&devpts_mutex);
739 index = devpts_new_index(inode); 745 index = devpts_new_index(fsi);
740 if (index < 0) {
741 retval = index;
742 mutex_unlock(&devpts_mutex);
743 goto err_file;
744 }
745
746 mutex_unlock(&devpts_mutex); 746 mutex_unlock(&devpts_mutex);
747 747
748 mutex_lock(&tty_mutex); 748 retval = index;
749 tty = tty_init_dev(ptm_driver, index); 749 if (index < 0)
750 goto out_put_ref;
750 751
751 if (IS_ERR(tty)) {
752 retval = PTR_ERR(tty);
753 goto out;
754 }
755 752
753 mutex_lock(&tty_mutex);
754 tty = tty_init_dev(ptm_driver, index);
756 /* The tty returned here is locked so we can safely 755 /* The tty returned here is locked so we can safely
757 drop the mutex */ 756 drop the mutex */
758 mutex_unlock(&tty_mutex); 757 mutex_unlock(&tty_mutex);
759 758
760 set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ 759 retval = PTR_ERR(tty);
761 tty->driver_data = inode; 760 if (IS_ERR(tty))
761 goto out;
762 762
763 /* 763 /*
764 * In the case where all references to ptmx inode are dropped and we 764 * From here on out, the tty is "live", and the index and
765 * still have /dev/tty opened pointing to the master/slave pair (ptmx 765 * fsi will be killed/put by the tty_release()
766 * is closed/released before /dev/tty), we must make sure that the inode
767 * is still valid when we call the final pty_unix98_shutdown, thus we
768 * hold an additional reference to the ptmx inode. For the same /dev/tty
769 * last close case, we also need to make sure the super_block isn't
770 * destroyed (devpts instance unmounted), before /dev/tty is closed and
771 * on its release devpts_kill_index is called.
772 */ 766 */
773 devpts_add_ref(inode); 767 set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
768 tty->driver_data = fsi;
774 769
775 tty_add_file(tty, filp); 770 tty_add_file(tty, filp);
776 771
777 slave_inode = devpts_pty_new(inode, 772 slave_inode = devpts_pty_new(fsi,
778 MKDEV(UNIX98_PTY_SLAVE_MAJOR, index), index, 773 MKDEV(UNIX98_PTY_SLAVE_MAJOR, index), index,
779 tty->link); 774 tty->link);
780 if (IS_ERR(slave_inode)) { 775 if (IS_ERR(slave_inode)) {
@@ -793,12 +788,14 @@ static int ptmx_open(struct inode *inode, struct file *filp)
793 return 0; 788 return 0;
794err_release: 789err_release:
795 tty_unlock(tty); 790 tty_unlock(tty);
791 // This will also put-ref the fsi
796 tty_release(inode, filp); 792 tty_release(inode, filp);
797 return retval; 793 return retval;
798out: 794out:
799 mutex_unlock(&tty_mutex); 795 devpts_kill_index(fsi, index);
800 devpts_kill_index(inode, index); 796out_put_ref:
801err_file: 797 devpts_put_ref(fsi);
798out_free_file:
802 tty_free_file(filp); 799 tty_free_file(filp);
803 return retval; 800 return retval;
804} 801}
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 655f21f99160..0af8e7d70d27 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -128,6 +128,7 @@ static const match_table_t tokens = {
128struct pts_fs_info { 128struct pts_fs_info {
129 struct ida allocated_ptys; 129 struct ida allocated_ptys;
130 struct pts_mount_opts mount_opts; 130 struct pts_mount_opts mount_opts;
131 struct super_block *sb;
131 struct dentry *ptmx_dentry; 132 struct dentry *ptmx_dentry;
132}; 133};
133 134
@@ -358,7 +359,7 @@ static const struct super_operations devpts_sops = {
358 .show_options = devpts_show_options, 359 .show_options = devpts_show_options,
359}; 360};
360 361
361static void *new_pts_fs_info(void) 362static void *new_pts_fs_info(struct super_block *sb)
362{ 363{
363 struct pts_fs_info *fsi; 364 struct pts_fs_info *fsi;
364 365
@@ -369,6 +370,7 @@ static void *new_pts_fs_info(void)
369 ida_init(&fsi->allocated_ptys); 370 ida_init(&fsi->allocated_ptys);
370 fsi->mount_opts.mode = DEVPTS_DEFAULT_MODE; 371 fsi->mount_opts.mode = DEVPTS_DEFAULT_MODE;
371 fsi->mount_opts.ptmxmode = DEVPTS_DEFAULT_PTMX_MODE; 372 fsi->mount_opts.ptmxmode = DEVPTS_DEFAULT_PTMX_MODE;
373 fsi->sb = sb;
372 374
373 return fsi; 375 return fsi;
374} 376}
@@ -384,7 +386,7 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
384 s->s_op = &devpts_sops; 386 s->s_op = &devpts_sops;
385 s->s_time_gran = 1; 387 s->s_time_gran = 1;
386 388
387 s->s_fs_info = new_pts_fs_info(); 389 s->s_fs_info = new_pts_fs_info(s);
388 if (!s->s_fs_info) 390 if (!s->s_fs_info)
389 goto fail; 391 goto fail;
390 392
@@ -524,17 +526,14 @@ static struct file_system_type devpts_fs_type = {
524 * to the System V naming convention 526 * to the System V naming convention
525 */ 527 */
526 528
527int devpts_new_index(struct inode *ptmx_inode) 529int devpts_new_index(struct pts_fs_info *fsi)
528{ 530{
529 struct super_block *sb = pts_sb_from_inode(ptmx_inode);
530 struct pts_fs_info *fsi;
531 int index; 531 int index;
532 int ida_ret; 532 int ida_ret;
533 533
534 if (!sb) 534 if (!fsi)
535 return -ENODEV; 535 return -ENODEV;
536 536
537 fsi = DEVPTS_SB(sb);
538retry: 537retry:
539 if (!ida_pre_get(&fsi->allocated_ptys, GFP_KERNEL)) 538 if (!ida_pre_get(&fsi->allocated_ptys, GFP_KERNEL))
540 return -ENOMEM; 539 return -ENOMEM;
@@ -564,11 +563,8 @@ retry:
564 return index; 563 return index;
565} 564}
566 565
567void devpts_kill_index(struct inode *ptmx_inode, int idx) 566void devpts_kill_index(struct pts_fs_info *fsi, int idx)
568{ 567{
569 struct super_block *sb = pts_sb_from_inode(ptmx_inode);
570 struct pts_fs_info *fsi = DEVPTS_SB(sb);
571
572 mutex_lock(&allocated_ptys_lock); 568 mutex_lock(&allocated_ptys_lock);
573 ida_remove(&fsi->allocated_ptys, idx); 569 ida_remove(&fsi->allocated_ptys, idx);
574 pty_count--; 570 pty_count--;
@@ -578,21 +574,25 @@ void devpts_kill_index(struct inode *ptmx_inode, int idx)
578/* 574/*
579 * pty code needs to hold extra references in case of last /dev/tty close 575 * pty code needs to hold extra references in case of last /dev/tty close
580 */ 576 */
581 577struct pts_fs_info *devpts_get_ref(struct inode *ptmx_inode, struct file *file)
582void devpts_add_ref(struct inode *ptmx_inode)
583{ 578{
584 struct super_block *sb = pts_sb_from_inode(ptmx_inode); 579 struct super_block *sb;
580 struct pts_fs_info *fsi;
581
582 sb = pts_sb_from_inode(ptmx_inode);
583 if (!sb)
584 return NULL;
585 fsi = DEVPTS_SB(sb);
586 if (!fsi)
587 return NULL;
585 588
586 atomic_inc(&sb->s_active); 589 atomic_inc(&sb->s_active);
587 ihold(ptmx_inode); 590 return fsi;
588} 591}
589 592
590void devpts_del_ref(struct inode *ptmx_inode) 593void devpts_put_ref(struct pts_fs_info *fsi)
591{ 594{
592 struct super_block *sb = pts_sb_from_inode(ptmx_inode); 595 deactivate_super(fsi->sb);
593
594 iput(ptmx_inode);
595 deactivate_super(sb);
596} 596}
597 597
598/** 598/**
@@ -604,22 +604,21 @@ void devpts_del_ref(struct inode *ptmx_inode)
604 * 604 *
605 * The created inode is returned. Remove it from /dev/pts/ by devpts_pty_kill. 605 * The created inode is returned. Remove it from /dev/pts/ by devpts_pty_kill.
606 */ 606 */
607struct inode *devpts_pty_new(struct inode *ptmx_inode, dev_t device, int index, 607struct inode *devpts_pty_new(struct pts_fs_info *fsi, dev_t device, int index,
608 void *priv) 608 void *priv)
609{ 609{
610 struct dentry *dentry; 610 struct dentry *dentry;
611 struct super_block *sb = pts_sb_from_inode(ptmx_inode); 611 struct super_block *sb;
612 struct inode *inode; 612 struct inode *inode;
613 struct dentry *root; 613 struct dentry *root;
614 struct pts_fs_info *fsi;
615 struct pts_mount_opts *opts; 614 struct pts_mount_opts *opts;
616 char s[12]; 615 char s[12];
617 616
618 if (!sb) 617 if (!fsi)
619 return ERR_PTR(-ENODEV); 618 return ERR_PTR(-ENODEV);
620 619
620 sb = fsi->sb;
621 root = sb->s_root; 621 root = sb->s_root;
622 fsi = DEVPTS_SB(sb);
623 opts = &fsi->mount_opts; 622 opts = &fsi->mount_opts;
624 623
625 inode = new_inode(sb); 624 inode = new_inode(sb);
diff --git a/include/linux/devpts_fs.h b/include/linux/devpts_fs.h
index e0ee0b3000b2..358a4db72a27 100644
--- a/include/linux/devpts_fs.h
+++ b/include/linux/devpts_fs.h
@@ -15,38 +15,24 @@
15 15
16#include <linux/errno.h> 16#include <linux/errno.h>
17 17
18struct pts_fs_info;
19
18#ifdef CONFIG_UNIX98_PTYS 20#ifdef CONFIG_UNIX98_PTYS
19 21
20int devpts_new_index(struct inode *ptmx_inode); 22/* Look up a pts fs info and get a ref to it */
21void devpts_kill_index(struct inode *ptmx_inode, int idx); 23struct pts_fs_info *devpts_get_ref(struct inode *, struct file *);
22void devpts_add_ref(struct inode *ptmx_inode); 24void devpts_put_ref(struct pts_fs_info *);
23void devpts_del_ref(struct inode *ptmx_inode); 25
26int devpts_new_index(struct pts_fs_info *);
27void devpts_kill_index(struct pts_fs_info *, int);
28
24/* mknod in devpts */ 29/* mknod in devpts */
25struct inode *devpts_pty_new(struct inode *ptmx_inode, dev_t device, int index, 30struct inode *devpts_pty_new(struct pts_fs_info *, dev_t, int, void *);
26 void *priv);
27/* get private structure */ 31/* get private structure */
28void *devpts_get_priv(struct inode *pts_inode); 32void *devpts_get_priv(struct inode *pts_inode);
29/* unlink */ 33/* unlink */
30void devpts_pty_kill(struct inode *inode); 34void devpts_pty_kill(struct inode *inode);
31 35
32#else
33
34/* Dummy stubs in the no-pty case */
35static inline int devpts_new_index(struct inode *ptmx_inode) { return -EINVAL; }
36static inline void devpts_kill_index(struct inode *ptmx_inode, int idx) { }
37static inline void devpts_add_ref(struct inode *ptmx_inode) { }
38static inline void devpts_del_ref(struct inode *ptmx_inode) { }
39static inline struct inode *devpts_pty_new(struct inode *ptmx_inode,
40 dev_t device, int index, void *priv)
41{
42 return ERR_PTR(-EINVAL);
43}
44static inline void *devpts_get_priv(struct inode *pts_inode)
45{
46 return NULL;
47}
48static inline void devpts_pty_kill(struct inode *inode) { }
49
50#endif 36#endif
51 37
52 38