diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/inotify.c | 125 |
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; |
912 | out_err: | 909 | out_free_uid: |
913 | put_unused_fd (fd); | ||
914 | put_filp (filp); | ||
915 | free_uid(user); | 910 | free_uid(user); |
916 | out: | 911 | put_filp(filp); |
912 | out_put_fd: | ||
913 | put_unused_fd(fd); | ||
917 | return ret; | 914 | return ret; |
918 | } | 915 | } |
919 | 916 | ||
920 | asmlinkage long sys_inotify_add_watch(int fd, const char *path, u32 mask) | 917 | asmlinkage 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; |
973 | out: | 975 | out: |
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); | ||
977 | fput_and_out: | 979 | fput_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 | ||
1003 | out: | ||
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 | */ |
1016 | static int __init inotify_init(void) | 1026 | static 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 | ||
1037 | module_init(inotify_init); | 1054 | module_init(inotify_setup); |