aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/inotify.c125
1 files changed, 71 insertions, 54 deletions
diff --git a/fs/inotify.c b/fs/inotify.c
index 54757be888b6..a8a714e48140 100644
--- a/fs/inotify.c
+++ b/fs/inotify.c
@@ -62,8 +62,8 @@ int inotify_max_queued_events;
62 * Lifetimes of the three main data structures--inotify_device, inode, and 62 * Lifetimes of the three main data structures--inotify_device, inode, and
63 * inotify_watch--are managed by reference count. 63 * inotify_watch--are managed by reference count.
64 * 64 *
65 * inotify_device: Lifetime is from open until release. Additional references 65 * inotify_device: Lifetime is from inotify_init() until release. Additional
66 * can bump the count via get_inotify_dev() and drop the count via 66 * references can bump the count via get_inotify_dev() and drop the count via
67 * put_inotify_dev(). 67 * put_inotify_dev().
68 * 68 *
69 * inotify_watch: Lifetime is from create_watch() to destory_watch(). 69 * inotify_watch: Lifetime is from create_watch() to destory_watch().
@@ -75,7 +75,7 @@ int inotify_max_queued_events;
75 */ 75 */
76 76
77/* 77/*
78 * struct inotify_device - represents an open instance of an inotify device 78 * struct inotify_device - represents an inotify instance
79 * 79 *
80 * This structure is protected by the semaphore 'sem'. 80 * This structure is protected by the semaphore 'sem'.
81 */ 81 */
@@ -371,7 +371,7 @@ static int find_inode(const char __user *dirname, struct nameidata *nd)
371 /* you can only watch an inode if you have read permissions on it */ 371 /* you can only watch an inode if you have read permissions on it */
372 error = permission(nd->dentry->d_inode, MAY_READ, NULL); 372 error = permission(nd->dentry->d_inode, MAY_READ, NULL);
373 if (error) 373 if (error)
374 path_release (nd); 374 path_release(nd);
375 return error; 375 return error;
376} 376}
377 377
@@ -387,7 +387,8 @@ static struct inotify_watch *create_watch(struct inotify_device *dev,
387 struct inotify_watch *watch; 387 struct inotify_watch *watch;
388 int ret; 388 int ret;
389 389
390 if (atomic_read(&dev->user->inotify_watches) >= inotify_max_user_watches) 390 if (atomic_read(&dev->user->inotify_watches) >=
391 inotify_max_user_watches)
391 return ERR_PTR(-ENOSPC); 392 return ERR_PTR(-ENOSPC);
392 393
393 watch = kmem_cache_alloc(watch_cachep, GFP_KERNEL); 394 watch = kmem_cache_alloc(watch_cachep, GFP_KERNEL);
@@ -783,15 +784,14 @@ static int inotify_release(struct inode *ignored, struct file *file)
783 inotify_dev_event_dequeue(dev); 784 inotify_dev_event_dequeue(dev);
784 up(&dev->sem); 785 up(&dev->sem);
785 786
786 /* free this device: the put matching the get in inotify_open() */ 787 /* free this device: the put matching the get in inotify_init() */
787 put_inotify_dev(dev); 788 put_inotify_dev(dev);
788 789
789 return 0; 790 return 0;
790} 791}
791 792
792/* 793/*
793 * inotify_ignore - handle the INOTIFY_IGNORE ioctl, asking that a given wd be 794 * inotify_ignore - remove a given wd from this inotify instance.
794 * removed from the device.
795 * 795 *
796 * Can sleep. 796 * Can sleep.
797 */ 797 */
@@ -856,42 +856,40 @@ asmlinkage long sys_inotify_init(void)
856{ 856{
857 struct inotify_device *dev; 857 struct inotify_device *dev;
858 struct user_struct *user; 858 struct user_struct *user;
859 int ret = -ENOTTY; 859 struct file *filp;
860 int fd; 860 int fd, ret;
861 struct file *filp;
862 861
863 fd = get_unused_fd(); 862 fd = get_unused_fd();
864 if (fd < 0) { 863 if (fd < 0)
865 ret = fd; 864 return fd;
866 goto out;
867 }
868 865
869 filp = get_empty_filp(); 866 filp = get_empty_filp();
870 if (!filp) { 867 if (!filp) {
871 put_unused_fd(fd);
872 ret = -ENFILE; 868 ret = -ENFILE;
873 goto out; 869 goto out_put_fd;
874 } 870 }
875 filp->f_op = &inotify_fops;
876 filp->f_vfsmnt = mntget(inotify_mnt);
877 filp->f_dentry = dget(inotify_mnt->mnt_root);
878 filp->f_mapping = filp->f_dentry->d_inode->i_mapping;
879 filp->f_mode = FMODE_READ;
880 filp->f_flags = O_RDONLY;
881 871
882 user = get_uid(current->user); 872 user = get_uid(current->user);
883 873 if (unlikely(atomic_read(&user->inotify_devs) >=
884 if (unlikely(atomic_read(&user->inotify_devs) >= inotify_max_user_instances)) { 874 inotify_max_user_instances)) {
885 ret = -EMFILE; 875 ret = -EMFILE;
886 goto out_err; 876 goto out_free_uid;
887 } 877 }
888 878
889 dev = kmalloc(sizeof(struct inotify_device), GFP_KERNEL); 879 dev = kmalloc(sizeof(struct inotify_device), GFP_KERNEL);
890 if (unlikely(!dev)) { 880 if (unlikely(!dev)) {
891 ret = -ENOMEM; 881 ret = -ENOMEM;
892 goto out_err; 882 goto out_free_uid;
893 } 883 }
894 884
885 filp->f_op = &inotify_fops;
886 filp->f_vfsmnt = mntget(inotify_mnt);
887 filp->f_dentry = dget(inotify_mnt->mnt_root);
888 filp->f_mapping = filp->f_dentry->d_inode->i_mapping;
889 filp->f_mode = FMODE_READ;
890 filp->f_flags = O_RDONLY;
891 filp->private_data = dev;
892
895 idr_init(&dev->idr); 893 idr_init(&dev->idr);
896 INIT_LIST_HEAD(&dev->events); 894 INIT_LIST_HEAD(&dev->events);
897 INIT_LIST_HEAD(&dev->watches); 895 INIT_LIST_HEAD(&dev->watches);
@@ -905,46 +903,50 @@ asmlinkage long sys_inotify_init(void)
905 903
906 get_inotify_dev(dev); 904 get_inotify_dev(dev);
907 atomic_inc(&user->inotify_devs); 905 atomic_inc(&user->inotify_devs);
906 fd_install(fd, filp);
908 907
909 filp->private_data = dev;
910 fd_install (fd, filp);
911 return fd; 908 return fd;
912out_err: 909out_free_uid:
913 put_unused_fd (fd);
914 put_filp (filp);
915 free_uid(user); 910 free_uid(user);
916out: 911 put_filp(filp);
912out_put_fd:
913 put_unused_fd(fd);
917 return ret; 914 return ret;
918} 915}
919 916
920asmlinkage long sys_inotify_add_watch(int fd, const char *path, u32 mask) 917asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask)
921{ 918{
922 struct inotify_watch *watch, *old; 919 struct inotify_watch *watch, *old;
923 struct inode *inode; 920 struct inode *inode;
924 struct inotify_device *dev; 921 struct inotify_device *dev;
925 struct nameidata nd; 922 struct nameidata nd;
926 struct file *filp; 923 struct file *filp;
927 int ret; 924 int ret, fput_needed;
928 925
929 filp = fget(fd); 926 filp = fget_light(fd, &fput_needed);
930 if (!filp) 927 if (unlikely(!filp))
931 return -EBADF; 928 return -EBADF;
932 929
933 dev = filp->private_data; 930 /* verify that this is indeed an inotify instance */
931 if (unlikely(filp->f_op != &inotify_fops)) {
932 ret = -EINVAL;
933 goto fput_and_out;
934 }
934 935
935 ret = find_inode((const char __user*) path, &nd); 936 ret = find_inode(path, &nd);
936 if (ret) 937 if (unlikely(ret))
937 goto fput_and_out; 938 goto fput_and_out;
938 939
939 /* Held in place by reference in nd */ 940 /* inode held in place by reference to nd; dev by fget on fd */
940 inode = nd.dentry->d_inode; 941 inode = nd.dentry->d_inode;
942 dev = filp->private_data;
941 943
942 down(&inode->inotify_sem); 944 down(&inode->inotify_sem);
943 down(&dev->sem); 945 down(&dev->sem);
944 946
945 /* don't let user-space set invalid bits: we don't want flags set */ 947 /* don't let user-space set invalid bits: we don't want flags set */
946 mask &= IN_ALL_EVENTS; 948 mask &= IN_ALL_EVENTS;
947 if (!mask) { 949 if (unlikely(!mask)) {
948 ret = -EINVAL; 950 ret = -EINVAL;
949 goto out; 951 goto out;
950 } 952 }
@@ -971,11 +973,11 @@ asmlinkage long sys_inotify_add_watch(int fd, const char *path, u32 mask)
971 list_add(&watch->i_list, &inode->inotify_watches); 973 list_add(&watch->i_list, &inode->inotify_watches);
972 ret = watch->wd; 974 ret = watch->wd;
973out: 975out:
974 path_release (&nd);
975 up(&dev->sem); 976 up(&dev->sem);
976 up(&inode->inotify_sem); 977 up(&inode->inotify_sem);
978 path_release(&nd);
977fput_and_out: 979fput_and_out:
978 fput(filp); 980 fput_light(filp, fput_needed);
979 return ret; 981 return ret;
980} 982}
981 983
@@ -983,15 +985,23 @@ asmlinkage long sys_inotify_rm_watch(int fd, u32 wd)
983{ 985{
984 struct file *filp; 986 struct file *filp;
985 struct inotify_device *dev; 987 struct inotify_device *dev;
986 int ret; 988 int ret, fput_needed;
987 989
988 filp = fget(fd); 990 filp = fget_light(fd, &fput_needed);
989 if (!filp) 991 if (unlikely(!filp))
990 return -EBADF; 992 return -EBADF;
993
994 /* verify that this is indeed an inotify instance */
995 if (unlikely(filp->f_op != &inotify_fops)) {
996 ret = -EINVAL;
997 goto out;
998 }
999
991 dev = filp->private_data; 1000 dev = filp->private_data;
992 ret = inotify_ignore(dev, wd); 1001 ret = inotify_ignore(dev, wd);
993 fput(filp);
994 1002
1003out:
1004 fput_light(filp, fput_needed);
995 return ret; 1005 return ret;
996} 1006}
997 1007
@@ -1009,17 +1019,24 @@ static struct file_system_type inotify_fs_type = {
1009}; 1019};
1010 1020
1011/* 1021/*
1012 * inotify_init - Our initialization function. Note that we cannnot return 1022 * inotify_setup - Our initialization function. Note that we cannnot return
1013 * error because we have compiled-in VFS hooks. So an (unlikely) failure here 1023 * error because we have compiled-in VFS hooks. So an (unlikely) failure here
1014 * must result in panic(). 1024 * must result in panic().
1015 */ 1025 */
1016static int __init inotify_init(void) 1026static int __init inotify_setup(void)
1017{ 1027{
1018 register_filesystem(&inotify_fs_type); 1028 int ret;
1029
1030 ret = register_filesystem(&inotify_fs_type);
1031 if (unlikely(ret))
1032 panic("inotify: register_filesystem returned %d!\n", ret);
1033
1019 inotify_mnt = kern_mount(&inotify_fs_type); 1034 inotify_mnt = kern_mount(&inotify_fs_type);
1035 if (IS_ERR(inotify_mnt))
1036 panic("inotify: kern_mount ret %ld!\n", PTR_ERR(inotify_mnt));
1020 1037
1021 inotify_max_queued_events = 8192; 1038 inotify_max_queued_events = 16384;
1022 inotify_max_user_instances = 8; 1039 inotify_max_user_instances = 128;
1023 inotify_max_user_watches = 8192; 1040 inotify_max_user_watches = 8192;
1024 1041
1025 atomic_set(&inotify_cookie, 0); 1042 atomic_set(&inotify_cookie, 0);
@@ -1034,4 +1051,4 @@ static int __init inotify_init(void)
1034 return 0; 1051 return 0;
1035} 1052}
1036 1053
1037module_init(inotify_init); 1054module_init(inotify_setup);