diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-13 20:03:53 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-13 20:03:53 -0400 |
commit | 8e8bb96d247fc67eb66a2ebcc6fd45787b5a8b15 (patch) | |
tree | 0c775af89ad3a0a634ee64b7f470f722a1290462 /fs | |
parent | cd7945397d4784318668fbbbfa99e4c6fcf30b3b (diff) | |
parent | d5751469f210d2149cc2159ffff66cbeef6da3f2 (diff) |
Merge git://git.samba.org/sfrench/cifs-2.6
Pull CIFS fixes from Steve French.
* git://git.samba.org/sfrench/cifs-2.6:
CIFS: Do not kmalloc under the flocks spinlock
cifs: possible memory leak in xattr.
Diffstat (limited to 'fs')
-rw-r--r-- | fs/cifs/file.c | 69 | ||||
-rw-r--r-- | fs/cifs/xattr.c | 6 |
2 files changed, 59 insertions, 16 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 4dd9283885e7..5e64748a2917 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -920,16 +920,26 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile) | |||
920 | for (lockp = &inode->i_flock; *lockp != NULL; \ | 920 | for (lockp = &inode->i_flock; *lockp != NULL; \ |
921 | lockp = &(*lockp)->fl_next) | 921 | lockp = &(*lockp)->fl_next) |
922 | 922 | ||
923 | struct lock_to_push { | ||
924 | struct list_head llist; | ||
925 | __u64 offset; | ||
926 | __u64 length; | ||
927 | __u32 pid; | ||
928 | __u16 netfid; | ||
929 | __u8 type; | ||
930 | }; | ||
931 | |||
923 | static int | 932 | static int |
924 | cifs_push_posix_locks(struct cifsFileInfo *cfile) | 933 | cifs_push_posix_locks(struct cifsFileInfo *cfile) |
925 | { | 934 | { |
926 | struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); | 935 | struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); |
927 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | 936 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); |
928 | struct file_lock *flock, **before; | 937 | struct file_lock *flock, **before; |
929 | struct cifsLockInfo *lck, *tmp; | 938 | unsigned int count = 0, i = 0; |
930 | int rc = 0, xid, type; | 939 | int rc = 0, xid, type; |
940 | struct list_head locks_to_send, *el; | ||
941 | struct lock_to_push *lck, *tmp; | ||
931 | __u64 length; | 942 | __u64 length; |
932 | struct list_head locks_to_send; | ||
933 | 943 | ||
934 | xid = GetXid(); | 944 | xid = GetXid(); |
935 | 945 | ||
@@ -940,29 +950,55 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile) | |||
940 | return rc; | 950 | return rc; |
941 | } | 951 | } |
942 | 952 | ||
953 | lock_flocks(); | ||
954 | cifs_for_each_lock(cfile->dentry->d_inode, before) { | ||
955 | if ((*before)->fl_flags & FL_POSIX) | ||
956 | count++; | ||
957 | } | ||
958 | unlock_flocks(); | ||
959 | |||
943 | INIT_LIST_HEAD(&locks_to_send); | 960 | INIT_LIST_HEAD(&locks_to_send); |
944 | 961 | ||
962 | /* | ||
963 | * Allocating count locks is enough because no locks can be added to | ||
964 | * the list while we are holding cinode->lock_mutex that protects | ||
965 | * locking operations of this inode. | ||
966 | */ | ||
967 | for (; i < count; i++) { | ||
968 | lck = kmalloc(sizeof(struct lock_to_push), GFP_KERNEL); | ||
969 | if (!lck) { | ||
970 | rc = -ENOMEM; | ||
971 | goto err_out; | ||
972 | } | ||
973 | list_add_tail(&lck->llist, &locks_to_send); | ||
974 | } | ||
975 | |||
976 | i = 0; | ||
977 | el = locks_to_send.next; | ||
945 | lock_flocks(); | 978 | lock_flocks(); |
946 | cifs_for_each_lock(cfile->dentry->d_inode, before) { | 979 | cifs_for_each_lock(cfile->dentry->d_inode, before) { |
980 | if (el == &locks_to_send) { | ||
981 | /* something is really wrong */ | ||
982 | cERROR(1, "Can't push all brlocks!"); | ||
983 | break; | ||
984 | } | ||
947 | flock = *before; | 985 | flock = *before; |
986 | if ((flock->fl_flags & FL_POSIX) == 0) | ||
987 | continue; | ||
948 | length = 1 + flock->fl_end - flock->fl_start; | 988 | length = 1 + flock->fl_end - flock->fl_start; |
949 | if (flock->fl_type == F_RDLCK || flock->fl_type == F_SHLCK) | 989 | if (flock->fl_type == F_RDLCK || flock->fl_type == F_SHLCK) |
950 | type = CIFS_RDLCK; | 990 | type = CIFS_RDLCK; |
951 | else | 991 | else |
952 | type = CIFS_WRLCK; | 992 | type = CIFS_WRLCK; |
953 | 993 | lck = list_entry(el, struct lock_to_push, llist); | |
954 | lck = cifs_lock_init(flock->fl_start, length, type, | ||
955 | cfile->netfid); | ||
956 | if (!lck) { | ||
957 | rc = -ENOMEM; | ||
958 | goto send_locks; | ||
959 | } | ||
960 | lck->pid = flock->fl_pid; | 994 | lck->pid = flock->fl_pid; |
961 | 995 | lck->netfid = cfile->netfid; | |
962 | list_add_tail(&lck->llist, &locks_to_send); | 996 | lck->length = length; |
997 | lck->type = type; | ||
998 | lck->offset = flock->fl_start; | ||
999 | i++; | ||
1000 | el = el->next; | ||
963 | } | 1001 | } |
964 | |||
965 | send_locks: | ||
966 | unlock_flocks(); | 1002 | unlock_flocks(); |
967 | 1003 | ||
968 | list_for_each_entry_safe(lck, tmp, &locks_to_send, llist) { | 1004 | list_for_each_entry_safe(lck, tmp, &locks_to_send, llist) { |
@@ -979,11 +1015,18 @@ send_locks: | |||
979 | kfree(lck); | 1015 | kfree(lck); |
980 | } | 1016 | } |
981 | 1017 | ||
1018 | out: | ||
982 | cinode->can_cache_brlcks = false; | 1019 | cinode->can_cache_brlcks = false; |
983 | mutex_unlock(&cinode->lock_mutex); | 1020 | mutex_unlock(&cinode->lock_mutex); |
984 | 1021 | ||
985 | FreeXid(xid); | 1022 | FreeXid(xid); |
986 | return rc; | 1023 | return rc; |
1024 | err_out: | ||
1025 | list_for_each_entry_safe(lck, tmp, &locks_to_send, llist) { | ||
1026 | list_del(&lck->llist); | ||
1027 | kfree(lck); | ||
1028 | } | ||
1029 | goto out; | ||
987 | } | 1030 | } |
988 | 1031 | ||
989 | static int | 1032 | static int |
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index 45f07c46f3ed..10d92cf57ab6 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c | |||
@@ -105,7 +105,6 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, | |||
105 | struct cifs_tcon *pTcon; | 105 | struct cifs_tcon *pTcon; |
106 | struct super_block *sb; | 106 | struct super_block *sb; |
107 | char *full_path; | 107 | char *full_path; |
108 | struct cifs_ntsd *pacl; | ||
109 | 108 | ||
110 | if (direntry == NULL) | 109 | if (direntry == NULL) |
111 | return -EIO; | 110 | return -EIO; |
@@ -164,23 +163,24 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, | |||
164 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 163 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
165 | } else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL, | 164 | } else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL, |
166 | strlen(CIFS_XATTR_CIFS_ACL)) == 0) { | 165 | strlen(CIFS_XATTR_CIFS_ACL)) == 0) { |
166 | #ifdef CONFIG_CIFS_ACL | ||
167 | struct cifs_ntsd *pacl; | ||
167 | pacl = kmalloc(value_size, GFP_KERNEL); | 168 | pacl = kmalloc(value_size, GFP_KERNEL); |
168 | if (!pacl) { | 169 | if (!pacl) { |
169 | cFYI(1, "%s: Can't allocate memory for ACL", | 170 | cFYI(1, "%s: Can't allocate memory for ACL", |
170 | __func__); | 171 | __func__); |
171 | rc = -ENOMEM; | 172 | rc = -ENOMEM; |
172 | } else { | 173 | } else { |
173 | #ifdef CONFIG_CIFS_ACL | ||
174 | memcpy(pacl, ea_value, value_size); | 174 | memcpy(pacl, ea_value, value_size); |
175 | rc = set_cifs_acl(pacl, value_size, | 175 | rc = set_cifs_acl(pacl, value_size, |
176 | direntry->d_inode, full_path, CIFS_ACL_DACL); | 176 | direntry->d_inode, full_path, CIFS_ACL_DACL); |
177 | if (rc == 0) /* force revalidate of the inode */ | 177 | if (rc == 0) /* force revalidate of the inode */ |
178 | CIFS_I(direntry->d_inode)->time = 0; | 178 | CIFS_I(direntry->d_inode)->time = 0; |
179 | kfree(pacl); | 179 | kfree(pacl); |
180 | } | ||
180 | #else | 181 | #else |
181 | cFYI(1, "Set CIFS ACL not supported yet"); | 182 | cFYI(1, "Set CIFS ACL not supported yet"); |
182 | #endif /* CONFIG_CIFS_ACL */ | 183 | #endif /* CONFIG_CIFS_ACL */ |
183 | } | ||
184 | } else { | 184 | } else { |
185 | int temp; | 185 | int temp; |
186 | temp = strncmp(ea_name, POSIX_ACL_XATTR_ACCESS, | 186 | temp = strncmp(ea_name, POSIX_ACL_XATTR_ACCESS, |