Commit d063389ecf20e5c20be91a0007656deb9fc38a1c
Committed by
Linus Torvalds
1 parent
44db77f33c
Exists in
master
and in
39 other branches
[PATCH] smbfs: remove kmalloc wrapper
Remove the remaining kmalloc() wrapper bits from fs/smbfs/. Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 4 changed files with 12 additions and 81 deletions Inline Diff
fs/smbfs/Makefile
1 | # | 1 | # |
2 | # Makefile for the linux smb-filesystem routines. | 2 | # Makefile for the linux smb-filesystem routines. |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_SMB_FS) += smbfs.o | 5 | obj-$(CONFIG_SMB_FS) += smbfs.o |
6 | 6 | ||
7 | smbfs-objs := proc.o dir.o cache.o sock.o inode.o file.o ioctl.o getopt.o \ | 7 | smbfs-objs := proc.o dir.o cache.o sock.o inode.o file.o ioctl.o getopt.o \ |
8 | symlink.o smbiod.o request.o | 8 | symlink.o smbiod.o request.o |
9 | 9 | ||
10 | # If you want debugging output, you may add these flags to the EXTRA_CFLAGS | 10 | # If you want debugging output, you may add these flags to the EXTRA_CFLAGS |
11 | # SMBFS_PARANOIA should normally be enabled. | 11 | # SMBFS_PARANOIA should normally be enabled. |
12 | 12 | ||
13 | EXTRA_CFLAGS += -DSMBFS_PARANOIA | 13 | EXTRA_CFLAGS += -DSMBFS_PARANOIA |
14 | #EXTRA_CFLAGS += -DSMBFS_DEBUG | 14 | #EXTRA_CFLAGS += -DSMBFS_DEBUG |
15 | #EXTRA_CFLAGS += -DSMBFS_DEBUG_VERBOSE | 15 | #EXTRA_CFLAGS += -DSMBFS_DEBUG_VERBOSE |
16 | #EXTRA_CFLAGS += -DDEBUG_SMB_MALLOC | ||
17 | #EXTRA_CFLAGS += -DDEBUG_SMB_TIMESTAMP | 16 | #EXTRA_CFLAGS += -DDEBUG_SMB_TIMESTAMP |
18 | #EXTRA_CFLAGS += -Werror | 17 | #EXTRA_CFLAGS += -Werror |
19 | 18 | ||
20 | # | 19 | # |
21 | # Maintainer rules | 20 | # Maintainer rules |
22 | # | 21 | # |
23 | 22 | ||
24 | # getopt.c not included. It is intentionally separate | 23 | # getopt.c not included. It is intentionally separate |
25 | SRC = proc.c dir.c cache.c sock.c inode.c file.c ioctl.c smbiod.c request.c \ | 24 | SRC = proc.c dir.c cache.c sock.c inode.c file.c ioctl.c smbiod.c request.c \ |
26 | symlink.c | 25 | symlink.c |
27 | 26 | ||
28 | proto: | 27 | proto: |
29 | -rm -f proto.h | 28 | -rm -f proto.h |
30 | @echo > proto2.h "/*" | 29 | @echo > proto2.h "/*" |
31 | @echo >> proto2.h " * Autogenerated with cproto on: " `date` | 30 | @echo >> proto2.h " * Autogenerated with cproto on: " `date` |
32 | @echo >> proto2.h " */" | 31 | @echo >> proto2.h " */" |
33 | @echo >> proto2.h "" | 32 | @echo >> proto2.h "" |
34 | @echo >> proto2.h "struct smb_request;" | 33 | @echo >> proto2.h "struct smb_request;" |
35 | @echo >> proto2.h "struct sock;" | 34 | @echo >> proto2.h "struct sock;" |
36 | @echo >> proto2.h "struct statfs;" | 35 | @echo >> proto2.h "struct statfs;" |
37 | @echo >> proto2.h "" | 36 | @echo >> proto2.h "" |
38 | cproto -E "gcc -E" -e -v -I $(TOPDIR)/include -DMAKING_PROTO -D__KERNEL__ $(SRC) >> proto2.h | 37 | cproto -E "gcc -E" -e -v -I $(TOPDIR)/include -DMAKING_PROTO -D__KERNEL__ $(SRC) >> proto2.h |
39 | mv proto2.h proto.h | 38 | mv proto2.h proto.h |
40 | 39 |
fs/smbfs/inode.c
1 | /* | 1 | /* |
2 | * inode.c | 2 | * inode.c |
3 | * | 3 | * |
4 | * Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke | 4 | * Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke |
5 | * Copyright (C) 1997 by Volker Lendecke | 5 | * Copyright (C) 1997 by Volker Lendecke |
6 | * | 6 | * |
7 | * Please add a note about your changes to smbfs in the ChangeLog file. | 7 | * Please add a note about your changes to smbfs in the ChangeLog file. |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/config.h> | 10 | #include <linux/config.h> |
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/time.h> | 12 | #include <linux/time.h> |
13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
14 | #include <linux/mm.h> | 14 | #include <linux/mm.h> |
15 | #include <linux/string.h> | 15 | #include <linux/string.h> |
16 | #include <linux/stat.h> | 16 | #include <linux/stat.h> |
17 | #include <linux/errno.h> | 17 | #include <linux/errno.h> |
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
20 | #include <linux/file.h> | 20 | #include <linux/file.h> |
21 | #include <linux/dcache.h> | 21 | #include <linux/dcache.h> |
22 | #include <linux/smp_lock.h> | 22 | #include <linux/smp_lock.h> |
23 | #include <linux/nls.h> | 23 | #include <linux/nls.h> |
24 | #include <linux/seq_file.h> | 24 | #include <linux/seq_file.h> |
25 | #include <linux/mount.h> | 25 | #include <linux/mount.h> |
26 | #include <linux/net.h> | 26 | #include <linux/net.h> |
27 | #include <linux/vfs.h> | 27 | #include <linux/vfs.h> |
28 | #include <linux/highuid.h> | 28 | #include <linux/highuid.h> |
29 | #include <linux/smb_fs.h> | 29 | #include <linux/smb_fs.h> |
30 | #include <linux/smbno.h> | 30 | #include <linux/smbno.h> |
31 | #include <linux/smb_mount.h> | 31 | #include <linux/smb_mount.h> |
32 | 32 | ||
33 | #include <asm/system.h> | 33 | #include <asm/system.h> |
34 | #include <asm/uaccess.h> | 34 | #include <asm/uaccess.h> |
35 | 35 | ||
36 | #include "smb_debug.h" | 36 | #include "smb_debug.h" |
37 | #include "getopt.h" | 37 | #include "getopt.h" |
38 | #include "proto.h" | 38 | #include "proto.h" |
39 | 39 | ||
40 | /* Always pick a default string */ | 40 | /* Always pick a default string */ |
41 | #ifdef CONFIG_SMB_NLS_REMOTE | 41 | #ifdef CONFIG_SMB_NLS_REMOTE |
42 | #define SMB_NLS_REMOTE CONFIG_SMB_NLS_REMOTE | 42 | #define SMB_NLS_REMOTE CONFIG_SMB_NLS_REMOTE |
43 | #else | 43 | #else |
44 | #define SMB_NLS_REMOTE "" | 44 | #define SMB_NLS_REMOTE "" |
45 | #endif | 45 | #endif |
46 | 46 | ||
47 | #define SMB_TTL_DEFAULT 1000 | 47 | #define SMB_TTL_DEFAULT 1000 |
48 | 48 | ||
49 | static void smb_delete_inode(struct inode *); | 49 | static void smb_delete_inode(struct inode *); |
50 | static void smb_put_super(struct super_block *); | 50 | static void smb_put_super(struct super_block *); |
51 | static int smb_statfs(struct super_block *, struct kstatfs *); | 51 | static int smb_statfs(struct super_block *, struct kstatfs *); |
52 | static int smb_show_options(struct seq_file *, struct vfsmount *); | 52 | static int smb_show_options(struct seq_file *, struct vfsmount *); |
53 | 53 | ||
54 | static kmem_cache_t *smb_inode_cachep; | 54 | static kmem_cache_t *smb_inode_cachep; |
55 | 55 | ||
56 | static struct inode *smb_alloc_inode(struct super_block *sb) | 56 | static struct inode *smb_alloc_inode(struct super_block *sb) |
57 | { | 57 | { |
58 | struct smb_inode_info *ei; | 58 | struct smb_inode_info *ei; |
59 | ei = (struct smb_inode_info *)kmem_cache_alloc(smb_inode_cachep, SLAB_KERNEL); | 59 | ei = (struct smb_inode_info *)kmem_cache_alloc(smb_inode_cachep, SLAB_KERNEL); |
60 | if (!ei) | 60 | if (!ei) |
61 | return NULL; | 61 | return NULL; |
62 | return &ei->vfs_inode; | 62 | return &ei->vfs_inode; |
63 | } | 63 | } |
64 | 64 | ||
65 | static void smb_destroy_inode(struct inode *inode) | 65 | static void smb_destroy_inode(struct inode *inode) |
66 | { | 66 | { |
67 | kmem_cache_free(smb_inode_cachep, SMB_I(inode)); | 67 | kmem_cache_free(smb_inode_cachep, SMB_I(inode)); |
68 | } | 68 | } |
69 | 69 | ||
70 | static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) | 70 | static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) |
71 | { | 71 | { |
72 | struct smb_inode_info *ei = (struct smb_inode_info *) foo; | 72 | struct smb_inode_info *ei = (struct smb_inode_info *) foo; |
73 | unsigned long flagmask = SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR; | 73 | unsigned long flagmask = SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR; |
74 | 74 | ||
75 | if ((flags & flagmask) == SLAB_CTOR_CONSTRUCTOR) | 75 | if ((flags & flagmask) == SLAB_CTOR_CONSTRUCTOR) |
76 | inode_init_once(&ei->vfs_inode); | 76 | inode_init_once(&ei->vfs_inode); |
77 | } | 77 | } |
78 | 78 | ||
79 | static int init_inodecache(void) | 79 | static int init_inodecache(void) |
80 | { | 80 | { |
81 | smb_inode_cachep = kmem_cache_create("smb_inode_cache", | 81 | smb_inode_cachep = kmem_cache_create("smb_inode_cache", |
82 | sizeof(struct smb_inode_info), | 82 | sizeof(struct smb_inode_info), |
83 | 0, SLAB_RECLAIM_ACCOUNT, | 83 | 0, SLAB_RECLAIM_ACCOUNT, |
84 | init_once, NULL); | 84 | init_once, NULL); |
85 | if (smb_inode_cachep == NULL) | 85 | if (smb_inode_cachep == NULL) |
86 | return -ENOMEM; | 86 | return -ENOMEM; |
87 | return 0; | 87 | return 0; |
88 | } | 88 | } |
89 | 89 | ||
90 | static void destroy_inodecache(void) | 90 | static void destroy_inodecache(void) |
91 | { | 91 | { |
92 | if (kmem_cache_destroy(smb_inode_cachep)) | 92 | if (kmem_cache_destroy(smb_inode_cachep)) |
93 | printk(KERN_INFO "smb_inode_cache: not all structures were freed\n"); | 93 | printk(KERN_INFO "smb_inode_cache: not all structures were freed\n"); |
94 | } | 94 | } |
95 | 95 | ||
96 | static int smb_remount(struct super_block *sb, int *flags, char *data) | 96 | static int smb_remount(struct super_block *sb, int *flags, char *data) |
97 | { | 97 | { |
98 | *flags |= MS_NODIRATIME; | 98 | *flags |= MS_NODIRATIME; |
99 | return 0; | 99 | return 0; |
100 | } | 100 | } |
101 | 101 | ||
102 | static struct super_operations smb_sops = | 102 | static struct super_operations smb_sops = |
103 | { | 103 | { |
104 | .alloc_inode = smb_alloc_inode, | 104 | .alloc_inode = smb_alloc_inode, |
105 | .destroy_inode = smb_destroy_inode, | 105 | .destroy_inode = smb_destroy_inode, |
106 | .drop_inode = generic_delete_inode, | 106 | .drop_inode = generic_delete_inode, |
107 | .delete_inode = smb_delete_inode, | 107 | .delete_inode = smb_delete_inode, |
108 | .put_super = smb_put_super, | 108 | .put_super = smb_put_super, |
109 | .statfs = smb_statfs, | 109 | .statfs = smb_statfs, |
110 | .show_options = smb_show_options, | 110 | .show_options = smb_show_options, |
111 | .remount_fs = smb_remount, | 111 | .remount_fs = smb_remount, |
112 | }; | 112 | }; |
113 | 113 | ||
114 | 114 | ||
115 | /* We are always generating a new inode here */ | 115 | /* We are always generating a new inode here */ |
116 | struct inode * | 116 | struct inode * |
117 | smb_iget(struct super_block *sb, struct smb_fattr *fattr) | 117 | smb_iget(struct super_block *sb, struct smb_fattr *fattr) |
118 | { | 118 | { |
119 | struct smb_sb_info *server = SMB_SB(sb); | 119 | struct smb_sb_info *server = SMB_SB(sb); |
120 | struct inode *result; | 120 | struct inode *result; |
121 | 121 | ||
122 | DEBUG1("smb_iget: %p\n", fattr); | 122 | DEBUG1("smb_iget: %p\n", fattr); |
123 | 123 | ||
124 | result = new_inode(sb); | 124 | result = new_inode(sb); |
125 | if (!result) | 125 | if (!result) |
126 | return result; | 126 | return result; |
127 | result->i_ino = fattr->f_ino; | 127 | result->i_ino = fattr->f_ino; |
128 | SMB_I(result)->open = 0; | 128 | SMB_I(result)->open = 0; |
129 | SMB_I(result)->fileid = 0; | 129 | SMB_I(result)->fileid = 0; |
130 | SMB_I(result)->access = 0; | 130 | SMB_I(result)->access = 0; |
131 | SMB_I(result)->flags = 0; | 131 | SMB_I(result)->flags = 0; |
132 | SMB_I(result)->closed = 0; | 132 | SMB_I(result)->closed = 0; |
133 | SMB_I(result)->openers = 0; | 133 | SMB_I(result)->openers = 0; |
134 | smb_set_inode_attr(result, fattr); | 134 | smb_set_inode_attr(result, fattr); |
135 | if (S_ISREG(result->i_mode)) { | 135 | if (S_ISREG(result->i_mode)) { |
136 | result->i_op = &smb_file_inode_operations; | 136 | result->i_op = &smb_file_inode_operations; |
137 | result->i_fop = &smb_file_operations; | 137 | result->i_fop = &smb_file_operations; |
138 | result->i_data.a_ops = &smb_file_aops; | 138 | result->i_data.a_ops = &smb_file_aops; |
139 | } else if (S_ISDIR(result->i_mode)) { | 139 | } else if (S_ISDIR(result->i_mode)) { |
140 | if (server->opt.capabilities & SMB_CAP_UNIX) | 140 | if (server->opt.capabilities & SMB_CAP_UNIX) |
141 | result->i_op = &smb_dir_inode_operations_unix; | 141 | result->i_op = &smb_dir_inode_operations_unix; |
142 | else | 142 | else |
143 | result->i_op = &smb_dir_inode_operations; | 143 | result->i_op = &smb_dir_inode_operations; |
144 | result->i_fop = &smb_dir_operations; | 144 | result->i_fop = &smb_dir_operations; |
145 | } else if (S_ISLNK(result->i_mode)) { | 145 | } else if (S_ISLNK(result->i_mode)) { |
146 | result->i_op = &smb_link_inode_operations; | 146 | result->i_op = &smb_link_inode_operations; |
147 | } else { | 147 | } else { |
148 | init_special_inode(result, result->i_mode, fattr->f_rdev); | 148 | init_special_inode(result, result->i_mode, fattr->f_rdev); |
149 | } | 149 | } |
150 | insert_inode_hash(result); | 150 | insert_inode_hash(result); |
151 | return result; | 151 | return result; |
152 | } | 152 | } |
153 | 153 | ||
154 | /* | 154 | /* |
155 | * Copy the inode data to a smb_fattr structure. | 155 | * Copy the inode data to a smb_fattr structure. |
156 | */ | 156 | */ |
157 | void | 157 | void |
158 | smb_get_inode_attr(struct inode *inode, struct smb_fattr *fattr) | 158 | smb_get_inode_attr(struct inode *inode, struct smb_fattr *fattr) |
159 | { | 159 | { |
160 | memset(fattr, 0, sizeof(struct smb_fattr)); | 160 | memset(fattr, 0, sizeof(struct smb_fattr)); |
161 | fattr->f_mode = inode->i_mode; | 161 | fattr->f_mode = inode->i_mode; |
162 | fattr->f_nlink = inode->i_nlink; | 162 | fattr->f_nlink = inode->i_nlink; |
163 | fattr->f_ino = inode->i_ino; | 163 | fattr->f_ino = inode->i_ino; |
164 | fattr->f_uid = inode->i_uid; | 164 | fattr->f_uid = inode->i_uid; |
165 | fattr->f_gid = inode->i_gid; | 165 | fattr->f_gid = inode->i_gid; |
166 | fattr->f_size = inode->i_size; | 166 | fattr->f_size = inode->i_size; |
167 | fattr->f_mtime = inode->i_mtime; | 167 | fattr->f_mtime = inode->i_mtime; |
168 | fattr->f_ctime = inode->i_ctime; | 168 | fattr->f_ctime = inode->i_ctime; |
169 | fattr->f_atime = inode->i_atime; | 169 | fattr->f_atime = inode->i_atime; |
170 | fattr->f_blksize= inode->i_blksize; | 170 | fattr->f_blksize= inode->i_blksize; |
171 | fattr->f_blocks = inode->i_blocks; | 171 | fattr->f_blocks = inode->i_blocks; |
172 | 172 | ||
173 | fattr->attr = SMB_I(inode)->attr; | 173 | fattr->attr = SMB_I(inode)->attr; |
174 | /* | 174 | /* |
175 | * Keep the attributes in sync with the inode permissions. | 175 | * Keep the attributes in sync with the inode permissions. |
176 | */ | 176 | */ |
177 | if (fattr->f_mode & S_IWUSR) | 177 | if (fattr->f_mode & S_IWUSR) |
178 | fattr->attr &= ~aRONLY; | 178 | fattr->attr &= ~aRONLY; |
179 | else | 179 | else |
180 | fattr->attr |= aRONLY; | 180 | fattr->attr |= aRONLY; |
181 | } | 181 | } |
182 | 182 | ||
183 | /* | 183 | /* |
184 | * Update the inode, possibly causing it to invalidate its pages if mtime/size | 184 | * Update the inode, possibly causing it to invalidate its pages if mtime/size |
185 | * is different from last time. | 185 | * is different from last time. |
186 | */ | 186 | */ |
187 | void | 187 | void |
188 | smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr) | 188 | smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr) |
189 | { | 189 | { |
190 | struct smb_inode_info *ei = SMB_I(inode); | 190 | struct smb_inode_info *ei = SMB_I(inode); |
191 | 191 | ||
192 | /* | 192 | /* |
193 | * A size change should have a different mtime, or same mtime | 193 | * A size change should have a different mtime, or same mtime |
194 | * but different size. | 194 | * but different size. |
195 | */ | 195 | */ |
196 | time_t last_time = inode->i_mtime.tv_sec; | 196 | time_t last_time = inode->i_mtime.tv_sec; |
197 | loff_t last_sz = inode->i_size; | 197 | loff_t last_sz = inode->i_size; |
198 | 198 | ||
199 | inode->i_mode = fattr->f_mode; | 199 | inode->i_mode = fattr->f_mode; |
200 | inode->i_nlink = fattr->f_nlink; | 200 | inode->i_nlink = fattr->f_nlink; |
201 | inode->i_uid = fattr->f_uid; | 201 | inode->i_uid = fattr->f_uid; |
202 | inode->i_gid = fattr->f_gid; | 202 | inode->i_gid = fattr->f_gid; |
203 | inode->i_ctime = fattr->f_ctime; | 203 | inode->i_ctime = fattr->f_ctime; |
204 | inode->i_blksize= fattr->f_blksize; | 204 | inode->i_blksize= fattr->f_blksize; |
205 | inode->i_blocks = fattr->f_blocks; | 205 | inode->i_blocks = fattr->f_blocks; |
206 | inode->i_size = fattr->f_size; | 206 | inode->i_size = fattr->f_size; |
207 | inode->i_mtime = fattr->f_mtime; | 207 | inode->i_mtime = fattr->f_mtime; |
208 | inode->i_atime = fattr->f_atime; | 208 | inode->i_atime = fattr->f_atime; |
209 | ei->attr = fattr->attr; | 209 | ei->attr = fattr->attr; |
210 | 210 | ||
211 | /* | 211 | /* |
212 | * Update the "last time refreshed" field for revalidation. | 212 | * Update the "last time refreshed" field for revalidation. |
213 | */ | 213 | */ |
214 | ei->oldmtime = jiffies; | 214 | ei->oldmtime = jiffies; |
215 | 215 | ||
216 | if (inode->i_mtime.tv_sec != last_time || inode->i_size != last_sz) { | 216 | if (inode->i_mtime.tv_sec != last_time || inode->i_size != last_sz) { |
217 | VERBOSE("%ld changed, old=%ld, new=%ld, oz=%ld, nz=%ld\n", | 217 | VERBOSE("%ld changed, old=%ld, new=%ld, oz=%ld, nz=%ld\n", |
218 | inode->i_ino, | 218 | inode->i_ino, |
219 | (long) last_time, (long) inode->i_mtime, | 219 | (long) last_time, (long) inode->i_mtime, |
220 | (long) last_sz, (long) inode->i_size); | 220 | (long) last_sz, (long) inode->i_size); |
221 | 221 | ||
222 | if (!S_ISDIR(inode->i_mode)) | 222 | if (!S_ISDIR(inode->i_mode)) |
223 | invalidate_remote_inode(inode); | 223 | invalidate_remote_inode(inode); |
224 | } | 224 | } |
225 | } | 225 | } |
226 | 226 | ||
227 | /* | 227 | /* |
228 | * This is called if the connection has gone bad ... | 228 | * This is called if the connection has gone bad ... |
229 | * try to kill off all the current inodes. | 229 | * try to kill off all the current inodes. |
230 | */ | 230 | */ |
231 | void | 231 | void |
232 | smb_invalidate_inodes(struct smb_sb_info *server) | 232 | smb_invalidate_inodes(struct smb_sb_info *server) |
233 | { | 233 | { |
234 | VERBOSE("\n"); | 234 | VERBOSE("\n"); |
235 | shrink_dcache_sb(SB_of(server)); | 235 | shrink_dcache_sb(SB_of(server)); |
236 | invalidate_inodes(SB_of(server)); | 236 | invalidate_inodes(SB_of(server)); |
237 | } | 237 | } |
238 | 238 | ||
239 | /* | 239 | /* |
240 | * This is called to update the inode attributes after | 240 | * This is called to update the inode attributes after |
241 | * we've made changes to a file or directory. | 241 | * we've made changes to a file or directory. |
242 | */ | 242 | */ |
243 | static int | 243 | static int |
244 | smb_refresh_inode(struct dentry *dentry) | 244 | smb_refresh_inode(struct dentry *dentry) |
245 | { | 245 | { |
246 | struct inode *inode = dentry->d_inode; | 246 | struct inode *inode = dentry->d_inode; |
247 | int error; | 247 | int error; |
248 | struct smb_fattr fattr; | 248 | struct smb_fattr fattr; |
249 | 249 | ||
250 | error = smb_proc_getattr(dentry, &fattr); | 250 | error = smb_proc_getattr(dentry, &fattr); |
251 | if (!error) { | 251 | if (!error) { |
252 | smb_renew_times(dentry); | 252 | smb_renew_times(dentry); |
253 | /* | 253 | /* |
254 | * Check whether the type part of the mode changed, | 254 | * Check whether the type part of the mode changed, |
255 | * and don't update the attributes if it did. | 255 | * and don't update the attributes if it did. |
256 | * | 256 | * |
257 | * And don't dick with the root inode | 257 | * And don't dick with the root inode |
258 | */ | 258 | */ |
259 | if (inode->i_ino == 2) | 259 | if (inode->i_ino == 2) |
260 | return error; | 260 | return error; |
261 | if (S_ISLNK(inode->i_mode)) | 261 | if (S_ISLNK(inode->i_mode)) |
262 | return error; /* VFS will deal with it */ | 262 | return error; /* VFS will deal with it */ |
263 | 263 | ||
264 | if ((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT)) { | 264 | if ((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT)) { |
265 | smb_set_inode_attr(inode, &fattr); | 265 | smb_set_inode_attr(inode, &fattr); |
266 | } else { | 266 | } else { |
267 | /* | 267 | /* |
268 | * Big trouble! The inode has become a new object, | 268 | * Big trouble! The inode has become a new object, |
269 | * so any operations attempted on it are invalid. | 269 | * so any operations attempted on it are invalid. |
270 | * | 270 | * |
271 | * To limit damage, mark the inode as bad so that | 271 | * To limit damage, mark the inode as bad so that |
272 | * subsequent lookup validations will fail. | 272 | * subsequent lookup validations will fail. |
273 | */ | 273 | */ |
274 | PARANOIA("%s/%s changed mode, %07o to %07o\n", | 274 | PARANOIA("%s/%s changed mode, %07o to %07o\n", |
275 | DENTRY_PATH(dentry), | 275 | DENTRY_PATH(dentry), |
276 | inode->i_mode, fattr.f_mode); | 276 | inode->i_mode, fattr.f_mode); |
277 | 277 | ||
278 | fattr.f_mode = inode->i_mode; /* save mode */ | 278 | fattr.f_mode = inode->i_mode; /* save mode */ |
279 | make_bad_inode(inode); | 279 | make_bad_inode(inode); |
280 | inode->i_mode = fattr.f_mode; /* restore mode */ | 280 | inode->i_mode = fattr.f_mode; /* restore mode */ |
281 | /* | 281 | /* |
282 | * No need to worry about unhashing the dentry: the | 282 | * No need to worry about unhashing the dentry: the |
283 | * lookup validation will see that the inode is bad. | 283 | * lookup validation will see that the inode is bad. |
284 | * But we do want to invalidate the caches ... | 284 | * But we do want to invalidate the caches ... |
285 | */ | 285 | */ |
286 | if (!S_ISDIR(inode->i_mode)) | 286 | if (!S_ISDIR(inode->i_mode)) |
287 | invalidate_remote_inode(inode); | 287 | invalidate_remote_inode(inode); |
288 | else | 288 | else |
289 | smb_invalid_dir_cache(inode); | 289 | smb_invalid_dir_cache(inode); |
290 | error = -EIO; | 290 | error = -EIO; |
291 | } | 291 | } |
292 | } | 292 | } |
293 | return error; | 293 | return error; |
294 | } | 294 | } |
295 | 295 | ||
296 | /* | 296 | /* |
297 | * This is called when we want to check whether the inode | 297 | * This is called when we want to check whether the inode |
298 | * has changed on the server. If it has changed, we must | 298 | * has changed on the server. If it has changed, we must |
299 | * invalidate our local caches. | 299 | * invalidate our local caches. |
300 | */ | 300 | */ |
301 | int | 301 | int |
302 | smb_revalidate_inode(struct dentry *dentry) | 302 | smb_revalidate_inode(struct dentry *dentry) |
303 | { | 303 | { |
304 | struct smb_sb_info *s = server_from_dentry(dentry); | 304 | struct smb_sb_info *s = server_from_dentry(dentry); |
305 | struct inode *inode = dentry->d_inode; | 305 | struct inode *inode = dentry->d_inode; |
306 | int error = 0; | 306 | int error = 0; |
307 | 307 | ||
308 | DEBUG1("smb_revalidate_inode\n"); | 308 | DEBUG1("smb_revalidate_inode\n"); |
309 | lock_kernel(); | 309 | lock_kernel(); |
310 | 310 | ||
311 | /* | 311 | /* |
312 | * Check whether we've recently refreshed the inode. | 312 | * Check whether we've recently refreshed the inode. |
313 | */ | 313 | */ |
314 | if (time_before(jiffies, SMB_I(inode)->oldmtime + SMB_MAX_AGE(s))) { | 314 | if (time_before(jiffies, SMB_I(inode)->oldmtime + SMB_MAX_AGE(s))) { |
315 | VERBOSE("up-to-date, ino=%ld, jiffies=%lu, oldtime=%lu\n", | 315 | VERBOSE("up-to-date, ino=%ld, jiffies=%lu, oldtime=%lu\n", |
316 | inode->i_ino, jiffies, SMB_I(inode)->oldmtime); | 316 | inode->i_ino, jiffies, SMB_I(inode)->oldmtime); |
317 | goto out; | 317 | goto out; |
318 | } | 318 | } |
319 | 319 | ||
320 | error = smb_refresh_inode(dentry); | 320 | error = smb_refresh_inode(dentry); |
321 | out: | 321 | out: |
322 | unlock_kernel(); | 322 | unlock_kernel(); |
323 | return error; | 323 | return error; |
324 | } | 324 | } |
325 | 325 | ||
326 | /* | 326 | /* |
327 | * This routine is called when i_nlink == 0 and i_count goes to 0. | 327 | * This routine is called when i_nlink == 0 and i_count goes to 0. |
328 | * All blocking cleanup operations need to go here to avoid races. | 328 | * All blocking cleanup operations need to go here to avoid races. |
329 | */ | 329 | */ |
330 | static void | 330 | static void |
331 | smb_delete_inode(struct inode *ino) | 331 | smb_delete_inode(struct inode *ino) |
332 | { | 332 | { |
333 | DEBUG1("ino=%ld\n", ino->i_ino); | 333 | DEBUG1("ino=%ld\n", ino->i_ino); |
334 | truncate_inode_pages(&ino->i_data, 0); | 334 | truncate_inode_pages(&ino->i_data, 0); |
335 | lock_kernel(); | 335 | lock_kernel(); |
336 | if (smb_close(ino)) | 336 | if (smb_close(ino)) |
337 | PARANOIA("could not close inode %ld\n", ino->i_ino); | 337 | PARANOIA("could not close inode %ld\n", ino->i_ino); |
338 | unlock_kernel(); | 338 | unlock_kernel(); |
339 | clear_inode(ino); | 339 | clear_inode(ino); |
340 | } | 340 | } |
341 | 341 | ||
342 | static struct option opts[] = { | 342 | static struct option opts[] = { |
343 | { "version", 0, 'v' }, | 343 | { "version", 0, 'v' }, |
344 | { "win95", SMB_MOUNT_WIN95, 1 }, | 344 | { "win95", SMB_MOUNT_WIN95, 1 }, |
345 | { "oldattr", SMB_MOUNT_OLDATTR, 1 }, | 345 | { "oldattr", SMB_MOUNT_OLDATTR, 1 }, |
346 | { "dirattr", SMB_MOUNT_DIRATTR, 1 }, | 346 | { "dirattr", SMB_MOUNT_DIRATTR, 1 }, |
347 | { "case", SMB_MOUNT_CASE, 1 }, | 347 | { "case", SMB_MOUNT_CASE, 1 }, |
348 | { "uid", 0, 'u' }, | 348 | { "uid", 0, 'u' }, |
349 | { "gid", 0, 'g' }, | 349 | { "gid", 0, 'g' }, |
350 | { "file_mode", 0, 'f' }, | 350 | { "file_mode", 0, 'f' }, |
351 | { "dir_mode", 0, 'd' }, | 351 | { "dir_mode", 0, 'd' }, |
352 | { "iocharset", 0, 'i' }, | 352 | { "iocharset", 0, 'i' }, |
353 | { "codepage", 0, 'c' }, | 353 | { "codepage", 0, 'c' }, |
354 | { "ttl", 0, 't' }, | 354 | { "ttl", 0, 't' }, |
355 | { NULL, 0, 0} | 355 | { NULL, 0, 0} |
356 | }; | 356 | }; |
357 | 357 | ||
358 | static int | 358 | static int |
359 | parse_options(struct smb_mount_data_kernel *mnt, char *options) | 359 | parse_options(struct smb_mount_data_kernel *mnt, char *options) |
360 | { | 360 | { |
361 | int c; | 361 | int c; |
362 | unsigned long flags; | 362 | unsigned long flags; |
363 | unsigned long value; | 363 | unsigned long value; |
364 | char *optarg; | 364 | char *optarg; |
365 | char *optopt; | 365 | char *optopt; |
366 | 366 | ||
367 | flags = 0; | 367 | flags = 0; |
368 | while ( (c = smb_getopt("smbfs", &options, opts, | 368 | while ( (c = smb_getopt("smbfs", &options, opts, |
369 | &optopt, &optarg, &flags, &value)) > 0) { | 369 | &optopt, &optarg, &flags, &value)) > 0) { |
370 | 370 | ||
371 | VERBOSE("'%s' -> '%s'\n", optopt, optarg ? optarg : "<none>"); | 371 | VERBOSE("'%s' -> '%s'\n", optopt, optarg ? optarg : "<none>"); |
372 | switch (c) { | 372 | switch (c) { |
373 | case 1: | 373 | case 1: |
374 | /* got a "flag" option */ | 374 | /* got a "flag" option */ |
375 | break; | 375 | break; |
376 | case 'v': | 376 | case 'v': |
377 | if (value != SMB_MOUNT_VERSION) { | 377 | if (value != SMB_MOUNT_VERSION) { |
378 | printk ("smbfs: Bad mount version %ld, expected %d\n", | 378 | printk ("smbfs: Bad mount version %ld, expected %d\n", |
379 | value, SMB_MOUNT_VERSION); | 379 | value, SMB_MOUNT_VERSION); |
380 | return 0; | 380 | return 0; |
381 | } | 381 | } |
382 | mnt->version = value; | 382 | mnt->version = value; |
383 | break; | 383 | break; |
384 | case 'u': | 384 | case 'u': |
385 | mnt->uid = value; | 385 | mnt->uid = value; |
386 | flags |= SMB_MOUNT_UID; | 386 | flags |= SMB_MOUNT_UID; |
387 | break; | 387 | break; |
388 | case 'g': | 388 | case 'g': |
389 | mnt->gid = value; | 389 | mnt->gid = value; |
390 | flags |= SMB_MOUNT_GID; | 390 | flags |= SMB_MOUNT_GID; |
391 | break; | 391 | break; |
392 | case 'f': | 392 | case 'f': |
393 | mnt->file_mode = (value & S_IRWXUGO) | S_IFREG; | 393 | mnt->file_mode = (value & S_IRWXUGO) | S_IFREG; |
394 | flags |= SMB_MOUNT_FMODE; | 394 | flags |= SMB_MOUNT_FMODE; |
395 | break; | 395 | break; |
396 | case 'd': | 396 | case 'd': |
397 | mnt->dir_mode = (value & S_IRWXUGO) | S_IFDIR; | 397 | mnt->dir_mode = (value & S_IRWXUGO) | S_IFDIR; |
398 | flags |= SMB_MOUNT_DMODE; | 398 | flags |= SMB_MOUNT_DMODE; |
399 | break; | 399 | break; |
400 | case 'i': | 400 | case 'i': |
401 | strlcpy(mnt->codepage.local_name, optarg, | 401 | strlcpy(mnt->codepage.local_name, optarg, |
402 | SMB_NLS_MAXNAMELEN); | 402 | SMB_NLS_MAXNAMELEN); |
403 | break; | 403 | break; |
404 | case 'c': | 404 | case 'c': |
405 | strlcpy(mnt->codepage.remote_name, optarg, | 405 | strlcpy(mnt->codepage.remote_name, optarg, |
406 | SMB_NLS_MAXNAMELEN); | 406 | SMB_NLS_MAXNAMELEN); |
407 | break; | 407 | break; |
408 | case 't': | 408 | case 't': |
409 | mnt->ttl = value; | 409 | mnt->ttl = value; |
410 | break; | 410 | break; |
411 | default: | 411 | default: |
412 | printk ("smbfs: Unrecognized mount option %s\n", | 412 | printk ("smbfs: Unrecognized mount option %s\n", |
413 | optopt); | 413 | optopt); |
414 | return -1; | 414 | return -1; |
415 | } | 415 | } |
416 | } | 416 | } |
417 | mnt->flags = flags; | 417 | mnt->flags = flags; |
418 | return c; | 418 | return c; |
419 | } | 419 | } |
420 | 420 | ||
421 | /* | 421 | /* |
422 | * smb_show_options() is for displaying mount options in /proc/mounts. | 422 | * smb_show_options() is for displaying mount options in /proc/mounts. |
423 | * It tries to avoid showing settings that were not changed from their | 423 | * It tries to avoid showing settings that were not changed from their |
424 | * defaults. | 424 | * defaults. |
425 | */ | 425 | */ |
426 | static int | 426 | static int |
427 | smb_show_options(struct seq_file *s, struct vfsmount *m) | 427 | smb_show_options(struct seq_file *s, struct vfsmount *m) |
428 | { | 428 | { |
429 | struct smb_mount_data_kernel *mnt = SMB_SB(m->mnt_sb)->mnt; | 429 | struct smb_mount_data_kernel *mnt = SMB_SB(m->mnt_sb)->mnt; |
430 | int i; | 430 | int i; |
431 | 431 | ||
432 | for (i = 0; opts[i].name != NULL; i++) | 432 | for (i = 0; opts[i].name != NULL; i++) |
433 | if (mnt->flags & opts[i].flag) | 433 | if (mnt->flags & opts[i].flag) |
434 | seq_printf(s, ",%s", opts[i].name); | 434 | seq_printf(s, ",%s", opts[i].name); |
435 | 435 | ||
436 | if (mnt->flags & SMB_MOUNT_UID) | 436 | if (mnt->flags & SMB_MOUNT_UID) |
437 | seq_printf(s, ",uid=%d", mnt->uid); | 437 | seq_printf(s, ",uid=%d", mnt->uid); |
438 | if (mnt->flags & SMB_MOUNT_GID) | 438 | if (mnt->flags & SMB_MOUNT_GID) |
439 | seq_printf(s, ",gid=%d", mnt->gid); | 439 | seq_printf(s, ",gid=%d", mnt->gid); |
440 | if (mnt->mounted_uid != 0) | 440 | if (mnt->mounted_uid != 0) |
441 | seq_printf(s, ",mounted_uid=%d", mnt->mounted_uid); | 441 | seq_printf(s, ",mounted_uid=%d", mnt->mounted_uid); |
442 | 442 | ||
443 | /* | 443 | /* |
444 | * Defaults for file_mode and dir_mode are unknown to us; they | 444 | * Defaults for file_mode and dir_mode are unknown to us; they |
445 | * depend on the current umask of the user doing the mount. | 445 | * depend on the current umask of the user doing the mount. |
446 | */ | 446 | */ |
447 | if (mnt->flags & SMB_MOUNT_FMODE) | 447 | if (mnt->flags & SMB_MOUNT_FMODE) |
448 | seq_printf(s, ",file_mode=%04o", mnt->file_mode & S_IRWXUGO); | 448 | seq_printf(s, ",file_mode=%04o", mnt->file_mode & S_IRWXUGO); |
449 | if (mnt->flags & SMB_MOUNT_DMODE) | 449 | if (mnt->flags & SMB_MOUNT_DMODE) |
450 | seq_printf(s, ",dir_mode=%04o", mnt->dir_mode & S_IRWXUGO); | 450 | seq_printf(s, ",dir_mode=%04o", mnt->dir_mode & S_IRWXUGO); |
451 | 451 | ||
452 | if (strcmp(mnt->codepage.local_name, CONFIG_NLS_DEFAULT)) | 452 | if (strcmp(mnt->codepage.local_name, CONFIG_NLS_DEFAULT)) |
453 | seq_printf(s, ",iocharset=%s", mnt->codepage.local_name); | 453 | seq_printf(s, ",iocharset=%s", mnt->codepage.local_name); |
454 | if (strcmp(mnt->codepage.remote_name, SMB_NLS_REMOTE)) | 454 | if (strcmp(mnt->codepage.remote_name, SMB_NLS_REMOTE)) |
455 | seq_printf(s, ",codepage=%s", mnt->codepage.remote_name); | 455 | seq_printf(s, ",codepage=%s", mnt->codepage.remote_name); |
456 | 456 | ||
457 | if (mnt->ttl != SMB_TTL_DEFAULT) | 457 | if (mnt->ttl != SMB_TTL_DEFAULT) |
458 | seq_printf(s, ",ttl=%d", mnt->ttl); | 458 | seq_printf(s, ",ttl=%d", mnt->ttl); |
459 | 459 | ||
460 | return 0; | 460 | return 0; |
461 | } | 461 | } |
462 | 462 | ||
463 | static void | 463 | static void |
464 | smb_unload_nls(struct smb_sb_info *server) | 464 | smb_unload_nls(struct smb_sb_info *server) |
465 | { | 465 | { |
466 | if (server->remote_nls) { | 466 | if (server->remote_nls) { |
467 | unload_nls(server->remote_nls); | 467 | unload_nls(server->remote_nls); |
468 | server->remote_nls = NULL; | 468 | server->remote_nls = NULL; |
469 | } | 469 | } |
470 | if (server->local_nls) { | 470 | if (server->local_nls) { |
471 | unload_nls(server->local_nls); | 471 | unload_nls(server->local_nls); |
472 | server->local_nls = NULL; | 472 | server->local_nls = NULL; |
473 | } | 473 | } |
474 | } | 474 | } |
475 | 475 | ||
476 | static void | 476 | static void |
477 | smb_put_super(struct super_block *sb) | 477 | smb_put_super(struct super_block *sb) |
478 | { | 478 | { |
479 | struct smb_sb_info *server = SMB_SB(sb); | 479 | struct smb_sb_info *server = SMB_SB(sb); |
480 | 480 | ||
481 | smb_lock_server(server); | 481 | smb_lock_server(server); |
482 | server->state = CONN_INVALID; | 482 | server->state = CONN_INVALID; |
483 | smbiod_unregister_server(server); | 483 | smbiod_unregister_server(server); |
484 | 484 | ||
485 | smb_close_socket(server); | 485 | smb_close_socket(server); |
486 | 486 | ||
487 | if (server->conn_pid) | 487 | if (server->conn_pid) |
488 | kill_proc(server->conn_pid, SIGTERM, 1); | 488 | kill_proc(server->conn_pid, SIGTERM, 1); |
489 | 489 | ||
490 | smb_kfree(server->ops); | 490 | kfree(server->ops); |
491 | smb_unload_nls(server); | 491 | smb_unload_nls(server); |
492 | sb->s_fs_info = NULL; | 492 | sb->s_fs_info = NULL; |
493 | smb_unlock_server(server); | 493 | smb_unlock_server(server); |
494 | smb_kfree(server); | 494 | kfree(server); |
495 | } | 495 | } |
496 | 496 | ||
497 | static int smb_fill_super(struct super_block *sb, void *raw_data, int silent) | 497 | static int smb_fill_super(struct super_block *sb, void *raw_data, int silent) |
498 | { | 498 | { |
499 | struct smb_sb_info *server; | 499 | struct smb_sb_info *server; |
500 | struct smb_mount_data_kernel *mnt; | 500 | struct smb_mount_data_kernel *mnt; |
501 | struct smb_mount_data *oldmnt; | 501 | struct smb_mount_data *oldmnt; |
502 | struct inode *root_inode; | 502 | struct inode *root_inode; |
503 | struct smb_fattr root; | 503 | struct smb_fattr root; |
504 | int ver; | 504 | int ver; |
505 | void *mem; | 505 | void *mem; |
506 | 506 | ||
507 | if (!raw_data) | 507 | if (!raw_data) |
508 | goto out_no_data; | 508 | goto out_no_data; |
509 | 509 | ||
510 | oldmnt = (struct smb_mount_data *) raw_data; | 510 | oldmnt = (struct smb_mount_data *) raw_data; |
511 | ver = oldmnt->version; | 511 | ver = oldmnt->version; |
512 | if (ver != SMB_MOUNT_OLDVERSION && cpu_to_be32(ver) != SMB_MOUNT_ASCII) | 512 | if (ver != SMB_MOUNT_OLDVERSION && cpu_to_be32(ver) != SMB_MOUNT_ASCII) |
513 | goto out_wrong_data; | 513 | goto out_wrong_data; |
514 | 514 | ||
515 | sb->s_flags |= MS_NODIRATIME; | 515 | sb->s_flags |= MS_NODIRATIME; |
516 | sb->s_blocksize = 1024; /* Eh... Is this correct? */ | 516 | sb->s_blocksize = 1024; /* Eh... Is this correct? */ |
517 | sb->s_blocksize_bits = 10; | 517 | sb->s_blocksize_bits = 10; |
518 | sb->s_magic = SMB_SUPER_MAGIC; | 518 | sb->s_magic = SMB_SUPER_MAGIC; |
519 | sb->s_op = &smb_sops; | 519 | sb->s_op = &smb_sops; |
520 | sb->s_time_gran = 100; | 520 | sb->s_time_gran = 100; |
521 | 521 | ||
522 | server = smb_kmalloc(sizeof(struct smb_sb_info), GFP_KERNEL); | 522 | server = kzalloc(sizeof(struct smb_sb_info), GFP_KERNEL); |
523 | if (!server) | 523 | if (!server) |
524 | goto out_no_server; | 524 | goto out_no_server; |
525 | sb->s_fs_info = server; | 525 | sb->s_fs_info = server; |
526 | memset(server, 0, sizeof(struct smb_sb_info)); | ||
527 | 526 | ||
528 | server->super_block = sb; | 527 | server->super_block = sb; |
529 | server->mnt = NULL; | 528 | server->mnt = NULL; |
530 | server->sock_file = NULL; | 529 | server->sock_file = NULL; |
531 | init_waitqueue_head(&server->conn_wq); | 530 | init_waitqueue_head(&server->conn_wq); |
532 | init_MUTEX(&server->sem); | 531 | init_MUTEX(&server->sem); |
533 | INIT_LIST_HEAD(&server->entry); | 532 | INIT_LIST_HEAD(&server->entry); |
534 | INIT_LIST_HEAD(&server->xmitq); | 533 | INIT_LIST_HEAD(&server->xmitq); |
535 | INIT_LIST_HEAD(&server->recvq); | 534 | INIT_LIST_HEAD(&server->recvq); |
536 | server->conn_error = 0; | 535 | server->conn_error = 0; |
537 | server->conn_pid = 0; | 536 | server->conn_pid = 0; |
538 | server->state = CONN_INVALID; /* no connection yet */ | 537 | server->state = CONN_INVALID; /* no connection yet */ |
539 | server->generation = 0; | 538 | server->generation = 0; |
540 | 539 | ||
541 | /* Allocate the global temp buffer and some superblock helper structs */ | 540 | /* Allocate the global temp buffer and some superblock helper structs */ |
542 | /* FIXME: move these to the smb_sb_info struct */ | 541 | /* FIXME: move these to the smb_sb_info struct */ |
543 | VERBOSE("alloc chunk = %d\n", sizeof(struct smb_ops) + | 542 | VERBOSE("alloc chunk = %d\n", sizeof(struct smb_ops) + |
544 | sizeof(struct smb_mount_data_kernel)); | 543 | sizeof(struct smb_mount_data_kernel)); |
545 | mem = smb_kmalloc(sizeof(struct smb_ops) + | 544 | mem = kmalloc(sizeof(struct smb_ops) + |
546 | sizeof(struct smb_mount_data_kernel), GFP_KERNEL); | 545 | sizeof(struct smb_mount_data_kernel), GFP_KERNEL); |
547 | if (!mem) | 546 | if (!mem) |
548 | goto out_no_mem; | 547 | goto out_no_mem; |
549 | 548 | ||
550 | server->ops = mem; | 549 | server->ops = mem; |
551 | smb_install_null_ops(server->ops); | 550 | smb_install_null_ops(server->ops); |
552 | server->mnt = mem + sizeof(struct smb_ops); | 551 | server->mnt = mem + sizeof(struct smb_ops); |
553 | 552 | ||
554 | /* Setup NLS stuff */ | 553 | /* Setup NLS stuff */ |
555 | server->remote_nls = NULL; | 554 | server->remote_nls = NULL; |
556 | server->local_nls = NULL; | 555 | server->local_nls = NULL; |
557 | 556 | ||
558 | mnt = server->mnt; | 557 | mnt = server->mnt; |
559 | 558 | ||
560 | memset(mnt, 0, sizeof(struct smb_mount_data_kernel)); | 559 | memset(mnt, 0, sizeof(struct smb_mount_data_kernel)); |
561 | strlcpy(mnt->codepage.local_name, CONFIG_NLS_DEFAULT, | 560 | strlcpy(mnt->codepage.local_name, CONFIG_NLS_DEFAULT, |
562 | SMB_NLS_MAXNAMELEN); | 561 | SMB_NLS_MAXNAMELEN); |
563 | strlcpy(mnt->codepage.remote_name, SMB_NLS_REMOTE, | 562 | strlcpy(mnt->codepage.remote_name, SMB_NLS_REMOTE, |
564 | SMB_NLS_MAXNAMELEN); | 563 | SMB_NLS_MAXNAMELEN); |
565 | 564 | ||
566 | mnt->ttl = SMB_TTL_DEFAULT; | 565 | mnt->ttl = SMB_TTL_DEFAULT; |
567 | if (ver == SMB_MOUNT_OLDVERSION) { | 566 | if (ver == SMB_MOUNT_OLDVERSION) { |
568 | mnt->version = oldmnt->version; | 567 | mnt->version = oldmnt->version; |
569 | 568 | ||
570 | SET_UID(mnt->uid, oldmnt->uid); | 569 | SET_UID(mnt->uid, oldmnt->uid); |
571 | SET_GID(mnt->gid, oldmnt->gid); | 570 | SET_GID(mnt->gid, oldmnt->gid); |
572 | 571 | ||
573 | mnt->file_mode = (oldmnt->file_mode & S_IRWXUGO) | S_IFREG; | 572 | mnt->file_mode = (oldmnt->file_mode & S_IRWXUGO) | S_IFREG; |
574 | mnt->dir_mode = (oldmnt->dir_mode & S_IRWXUGO) | S_IFDIR; | 573 | mnt->dir_mode = (oldmnt->dir_mode & S_IRWXUGO) | S_IFDIR; |
575 | 574 | ||
576 | mnt->flags = (oldmnt->file_mode >> 9) | SMB_MOUNT_UID | | 575 | mnt->flags = (oldmnt->file_mode >> 9) | SMB_MOUNT_UID | |
577 | SMB_MOUNT_GID | SMB_MOUNT_FMODE | SMB_MOUNT_DMODE; | 576 | SMB_MOUNT_GID | SMB_MOUNT_FMODE | SMB_MOUNT_DMODE; |
578 | } else { | 577 | } else { |
579 | mnt->file_mode = S_IRWXU | S_IRGRP | S_IXGRP | | 578 | mnt->file_mode = S_IRWXU | S_IRGRP | S_IXGRP | |
580 | S_IROTH | S_IXOTH | S_IFREG; | 579 | S_IROTH | S_IXOTH | S_IFREG; |
581 | mnt->dir_mode = S_IRWXU | S_IRGRP | S_IXGRP | | 580 | mnt->dir_mode = S_IRWXU | S_IRGRP | S_IXGRP | |
582 | S_IROTH | S_IXOTH | S_IFDIR; | 581 | S_IROTH | S_IXOTH | S_IFDIR; |
583 | if (parse_options(mnt, raw_data)) | 582 | if (parse_options(mnt, raw_data)) |
584 | goto out_bad_option; | 583 | goto out_bad_option; |
585 | } | 584 | } |
586 | mnt->mounted_uid = current->uid; | 585 | mnt->mounted_uid = current->uid; |
587 | smb_setcodepage(server, &mnt->codepage); | 586 | smb_setcodepage(server, &mnt->codepage); |
588 | 587 | ||
589 | /* | 588 | /* |
590 | * Display the enabled options | 589 | * Display the enabled options |
591 | * Note: smb_proc_getattr uses these in 2.4 (but was changed in 2.2) | 590 | * Note: smb_proc_getattr uses these in 2.4 (but was changed in 2.2) |
592 | */ | 591 | */ |
593 | if (mnt->flags & SMB_MOUNT_OLDATTR) | 592 | if (mnt->flags & SMB_MOUNT_OLDATTR) |
594 | printk("SMBFS: Using core getattr (Win 95 speedup)\n"); | 593 | printk("SMBFS: Using core getattr (Win 95 speedup)\n"); |
595 | else if (mnt->flags & SMB_MOUNT_DIRATTR) | 594 | else if (mnt->flags & SMB_MOUNT_DIRATTR) |
596 | printk("SMBFS: Using dir ff getattr\n"); | 595 | printk("SMBFS: Using dir ff getattr\n"); |
597 | 596 | ||
598 | if (smbiod_register_server(server) < 0) { | 597 | if (smbiod_register_server(server) < 0) { |
599 | printk(KERN_ERR "smbfs: failed to start smbiod\n"); | 598 | printk(KERN_ERR "smbfs: failed to start smbiod\n"); |
600 | goto out_no_smbiod; | 599 | goto out_no_smbiod; |
601 | } | 600 | } |
602 | 601 | ||
603 | /* | 602 | /* |
604 | * Keep the super block locked while we get the root inode. | 603 | * Keep the super block locked while we get the root inode. |
605 | */ | 604 | */ |
606 | smb_init_root_dirent(server, &root, sb); | 605 | smb_init_root_dirent(server, &root, sb); |
607 | root_inode = smb_iget(sb, &root); | 606 | root_inode = smb_iget(sb, &root); |
608 | if (!root_inode) | 607 | if (!root_inode) |
609 | goto out_no_root; | 608 | goto out_no_root; |
610 | 609 | ||
611 | sb->s_root = d_alloc_root(root_inode); | 610 | sb->s_root = d_alloc_root(root_inode); |
612 | if (!sb->s_root) | 611 | if (!sb->s_root) |
613 | goto out_no_root; | 612 | goto out_no_root; |
614 | 613 | ||
615 | smb_new_dentry(sb->s_root); | 614 | smb_new_dentry(sb->s_root); |
616 | 615 | ||
617 | return 0; | 616 | return 0; |
618 | 617 | ||
619 | out_no_root: | 618 | out_no_root: |
620 | iput(root_inode); | 619 | iput(root_inode); |
621 | out_no_smbiod: | 620 | out_no_smbiod: |
622 | smb_unload_nls(server); | 621 | smb_unload_nls(server); |
623 | out_bad_option: | 622 | out_bad_option: |
624 | smb_kfree(mem); | 623 | kfree(mem); |
625 | out_no_mem: | 624 | out_no_mem: |
626 | if (!server->mnt) | 625 | if (!server->mnt) |
627 | printk(KERN_ERR "smb_fill_super: allocation failure\n"); | 626 | printk(KERN_ERR "smb_fill_super: allocation failure\n"); |
628 | sb->s_fs_info = NULL; | 627 | sb->s_fs_info = NULL; |
629 | smb_kfree(server); | 628 | kfree(server); |
630 | goto out_fail; | 629 | goto out_fail; |
631 | out_wrong_data: | 630 | out_wrong_data: |
632 | printk(KERN_ERR "smbfs: mount_data version %d is not supported\n", ver); | 631 | printk(KERN_ERR "smbfs: mount_data version %d is not supported\n", ver); |
633 | goto out_fail; | 632 | goto out_fail; |
634 | out_no_data: | 633 | out_no_data: |
635 | printk(KERN_ERR "smb_fill_super: missing data argument\n"); | 634 | printk(KERN_ERR "smb_fill_super: missing data argument\n"); |
636 | out_fail: | 635 | out_fail: |
637 | return -EINVAL; | 636 | return -EINVAL; |
638 | out_no_server: | 637 | out_no_server: |
639 | printk(KERN_ERR "smb_fill_super: cannot allocate struct smb_sb_info\n"); | 638 | printk(KERN_ERR "smb_fill_super: cannot allocate struct smb_sb_info\n"); |
640 | return -ENOMEM; | 639 | return -ENOMEM; |
641 | } | 640 | } |
642 | 641 | ||
643 | static int | 642 | static int |
644 | smb_statfs(struct super_block *sb, struct kstatfs *buf) | 643 | smb_statfs(struct super_block *sb, struct kstatfs *buf) |
645 | { | 644 | { |
646 | int result; | 645 | int result; |
647 | 646 | ||
648 | lock_kernel(); | 647 | lock_kernel(); |
649 | 648 | ||
650 | result = smb_proc_dskattr(sb, buf); | 649 | result = smb_proc_dskattr(sb, buf); |
651 | 650 | ||
652 | unlock_kernel(); | 651 | unlock_kernel(); |
653 | 652 | ||
654 | buf->f_type = SMB_SUPER_MAGIC; | 653 | buf->f_type = SMB_SUPER_MAGIC; |
655 | buf->f_namelen = SMB_MAXPATHLEN; | 654 | buf->f_namelen = SMB_MAXPATHLEN; |
656 | return result; | 655 | return result; |
657 | } | 656 | } |
658 | 657 | ||
659 | int smb_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | 658 | int smb_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) |
660 | { | 659 | { |
661 | int err = smb_revalidate_inode(dentry); | 660 | int err = smb_revalidate_inode(dentry); |
662 | if (!err) | 661 | if (!err) |
663 | generic_fillattr(dentry->d_inode, stat); | 662 | generic_fillattr(dentry->d_inode, stat); |
664 | return err; | 663 | return err; |
665 | } | 664 | } |
666 | 665 | ||
667 | int | 666 | int |
668 | smb_notify_change(struct dentry *dentry, struct iattr *attr) | 667 | smb_notify_change(struct dentry *dentry, struct iattr *attr) |
669 | { | 668 | { |
670 | struct inode *inode = dentry->d_inode; | 669 | struct inode *inode = dentry->d_inode; |
671 | struct smb_sb_info *server = server_from_dentry(dentry); | 670 | struct smb_sb_info *server = server_from_dentry(dentry); |
672 | unsigned int mask = (S_IFREG | S_IFDIR | S_IRWXUGO); | 671 | unsigned int mask = (S_IFREG | S_IFDIR | S_IRWXUGO); |
673 | int error, changed, refresh = 0; | 672 | int error, changed, refresh = 0; |
674 | struct smb_fattr fattr; | 673 | struct smb_fattr fattr; |
675 | 674 | ||
676 | lock_kernel(); | 675 | lock_kernel(); |
677 | 676 | ||
678 | error = smb_revalidate_inode(dentry); | 677 | error = smb_revalidate_inode(dentry); |
679 | if (error) | 678 | if (error) |
680 | goto out; | 679 | goto out; |
681 | 680 | ||
682 | if ((error = inode_change_ok(inode, attr)) < 0) | 681 | if ((error = inode_change_ok(inode, attr)) < 0) |
683 | goto out; | 682 | goto out; |
684 | 683 | ||
685 | error = -EPERM; | 684 | error = -EPERM; |
686 | if ((attr->ia_valid & ATTR_UID) && (attr->ia_uid != server->mnt->uid)) | 685 | if ((attr->ia_valid & ATTR_UID) && (attr->ia_uid != server->mnt->uid)) |
687 | goto out; | 686 | goto out; |
688 | 687 | ||
689 | if ((attr->ia_valid & ATTR_GID) && (attr->ia_uid != server->mnt->gid)) | 688 | if ((attr->ia_valid & ATTR_GID) && (attr->ia_uid != server->mnt->gid)) |
690 | goto out; | 689 | goto out; |
691 | 690 | ||
692 | if ((attr->ia_valid & ATTR_MODE) && (attr->ia_mode & ~mask)) | 691 | if ((attr->ia_valid & ATTR_MODE) && (attr->ia_mode & ~mask)) |
693 | goto out; | 692 | goto out; |
694 | 693 | ||
695 | if ((attr->ia_valid & ATTR_SIZE) != 0) { | 694 | if ((attr->ia_valid & ATTR_SIZE) != 0) { |
696 | VERBOSE("changing %s/%s, old size=%ld, new size=%ld\n", | 695 | VERBOSE("changing %s/%s, old size=%ld, new size=%ld\n", |
697 | DENTRY_PATH(dentry), | 696 | DENTRY_PATH(dentry), |
698 | (long) inode->i_size, (long) attr->ia_size); | 697 | (long) inode->i_size, (long) attr->ia_size); |
699 | 698 | ||
700 | filemap_write_and_wait(inode->i_mapping); | 699 | filemap_write_and_wait(inode->i_mapping); |
701 | 700 | ||
702 | error = smb_open(dentry, O_WRONLY); | 701 | error = smb_open(dentry, O_WRONLY); |
703 | if (error) | 702 | if (error) |
704 | goto out; | 703 | goto out; |
705 | error = server->ops->truncate(inode, attr->ia_size); | 704 | error = server->ops->truncate(inode, attr->ia_size); |
706 | if (error) | 705 | if (error) |
707 | goto out; | 706 | goto out; |
708 | error = vmtruncate(inode, attr->ia_size); | 707 | error = vmtruncate(inode, attr->ia_size); |
709 | if (error) | 708 | if (error) |
710 | goto out; | 709 | goto out; |
711 | refresh = 1; | 710 | refresh = 1; |
712 | } | 711 | } |
713 | 712 | ||
714 | if (server->opt.capabilities & SMB_CAP_UNIX) { | 713 | if (server->opt.capabilities & SMB_CAP_UNIX) { |
715 | /* For now we don't want to set the size with setattr_unix */ | 714 | /* For now we don't want to set the size with setattr_unix */ |
716 | attr->ia_valid &= ~ATTR_SIZE; | 715 | attr->ia_valid &= ~ATTR_SIZE; |
717 | /* FIXME: only call if we actually want to set something? */ | 716 | /* FIXME: only call if we actually want to set something? */ |
718 | error = smb_proc_setattr_unix(dentry, attr, 0, 0); | 717 | error = smb_proc_setattr_unix(dentry, attr, 0, 0); |
719 | if (!error) | 718 | if (!error) |
720 | refresh = 1; | 719 | refresh = 1; |
721 | 720 | ||
722 | goto out; | 721 | goto out; |
723 | } | 722 | } |
724 | 723 | ||
725 | /* | 724 | /* |
726 | * Initialize the fattr and check for changed fields. | 725 | * Initialize the fattr and check for changed fields. |
727 | * Note: CTIME under SMB is creation time rather than | 726 | * Note: CTIME under SMB is creation time rather than |
728 | * change time, so we don't attempt to change it. | 727 | * change time, so we don't attempt to change it. |
729 | */ | 728 | */ |
730 | smb_get_inode_attr(inode, &fattr); | 729 | smb_get_inode_attr(inode, &fattr); |
731 | 730 | ||
732 | changed = 0; | 731 | changed = 0; |
733 | if ((attr->ia_valid & ATTR_MTIME) != 0) { | 732 | if ((attr->ia_valid & ATTR_MTIME) != 0) { |
734 | fattr.f_mtime = attr->ia_mtime; | 733 | fattr.f_mtime = attr->ia_mtime; |
735 | changed = 1; | 734 | changed = 1; |
736 | } | 735 | } |
737 | if ((attr->ia_valid & ATTR_ATIME) != 0) { | 736 | if ((attr->ia_valid & ATTR_ATIME) != 0) { |
738 | fattr.f_atime = attr->ia_atime; | 737 | fattr.f_atime = attr->ia_atime; |
739 | /* Earlier protocols don't have an access time */ | 738 | /* Earlier protocols don't have an access time */ |
740 | if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2) | 739 | if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2) |
741 | changed = 1; | 740 | changed = 1; |
742 | } | 741 | } |
743 | if (changed) { | 742 | if (changed) { |
744 | error = smb_proc_settime(dentry, &fattr); | 743 | error = smb_proc_settime(dentry, &fattr); |
745 | if (error) | 744 | if (error) |
746 | goto out; | 745 | goto out; |
747 | refresh = 1; | 746 | refresh = 1; |
748 | } | 747 | } |
749 | 748 | ||
750 | /* | 749 | /* |
751 | * Check for mode changes ... we're extremely limited in | 750 | * Check for mode changes ... we're extremely limited in |
752 | * what can be set for SMB servers: just the read-only bit. | 751 | * what can be set for SMB servers: just the read-only bit. |
753 | */ | 752 | */ |
754 | if ((attr->ia_valid & ATTR_MODE) != 0) { | 753 | if ((attr->ia_valid & ATTR_MODE) != 0) { |
755 | VERBOSE("%s/%s mode change, old=%x, new=%x\n", | 754 | VERBOSE("%s/%s mode change, old=%x, new=%x\n", |
756 | DENTRY_PATH(dentry), fattr.f_mode, attr->ia_mode); | 755 | DENTRY_PATH(dentry), fattr.f_mode, attr->ia_mode); |
757 | changed = 0; | 756 | changed = 0; |
758 | if (attr->ia_mode & S_IWUSR) { | 757 | if (attr->ia_mode & S_IWUSR) { |
759 | if (fattr.attr & aRONLY) { | 758 | if (fattr.attr & aRONLY) { |
760 | fattr.attr &= ~aRONLY; | 759 | fattr.attr &= ~aRONLY; |
761 | changed = 1; | 760 | changed = 1; |
762 | } | 761 | } |
763 | } else { | 762 | } else { |
764 | if (!(fattr.attr & aRONLY)) { | 763 | if (!(fattr.attr & aRONLY)) { |
765 | fattr.attr |= aRONLY; | 764 | fattr.attr |= aRONLY; |
766 | changed = 1; | 765 | changed = 1; |
767 | } | 766 | } |
768 | } | 767 | } |
769 | if (changed) { | 768 | if (changed) { |
770 | error = smb_proc_setattr(dentry, &fattr); | 769 | error = smb_proc_setattr(dentry, &fattr); |
771 | if (error) | 770 | if (error) |
772 | goto out; | 771 | goto out; |
773 | refresh = 1; | 772 | refresh = 1; |
774 | } | 773 | } |
775 | } | 774 | } |
776 | error = 0; | 775 | error = 0; |
777 | 776 | ||
778 | out: | 777 | out: |
779 | if (refresh) | 778 | if (refresh) |
780 | smb_refresh_inode(dentry); | 779 | smb_refresh_inode(dentry); |
781 | unlock_kernel(); | 780 | unlock_kernel(); |
782 | return error; | 781 | return error; |
783 | } | 782 | } |
784 | 783 | ||
785 | #ifdef DEBUG_SMB_MALLOC | ||
786 | int smb_malloced; | ||
787 | int smb_current_kmalloced; | ||
788 | int smb_current_vmalloced; | ||
789 | #endif | ||
790 | |||
791 | static struct super_block *smb_get_sb(struct file_system_type *fs_type, | 784 | static struct super_block *smb_get_sb(struct file_system_type *fs_type, |
792 | int flags, const char *dev_name, void *data) | 785 | int flags, const char *dev_name, void *data) |
793 | { | 786 | { |
794 | return get_sb_nodev(fs_type, flags, data, smb_fill_super); | 787 | return get_sb_nodev(fs_type, flags, data, smb_fill_super); |
795 | } | 788 | } |
796 | 789 | ||
797 | static struct file_system_type smb_fs_type = { | 790 | static struct file_system_type smb_fs_type = { |
798 | .owner = THIS_MODULE, | 791 | .owner = THIS_MODULE, |
799 | .name = "smbfs", | 792 | .name = "smbfs", |
800 | .get_sb = smb_get_sb, | 793 | .get_sb = smb_get_sb, |
801 | .kill_sb = kill_anon_super, | 794 | .kill_sb = kill_anon_super, |
802 | .fs_flags = FS_BINARY_MOUNTDATA, | 795 | .fs_flags = FS_BINARY_MOUNTDATA, |
803 | }; | 796 | }; |
804 | 797 | ||
805 | static int __init init_smb_fs(void) | 798 | static int __init init_smb_fs(void) |
806 | { | 799 | { |
807 | int err; | 800 | int err; |
808 | DEBUG1("registering ...\n"); | 801 | DEBUG1("registering ...\n"); |
809 | 802 | ||
810 | #ifdef DEBUG_SMB_MALLOC | ||
811 | smb_malloced = 0; | ||
812 | smb_current_kmalloced = 0; | ||
813 | smb_current_vmalloced = 0; | ||
814 | #endif | ||
815 | |||
816 | err = init_inodecache(); | 803 | err = init_inodecache(); |
817 | if (err) | 804 | if (err) |
818 | goto out_inode; | 805 | goto out_inode; |
819 | err = smb_init_request_cache(); | 806 | err = smb_init_request_cache(); |
820 | if (err) | 807 | if (err) |
821 | goto out_request; | 808 | goto out_request; |
822 | err = register_filesystem(&smb_fs_type); | 809 | err = register_filesystem(&smb_fs_type); |
823 | if (err) | 810 | if (err) |
824 | goto out; | 811 | goto out; |
825 | return 0; | 812 | return 0; |
826 | out: | 813 | out: |
827 | smb_destroy_request_cache(); | 814 | smb_destroy_request_cache(); |
828 | out_request: | 815 | out_request: |
829 | destroy_inodecache(); | 816 | destroy_inodecache(); |
830 | out_inode: | 817 | out_inode: |
831 | return err; | 818 | return err; |
832 | } | 819 | } |
833 | 820 | ||
834 | static void __exit exit_smb_fs(void) | 821 | static void __exit exit_smb_fs(void) |
835 | { | 822 | { |
836 | DEBUG1("unregistering ...\n"); | 823 | DEBUG1("unregistering ...\n"); |
837 | unregister_filesystem(&smb_fs_type); | 824 | unregister_filesystem(&smb_fs_type); |
838 | smb_destroy_request_cache(); | 825 | smb_destroy_request_cache(); |
839 | destroy_inodecache(); | 826 | destroy_inodecache(); |
840 | #ifdef DEBUG_SMB_MALLOC | ||
841 | printk(KERN_DEBUG "smb_malloced: %d\n", smb_malloced); | ||
842 | printk(KERN_DEBUG "smb_current_kmalloced: %d\n",smb_current_kmalloced); | ||
843 | printk(KERN_DEBUG "smb_current_vmalloced: %d\n",smb_current_vmalloced); | ||
844 | #endif | ||
845 | } | 827 | } |
846 | 828 | ||
847 | module_init(init_smb_fs) | 829 | module_init(init_smb_fs) |
848 | module_exit(exit_smb_fs) | 830 | module_exit(exit_smb_fs) |
849 | MODULE_LICENSE("GPL"); | 831 | MODULE_LICENSE("GPL"); |
850 | 832 |
fs/smbfs/request.c
1 | /* | 1 | /* |
2 | * request.c | 2 | * request.c |
3 | * | 3 | * |
4 | * Copyright (C) 2001 by Urban Widmark | 4 | * Copyright (C) 2001 by Urban Widmark |
5 | * | 5 | * |
6 | * Please add a note about your changes to smbfs in the ChangeLog file. | 6 | * Please add a note about your changes to smbfs in the ChangeLog file. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/types.h> | 9 | #include <linux/types.h> |
10 | #include <linux/fs.h> | 10 | #include <linux/fs.h> |
11 | #include <linux/slab.h> | 11 | #include <linux/slab.h> |
12 | #include <linux/net.h> | 12 | #include <linux/net.h> |
13 | 13 | ||
14 | #include <linux/smb_fs.h> | 14 | #include <linux/smb_fs.h> |
15 | #include <linux/smbno.h> | 15 | #include <linux/smbno.h> |
16 | #include <linux/smb_mount.h> | 16 | #include <linux/smb_mount.h> |
17 | 17 | ||
18 | #include "smb_debug.h" | 18 | #include "smb_debug.h" |
19 | #include "request.h" | 19 | #include "request.h" |
20 | #include "proto.h" | 20 | #include "proto.h" |
21 | 21 | ||
22 | /* #define SMB_SLAB_DEBUG (SLAB_RED_ZONE | SLAB_POISON) */ | 22 | /* #define SMB_SLAB_DEBUG (SLAB_RED_ZONE | SLAB_POISON) */ |
23 | #define SMB_SLAB_DEBUG 0 | 23 | #define SMB_SLAB_DEBUG 0 |
24 | 24 | ||
25 | #define ROUND_UP(x) (((x)+3) & ~3) | 25 | #define ROUND_UP(x) (((x)+3) & ~3) |
26 | 26 | ||
27 | /* cache for request structures */ | 27 | /* cache for request structures */ |
28 | static kmem_cache_t *req_cachep; | 28 | static kmem_cache_t *req_cachep; |
29 | 29 | ||
30 | static int smb_request_send_req(struct smb_request *req); | 30 | static int smb_request_send_req(struct smb_request *req); |
31 | 31 | ||
32 | /* | 32 | /* |
33 | /proc/slabinfo: | 33 | /proc/slabinfo: |
34 | name, active, num, objsize, active_slabs, num_slaps, #pages | 34 | name, active, num, objsize, active_slabs, num_slaps, #pages |
35 | */ | 35 | */ |
36 | 36 | ||
37 | 37 | ||
38 | int smb_init_request_cache(void) | 38 | int smb_init_request_cache(void) |
39 | { | 39 | { |
40 | req_cachep = kmem_cache_create("smb_request", | 40 | req_cachep = kmem_cache_create("smb_request", |
41 | sizeof(struct smb_request), 0, | 41 | sizeof(struct smb_request), 0, |
42 | SMB_SLAB_DEBUG | SLAB_HWCACHE_ALIGN, | 42 | SMB_SLAB_DEBUG | SLAB_HWCACHE_ALIGN, |
43 | NULL, NULL); | 43 | NULL, NULL); |
44 | if (req_cachep == NULL) | 44 | if (req_cachep == NULL) |
45 | return -ENOMEM; | 45 | return -ENOMEM; |
46 | 46 | ||
47 | return 0; | 47 | return 0; |
48 | } | 48 | } |
49 | 49 | ||
50 | void smb_destroy_request_cache(void) | 50 | void smb_destroy_request_cache(void) |
51 | { | 51 | { |
52 | if (kmem_cache_destroy(req_cachep)) | 52 | if (kmem_cache_destroy(req_cachep)) |
53 | printk(KERN_INFO "smb_destroy_request_cache: not all structures were freed\n"); | 53 | printk(KERN_INFO "smb_destroy_request_cache: not all structures were freed\n"); |
54 | } | 54 | } |
55 | 55 | ||
56 | /* | 56 | /* |
57 | * Allocate and initialise a request structure | 57 | * Allocate and initialise a request structure |
58 | */ | 58 | */ |
59 | static struct smb_request *smb_do_alloc_request(struct smb_sb_info *server, | 59 | static struct smb_request *smb_do_alloc_request(struct smb_sb_info *server, |
60 | int bufsize) | 60 | int bufsize) |
61 | { | 61 | { |
62 | struct smb_request *req; | 62 | struct smb_request *req; |
63 | unsigned char *buf = NULL; | 63 | unsigned char *buf = NULL; |
64 | 64 | ||
65 | req = kmem_cache_alloc(req_cachep, SLAB_KERNEL); | 65 | req = kmem_cache_alloc(req_cachep, SLAB_KERNEL); |
66 | VERBOSE("allocating request: %p\n", req); | 66 | VERBOSE("allocating request: %p\n", req); |
67 | if (!req) | 67 | if (!req) |
68 | goto out; | 68 | goto out; |
69 | 69 | ||
70 | if (bufsize > 0) { | 70 | if (bufsize > 0) { |
71 | buf = smb_kmalloc(bufsize, GFP_NOFS); | 71 | buf = kmalloc(bufsize, GFP_NOFS); |
72 | if (!buf) { | 72 | if (!buf) { |
73 | kmem_cache_free(req_cachep, req); | 73 | kmem_cache_free(req_cachep, req); |
74 | return NULL; | 74 | return NULL; |
75 | } | 75 | } |
76 | } | 76 | } |
77 | 77 | ||
78 | memset(req, 0, sizeof(struct smb_request)); | 78 | memset(req, 0, sizeof(struct smb_request)); |
79 | req->rq_buffer = buf; | 79 | req->rq_buffer = buf; |
80 | req->rq_bufsize = bufsize; | 80 | req->rq_bufsize = bufsize; |
81 | req->rq_server = server; | 81 | req->rq_server = server; |
82 | init_waitqueue_head(&req->rq_wait); | 82 | init_waitqueue_head(&req->rq_wait); |
83 | INIT_LIST_HEAD(&req->rq_queue); | 83 | INIT_LIST_HEAD(&req->rq_queue); |
84 | atomic_set(&req->rq_count, 1); | 84 | atomic_set(&req->rq_count, 1); |
85 | 85 | ||
86 | out: | 86 | out: |
87 | return req; | 87 | return req; |
88 | } | 88 | } |
89 | 89 | ||
90 | struct smb_request *smb_alloc_request(struct smb_sb_info *server, int bufsize) | 90 | struct smb_request *smb_alloc_request(struct smb_sb_info *server, int bufsize) |
91 | { | 91 | { |
92 | struct smb_request *req = NULL; | 92 | struct smb_request *req = NULL; |
93 | 93 | ||
94 | for (;;) { | 94 | for (;;) { |
95 | atomic_inc(&server->nr_requests); | 95 | atomic_inc(&server->nr_requests); |
96 | if (atomic_read(&server->nr_requests) <= MAX_REQUEST_HARD) { | 96 | if (atomic_read(&server->nr_requests) <= MAX_REQUEST_HARD) { |
97 | req = smb_do_alloc_request(server, bufsize); | 97 | req = smb_do_alloc_request(server, bufsize); |
98 | if (req != NULL) | 98 | if (req != NULL) |
99 | break; | 99 | break; |
100 | } | 100 | } |
101 | 101 | ||
102 | #if 0 | 102 | #if 0 |
103 | /* | 103 | /* |
104 | * Try to free up at least one request in order to stay | 104 | * Try to free up at least one request in order to stay |
105 | * below the hard limit | 105 | * below the hard limit |
106 | */ | 106 | */ |
107 | if (nfs_try_to_free_pages(server)) | 107 | if (nfs_try_to_free_pages(server)) |
108 | continue; | 108 | continue; |
109 | 109 | ||
110 | if (signalled() && (server->flags & NFS_MOUNT_INTR)) | 110 | if (signalled() && (server->flags & NFS_MOUNT_INTR)) |
111 | return ERR_PTR(-ERESTARTSYS); | 111 | return ERR_PTR(-ERESTARTSYS); |
112 | current->policy = SCHED_YIELD; | 112 | current->policy = SCHED_YIELD; |
113 | schedule(); | 113 | schedule(); |
114 | #else | 114 | #else |
115 | /* FIXME: we want something like nfs does above, but that | 115 | /* FIXME: we want something like nfs does above, but that |
116 | requires changes to all callers and can wait. */ | 116 | requires changes to all callers and can wait. */ |
117 | break; | 117 | break; |
118 | #endif | 118 | #endif |
119 | } | 119 | } |
120 | return req; | 120 | return req; |
121 | } | 121 | } |
122 | 122 | ||
123 | static void smb_free_request(struct smb_request *req) | 123 | static void smb_free_request(struct smb_request *req) |
124 | { | 124 | { |
125 | atomic_dec(&req->rq_server->nr_requests); | 125 | atomic_dec(&req->rq_server->nr_requests); |
126 | if (req->rq_buffer && !(req->rq_flags & SMB_REQ_STATIC)) | 126 | if (req->rq_buffer && !(req->rq_flags & SMB_REQ_STATIC)) |
127 | smb_kfree(req->rq_buffer); | 127 | kfree(req->rq_buffer); |
128 | if (req->rq_trans2buffer) | 128 | kfree(req->rq_trans2buffer); |
129 | smb_kfree(req->rq_trans2buffer); | ||
130 | kmem_cache_free(req_cachep, req); | 129 | kmem_cache_free(req_cachep, req); |
131 | } | 130 | } |
132 | 131 | ||
133 | /* | 132 | /* |
134 | * What prevents a rget to race with a rput? The count must never drop to zero | 133 | * What prevents a rget to race with a rput? The count must never drop to zero |
135 | * while it is in use. Only rput if it is ok that it is free'd. | 134 | * while it is in use. Only rput if it is ok that it is free'd. |
136 | */ | 135 | */ |
137 | static void smb_rget(struct smb_request *req) | 136 | static void smb_rget(struct smb_request *req) |
138 | { | 137 | { |
139 | atomic_inc(&req->rq_count); | 138 | atomic_inc(&req->rq_count); |
140 | } | 139 | } |
141 | void smb_rput(struct smb_request *req) | 140 | void smb_rput(struct smb_request *req) |
142 | { | 141 | { |
143 | if (atomic_dec_and_test(&req->rq_count)) { | 142 | if (atomic_dec_and_test(&req->rq_count)) { |
144 | list_del_init(&req->rq_queue); | 143 | list_del_init(&req->rq_queue); |
145 | smb_free_request(req); | 144 | smb_free_request(req); |
146 | } | 145 | } |
147 | } | 146 | } |
148 | 147 | ||
149 | /* setup to receive the data part of the SMB */ | 148 | /* setup to receive the data part of the SMB */ |
150 | static int smb_setup_bcc(struct smb_request *req) | 149 | static int smb_setup_bcc(struct smb_request *req) |
151 | { | 150 | { |
152 | int result = 0; | 151 | int result = 0; |
153 | req->rq_rlen = smb_len(req->rq_header) + 4 - req->rq_bytes_recvd; | 152 | req->rq_rlen = smb_len(req->rq_header) + 4 - req->rq_bytes_recvd; |
154 | 153 | ||
155 | if (req->rq_rlen > req->rq_bufsize) { | 154 | if (req->rq_rlen > req->rq_bufsize) { |
156 | PARANOIA("Packet too large %d > %d\n", | 155 | PARANOIA("Packet too large %d > %d\n", |
157 | req->rq_rlen, req->rq_bufsize); | 156 | req->rq_rlen, req->rq_bufsize); |
158 | return -ENOBUFS; | 157 | return -ENOBUFS; |
159 | } | 158 | } |
160 | 159 | ||
161 | req->rq_iov[0].iov_base = req->rq_buffer; | 160 | req->rq_iov[0].iov_base = req->rq_buffer; |
162 | req->rq_iov[0].iov_len = req->rq_rlen; | 161 | req->rq_iov[0].iov_len = req->rq_rlen; |
163 | req->rq_iovlen = 1; | 162 | req->rq_iovlen = 1; |
164 | 163 | ||
165 | return result; | 164 | return result; |
166 | } | 165 | } |
167 | 166 | ||
168 | /* | 167 | /* |
169 | * Prepare a "normal" request structure. | 168 | * Prepare a "normal" request structure. |
170 | */ | 169 | */ |
171 | static int smb_setup_request(struct smb_request *req) | 170 | static int smb_setup_request(struct smb_request *req) |
172 | { | 171 | { |
173 | int len = smb_len(req->rq_header) + 4; | 172 | int len = smb_len(req->rq_header) + 4; |
174 | req->rq_slen = len; | 173 | req->rq_slen = len; |
175 | 174 | ||
176 | /* if we expect a data part in the reply we set the iov's to read it */ | 175 | /* if we expect a data part in the reply we set the iov's to read it */ |
177 | if (req->rq_resp_bcc) | 176 | if (req->rq_resp_bcc) |
178 | req->rq_setup_read = smb_setup_bcc; | 177 | req->rq_setup_read = smb_setup_bcc; |
179 | 178 | ||
180 | /* This tries to support re-using the same request */ | 179 | /* This tries to support re-using the same request */ |
181 | req->rq_bytes_sent = 0; | 180 | req->rq_bytes_sent = 0; |
182 | req->rq_rcls = 0; | 181 | req->rq_rcls = 0; |
183 | req->rq_err = 0; | 182 | req->rq_err = 0; |
184 | req->rq_errno = 0; | 183 | req->rq_errno = 0; |
185 | req->rq_fragment = 0; | 184 | req->rq_fragment = 0; |
186 | if (req->rq_trans2buffer) | 185 | kfree(req->rq_trans2buffer); |
187 | smb_kfree(req->rq_trans2buffer); | ||
188 | 186 | ||
189 | return 0; | 187 | return 0; |
190 | } | 188 | } |
191 | 189 | ||
192 | /* | 190 | /* |
193 | * Prepare a transaction2 request structure | 191 | * Prepare a transaction2 request structure |
194 | */ | 192 | */ |
195 | static int smb_setup_trans2request(struct smb_request *req) | 193 | static int smb_setup_trans2request(struct smb_request *req) |
196 | { | 194 | { |
197 | struct smb_sb_info *server = req->rq_server; | 195 | struct smb_sb_info *server = req->rq_server; |
198 | int mparam, mdata; | 196 | int mparam, mdata; |
199 | static unsigned char padding[4]; | 197 | static unsigned char padding[4]; |
200 | 198 | ||
201 | /* I know the following is very ugly, but I want to build the | 199 | /* I know the following is very ugly, but I want to build the |
202 | smb packet as efficiently as possible. */ | 200 | smb packet as efficiently as possible. */ |
203 | 201 | ||
204 | const int smb_parameters = 15; | 202 | const int smb_parameters = 15; |
205 | const int header = SMB_HEADER_LEN + 2 * smb_parameters + 2; | 203 | const int header = SMB_HEADER_LEN + 2 * smb_parameters + 2; |
206 | const int oparam = ROUND_UP(header + 3); | 204 | const int oparam = ROUND_UP(header + 3); |
207 | const int odata = ROUND_UP(oparam + req->rq_lparm); | 205 | const int odata = ROUND_UP(oparam + req->rq_lparm); |
208 | const int bcc = (req->rq_data ? odata + req->rq_ldata : | 206 | const int bcc = (req->rq_data ? odata + req->rq_ldata : |
209 | oparam + req->rq_lparm) - header; | 207 | oparam + req->rq_lparm) - header; |
210 | 208 | ||
211 | if ((bcc + oparam) > server->opt.max_xmit) | 209 | if ((bcc + oparam) > server->opt.max_xmit) |
212 | return -ENOMEM; | 210 | return -ENOMEM; |
213 | smb_setup_header(req, SMBtrans2, smb_parameters, bcc); | 211 | smb_setup_header(req, SMBtrans2, smb_parameters, bcc); |
214 | 212 | ||
215 | /* | 213 | /* |
216 | * max parameters + max data + max setup == bufsize to make NT4 happy | 214 | * max parameters + max data + max setup == bufsize to make NT4 happy |
217 | * and not abort the transfer or split into multiple responses. It also | 215 | * and not abort the transfer or split into multiple responses. It also |
218 | * makes smbfs happy as handling packets larger than the buffer size | 216 | * makes smbfs happy as handling packets larger than the buffer size |
219 | * is extra work. | 217 | * is extra work. |
220 | * | 218 | * |
221 | * OS/2 is probably going to hate me for this ... | 219 | * OS/2 is probably going to hate me for this ... |
222 | */ | 220 | */ |
223 | mparam = SMB_TRANS2_MAX_PARAM; | 221 | mparam = SMB_TRANS2_MAX_PARAM; |
224 | mdata = req->rq_bufsize - mparam; | 222 | mdata = req->rq_bufsize - mparam; |
225 | 223 | ||
226 | mdata = server->opt.max_xmit - mparam - 100; | 224 | mdata = server->opt.max_xmit - mparam - 100; |
227 | if (mdata < 1024) { | 225 | if (mdata < 1024) { |
228 | mdata = 1024; | 226 | mdata = 1024; |
229 | mparam = 20; | 227 | mparam = 20; |
230 | } | 228 | } |
231 | 229 | ||
232 | #if 0 | 230 | #if 0 |
233 | /* NT/win2k has ~4k max_xmit, so with this we request more than it wants | 231 | /* NT/win2k has ~4k max_xmit, so with this we request more than it wants |
234 | to return as one SMB. Useful for testing the fragmented trans2 | 232 | to return as one SMB. Useful for testing the fragmented trans2 |
235 | handling. */ | 233 | handling. */ |
236 | mdata = 8192; | 234 | mdata = 8192; |
237 | #endif | 235 | #endif |
238 | 236 | ||
239 | WSET(req->rq_header, smb_tpscnt, req->rq_lparm); | 237 | WSET(req->rq_header, smb_tpscnt, req->rq_lparm); |
240 | WSET(req->rq_header, smb_tdscnt, req->rq_ldata); | 238 | WSET(req->rq_header, smb_tdscnt, req->rq_ldata); |
241 | WSET(req->rq_header, smb_mprcnt, mparam); | 239 | WSET(req->rq_header, smb_mprcnt, mparam); |
242 | WSET(req->rq_header, smb_mdrcnt, mdata); | 240 | WSET(req->rq_header, smb_mdrcnt, mdata); |
243 | WSET(req->rq_header, smb_msrcnt, 0); /* max setup always 0 ? */ | 241 | WSET(req->rq_header, smb_msrcnt, 0); /* max setup always 0 ? */ |
244 | WSET(req->rq_header, smb_flags, 0); | 242 | WSET(req->rq_header, smb_flags, 0); |
245 | DSET(req->rq_header, smb_timeout, 0); | 243 | DSET(req->rq_header, smb_timeout, 0); |
246 | WSET(req->rq_header, smb_pscnt, req->rq_lparm); | 244 | WSET(req->rq_header, smb_pscnt, req->rq_lparm); |
247 | WSET(req->rq_header, smb_psoff, oparam - 4); | 245 | WSET(req->rq_header, smb_psoff, oparam - 4); |
248 | WSET(req->rq_header, smb_dscnt, req->rq_ldata); | 246 | WSET(req->rq_header, smb_dscnt, req->rq_ldata); |
249 | WSET(req->rq_header, smb_dsoff, req->rq_data ? odata - 4 : 0); | 247 | WSET(req->rq_header, smb_dsoff, req->rq_data ? odata - 4 : 0); |
250 | *(req->rq_header + smb_suwcnt) = 0x01; /* setup count */ | 248 | *(req->rq_header + smb_suwcnt) = 0x01; /* setup count */ |
251 | *(req->rq_header + smb_suwcnt + 1) = 0x00; /* reserved */ | 249 | *(req->rq_header + smb_suwcnt + 1) = 0x00; /* reserved */ |
252 | WSET(req->rq_header, smb_setup0, req->rq_trans2_command); | 250 | WSET(req->rq_header, smb_setup0, req->rq_trans2_command); |
253 | 251 | ||
254 | req->rq_iovlen = 2; | 252 | req->rq_iovlen = 2; |
255 | req->rq_iov[0].iov_base = (void *) req->rq_header; | 253 | req->rq_iov[0].iov_base = (void *) req->rq_header; |
256 | req->rq_iov[0].iov_len = oparam; | 254 | req->rq_iov[0].iov_len = oparam; |
257 | req->rq_iov[1].iov_base = (req->rq_parm==NULL) ? padding : req->rq_parm; | 255 | req->rq_iov[1].iov_base = (req->rq_parm==NULL) ? padding : req->rq_parm; |
258 | req->rq_iov[1].iov_len = req->rq_lparm; | 256 | req->rq_iov[1].iov_len = req->rq_lparm; |
259 | req->rq_slen = oparam + req->rq_lparm; | 257 | req->rq_slen = oparam + req->rq_lparm; |
260 | 258 | ||
261 | if (req->rq_data) { | 259 | if (req->rq_data) { |
262 | req->rq_iovlen += 2; | 260 | req->rq_iovlen += 2; |
263 | req->rq_iov[2].iov_base = padding; | 261 | req->rq_iov[2].iov_base = padding; |
264 | req->rq_iov[2].iov_len = odata - oparam - req->rq_lparm; | 262 | req->rq_iov[2].iov_len = odata - oparam - req->rq_lparm; |
265 | req->rq_iov[3].iov_base = req->rq_data; | 263 | req->rq_iov[3].iov_base = req->rq_data; |
266 | req->rq_iov[3].iov_len = req->rq_ldata; | 264 | req->rq_iov[3].iov_len = req->rq_ldata; |
267 | req->rq_slen = odata + req->rq_ldata; | 265 | req->rq_slen = odata + req->rq_ldata; |
268 | } | 266 | } |
269 | 267 | ||
270 | /* always a data part for trans2 replies */ | 268 | /* always a data part for trans2 replies */ |
271 | req->rq_setup_read = smb_setup_bcc; | 269 | req->rq_setup_read = smb_setup_bcc; |
272 | 270 | ||
273 | return 0; | 271 | return 0; |
274 | } | 272 | } |
275 | 273 | ||
276 | /* | 274 | /* |
277 | * Add a request and tell smbiod to process it | 275 | * Add a request and tell smbiod to process it |
278 | */ | 276 | */ |
279 | int smb_add_request(struct smb_request *req) | 277 | int smb_add_request(struct smb_request *req) |
280 | { | 278 | { |
281 | long timeleft; | 279 | long timeleft; |
282 | struct smb_sb_info *server = req->rq_server; | 280 | struct smb_sb_info *server = req->rq_server; |
283 | int result = 0; | 281 | int result = 0; |
284 | 282 | ||
285 | smb_setup_request(req); | 283 | smb_setup_request(req); |
286 | if (req->rq_trans2_command) { | 284 | if (req->rq_trans2_command) { |
287 | if (req->rq_buffer == NULL) { | 285 | if (req->rq_buffer == NULL) { |
288 | PARANOIA("trans2 attempted without response buffer!\n"); | 286 | PARANOIA("trans2 attempted without response buffer!\n"); |
289 | return -EIO; | 287 | return -EIO; |
290 | } | 288 | } |
291 | result = smb_setup_trans2request(req); | 289 | result = smb_setup_trans2request(req); |
292 | } | 290 | } |
293 | if (result < 0) | 291 | if (result < 0) |
294 | return result; | 292 | return result; |
295 | 293 | ||
296 | #ifdef SMB_DEBUG_PACKET_SIZE | 294 | #ifdef SMB_DEBUG_PACKET_SIZE |
297 | add_xmit_stats(req); | 295 | add_xmit_stats(req); |
298 | #endif | 296 | #endif |
299 | 297 | ||
300 | /* add 'req' to the queue of requests */ | 298 | /* add 'req' to the queue of requests */ |
301 | if (smb_lock_server_interruptible(server)) | 299 | if (smb_lock_server_interruptible(server)) |
302 | return -EINTR; | 300 | return -EINTR; |
303 | 301 | ||
304 | /* | 302 | /* |
305 | * Try to send the request as the process. If that fails we queue the | 303 | * Try to send the request as the process. If that fails we queue the |
306 | * request and let smbiod send it later. | 304 | * request and let smbiod send it later. |
307 | */ | 305 | */ |
308 | 306 | ||
309 | /* FIXME: each server has a number on the maximum number of parallel | 307 | /* FIXME: each server has a number on the maximum number of parallel |
310 | requests. 10, 50 or so. We should not allow more requests to be | 308 | requests. 10, 50 or so. We should not allow more requests to be |
311 | active. */ | 309 | active. */ |
312 | if (server->mid > 0xf000) | 310 | if (server->mid > 0xf000) |
313 | server->mid = 0; | 311 | server->mid = 0; |
314 | req->rq_mid = server->mid++; | 312 | req->rq_mid = server->mid++; |
315 | WSET(req->rq_header, smb_mid, req->rq_mid); | 313 | WSET(req->rq_header, smb_mid, req->rq_mid); |
316 | 314 | ||
317 | result = 0; | 315 | result = 0; |
318 | if (server->state == CONN_VALID) { | 316 | if (server->state == CONN_VALID) { |
319 | if (list_empty(&server->xmitq)) | 317 | if (list_empty(&server->xmitq)) |
320 | result = smb_request_send_req(req); | 318 | result = smb_request_send_req(req); |
321 | if (result < 0) { | 319 | if (result < 0) { |
322 | /* Connection lost? */ | 320 | /* Connection lost? */ |
323 | server->conn_error = result; | 321 | server->conn_error = result; |
324 | server->state = CONN_INVALID; | 322 | server->state = CONN_INVALID; |
325 | } | 323 | } |
326 | } | 324 | } |
327 | if (result != 1) | 325 | if (result != 1) |
328 | list_add_tail(&req->rq_queue, &server->xmitq); | 326 | list_add_tail(&req->rq_queue, &server->xmitq); |
329 | smb_rget(req); | 327 | smb_rget(req); |
330 | 328 | ||
331 | if (server->state != CONN_VALID) | 329 | if (server->state != CONN_VALID) |
332 | smbiod_retry(server); | 330 | smbiod_retry(server); |
333 | 331 | ||
334 | smb_unlock_server(server); | 332 | smb_unlock_server(server); |
335 | 333 | ||
336 | smbiod_wake_up(); | 334 | smbiod_wake_up(); |
337 | 335 | ||
338 | timeleft = wait_event_interruptible_timeout(req->rq_wait, | 336 | timeleft = wait_event_interruptible_timeout(req->rq_wait, |
339 | req->rq_flags & SMB_REQ_RECEIVED, 30*HZ); | 337 | req->rq_flags & SMB_REQ_RECEIVED, 30*HZ); |
340 | if (!timeleft || signal_pending(current)) { | 338 | if (!timeleft || signal_pending(current)) { |
341 | /* | 339 | /* |
342 | * On timeout or on interrupt we want to try and remove the | 340 | * On timeout or on interrupt we want to try and remove the |
343 | * request from the recvq/xmitq. | 341 | * request from the recvq/xmitq. |
344 | */ | 342 | */ |
345 | smb_lock_server(server); | 343 | smb_lock_server(server); |
346 | if (!(req->rq_flags & SMB_REQ_RECEIVED)) { | 344 | if (!(req->rq_flags & SMB_REQ_RECEIVED)) { |
347 | list_del_init(&req->rq_queue); | 345 | list_del_init(&req->rq_queue); |
348 | smb_rput(req); | 346 | smb_rput(req); |
349 | } | 347 | } |
350 | smb_unlock_server(server); | 348 | smb_unlock_server(server); |
351 | } | 349 | } |
352 | 350 | ||
353 | if (!timeleft) { | 351 | if (!timeleft) { |
354 | PARANOIA("request [%p, mid=%d] timed out!\n", | 352 | PARANOIA("request [%p, mid=%d] timed out!\n", |
355 | req, req->rq_mid); | 353 | req, req->rq_mid); |
356 | VERBOSE("smb_com: %02x\n", *(req->rq_header + smb_com)); | 354 | VERBOSE("smb_com: %02x\n", *(req->rq_header + smb_com)); |
357 | VERBOSE("smb_rcls: %02x\n", *(req->rq_header + smb_rcls)); | 355 | VERBOSE("smb_rcls: %02x\n", *(req->rq_header + smb_rcls)); |
358 | VERBOSE("smb_flg: %02x\n", *(req->rq_header + smb_flg)); | 356 | VERBOSE("smb_flg: %02x\n", *(req->rq_header + smb_flg)); |
359 | VERBOSE("smb_tid: %04x\n", WVAL(req->rq_header, smb_tid)); | 357 | VERBOSE("smb_tid: %04x\n", WVAL(req->rq_header, smb_tid)); |
360 | VERBOSE("smb_pid: %04x\n", WVAL(req->rq_header, smb_pid)); | 358 | VERBOSE("smb_pid: %04x\n", WVAL(req->rq_header, smb_pid)); |
361 | VERBOSE("smb_uid: %04x\n", WVAL(req->rq_header, smb_uid)); | 359 | VERBOSE("smb_uid: %04x\n", WVAL(req->rq_header, smb_uid)); |
362 | VERBOSE("smb_mid: %04x\n", WVAL(req->rq_header, smb_mid)); | 360 | VERBOSE("smb_mid: %04x\n", WVAL(req->rq_header, smb_mid)); |
363 | VERBOSE("smb_wct: %02x\n", *(req->rq_header + smb_wct)); | 361 | VERBOSE("smb_wct: %02x\n", *(req->rq_header + smb_wct)); |
364 | 362 | ||
365 | req->rq_rcls = ERRSRV; | 363 | req->rq_rcls = ERRSRV; |
366 | req->rq_err = ERRtimeout; | 364 | req->rq_err = ERRtimeout; |
367 | 365 | ||
368 | /* Just in case it was "stuck" */ | 366 | /* Just in case it was "stuck" */ |
369 | smbiod_wake_up(); | 367 | smbiod_wake_up(); |
370 | } | 368 | } |
371 | VERBOSE("woke up, rcls=%d\n", req->rq_rcls); | 369 | VERBOSE("woke up, rcls=%d\n", req->rq_rcls); |
372 | 370 | ||
373 | if (req->rq_rcls != 0) | 371 | if (req->rq_rcls != 0) |
374 | req->rq_errno = smb_errno(req); | 372 | req->rq_errno = smb_errno(req); |
375 | if (signal_pending(current)) | 373 | if (signal_pending(current)) |
376 | req->rq_errno = -ERESTARTSYS; | 374 | req->rq_errno = -ERESTARTSYS; |
377 | return req->rq_errno; | 375 | return req->rq_errno; |
378 | } | 376 | } |
379 | 377 | ||
380 | /* | 378 | /* |
381 | * Send a request and place it on the recvq if successfully sent. | 379 | * Send a request and place it on the recvq if successfully sent. |
382 | * Must be called with the server lock held. | 380 | * Must be called with the server lock held. |
383 | */ | 381 | */ |
384 | static int smb_request_send_req(struct smb_request *req) | 382 | static int smb_request_send_req(struct smb_request *req) |
385 | { | 383 | { |
386 | struct smb_sb_info *server = req->rq_server; | 384 | struct smb_sb_info *server = req->rq_server; |
387 | int result; | 385 | int result; |
388 | 386 | ||
389 | if (req->rq_bytes_sent == 0) { | 387 | if (req->rq_bytes_sent == 0) { |
390 | WSET(req->rq_header, smb_tid, server->opt.tid); | 388 | WSET(req->rq_header, smb_tid, server->opt.tid); |
391 | WSET(req->rq_header, smb_pid, 1); | 389 | WSET(req->rq_header, smb_pid, 1); |
392 | WSET(req->rq_header, smb_uid, server->opt.server_uid); | 390 | WSET(req->rq_header, smb_uid, server->opt.server_uid); |
393 | } | 391 | } |
394 | 392 | ||
395 | result = smb_send_request(req); | 393 | result = smb_send_request(req); |
396 | if (result < 0 && result != -EAGAIN) | 394 | if (result < 0 && result != -EAGAIN) |
397 | goto out; | 395 | goto out; |
398 | 396 | ||
399 | result = 0; | 397 | result = 0; |
400 | if (!(req->rq_flags & SMB_REQ_TRANSMITTED)) | 398 | if (!(req->rq_flags & SMB_REQ_TRANSMITTED)) |
401 | goto out; | 399 | goto out; |
402 | 400 | ||
403 | list_del_init(&req->rq_queue); | 401 | list_del_init(&req->rq_queue); |
404 | list_add_tail(&req->rq_queue, &server->recvq); | 402 | list_add_tail(&req->rq_queue, &server->recvq); |
405 | result = 1; | 403 | result = 1; |
406 | out: | 404 | out: |
407 | return result; | 405 | return result; |
408 | } | 406 | } |
409 | 407 | ||
410 | /* | 408 | /* |
411 | * Sends one request for this server. (smbiod) | 409 | * Sends one request for this server. (smbiod) |
412 | * Must be called with the server lock held. | 410 | * Must be called with the server lock held. |
413 | * Returns: <0 on error | 411 | * Returns: <0 on error |
414 | * 0 if no request could be completely sent | 412 | * 0 if no request could be completely sent |
415 | * 1 if all data for one request was sent | 413 | * 1 if all data for one request was sent |
416 | */ | 414 | */ |
417 | int smb_request_send_server(struct smb_sb_info *server) | 415 | int smb_request_send_server(struct smb_sb_info *server) |
418 | { | 416 | { |
419 | struct list_head *head; | 417 | struct list_head *head; |
420 | struct smb_request *req; | 418 | struct smb_request *req; |
421 | int result; | 419 | int result; |
422 | 420 | ||
423 | if (server->state != CONN_VALID) | 421 | if (server->state != CONN_VALID) |
424 | return 0; | 422 | return 0; |
425 | 423 | ||
426 | /* dequeue first request, if any */ | 424 | /* dequeue first request, if any */ |
427 | req = NULL; | 425 | req = NULL; |
428 | head = server->xmitq.next; | 426 | head = server->xmitq.next; |
429 | if (head != &server->xmitq) { | 427 | if (head != &server->xmitq) { |
430 | req = list_entry(head, struct smb_request, rq_queue); | 428 | req = list_entry(head, struct smb_request, rq_queue); |
431 | } | 429 | } |
432 | if (!req) | 430 | if (!req) |
433 | return 0; | 431 | return 0; |
434 | 432 | ||
435 | result = smb_request_send_req(req); | 433 | result = smb_request_send_req(req); |
436 | if (result < 0) { | 434 | if (result < 0) { |
437 | server->conn_error = result; | 435 | server->conn_error = result; |
438 | list_del_init(&req->rq_queue); | 436 | list_del_init(&req->rq_queue); |
439 | list_add(&req->rq_queue, &server->xmitq); | 437 | list_add(&req->rq_queue, &server->xmitq); |
440 | result = -EIO; | 438 | result = -EIO; |
441 | goto out; | 439 | goto out; |
442 | } | 440 | } |
443 | 441 | ||
444 | out: | 442 | out: |
445 | return result; | 443 | return result; |
446 | } | 444 | } |
447 | 445 | ||
448 | /* | 446 | /* |
449 | * Try to find a request matching this "mid". Typically the first entry will | 447 | * Try to find a request matching this "mid". Typically the first entry will |
450 | * be the matching one. | 448 | * be the matching one. |
451 | */ | 449 | */ |
452 | static struct smb_request *find_request(struct smb_sb_info *server, int mid) | 450 | static struct smb_request *find_request(struct smb_sb_info *server, int mid) |
453 | { | 451 | { |
454 | struct list_head *tmp; | 452 | struct list_head *tmp; |
455 | struct smb_request *req = NULL; | 453 | struct smb_request *req = NULL; |
456 | 454 | ||
457 | list_for_each(tmp, &server->recvq) { | 455 | list_for_each(tmp, &server->recvq) { |
458 | req = list_entry(tmp, struct smb_request, rq_queue); | 456 | req = list_entry(tmp, struct smb_request, rq_queue); |
459 | if (req->rq_mid == mid) { | 457 | if (req->rq_mid == mid) { |
460 | break; | 458 | break; |
461 | } | 459 | } |
462 | req = NULL; | 460 | req = NULL; |
463 | } | 461 | } |
464 | 462 | ||
465 | if (!req) { | 463 | if (!req) { |
466 | VERBOSE("received reply with mid %d but no request!\n", | 464 | VERBOSE("received reply with mid %d but no request!\n", |
467 | WVAL(server->header, smb_mid)); | 465 | WVAL(server->header, smb_mid)); |
468 | server->rstate = SMB_RECV_DROP; | 466 | server->rstate = SMB_RECV_DROP; |
469 | } | 467 | } |
470 | 468 | ||
471 | return req; | 469 | return req; |
472 | } | 470 | } |
473 | 471 | ||
474 | /* | 472 | /* |
475 | * Called when we have read the smb header and believe this is a response. | 473 | * Called when we have read the smb header and believe this is a response. |
476 | */ | 474 | */ |
477 | static int smb_init_request(struct smb_sb_info *server, struct smb_request *req) | 475 | static int smb_init_request(struct smb_sb_info *server, struct smb_request *req) |
478 | { | 476 | { |
479 | int hdrlen, wct; | 477 | int hdrlen, wct; |
480 | 478 | ||
481 | memcpy(req->rq_header, server->header, SMB_HEADER_LEN); | 479 | memcpy(req->rq_header, server->header, SMB_HEADER_LEN); |
482 | 480 | ||
483 | wct = *(req->rq_header + smb_wct); | 481 | wct = *(req->rq_header + smb_wct); |
484 | if (wct > 20) { | 482 | if (wct > 20) { |
485 | PARANOIA("wct too large, %d > 20\n", wct); | 483 | PARANOIA("wct too large, %d > 20\n", wct); |
486 | server->rstate = SMB_RECV_DROP; | 484 | server->rstate = SMB_RECV_DROP; |
487 | return 0; | 485 | return 0; |
488 | } | 486 | } |
489 | 487 | ||
490 | req->rq_resp_wct = wct; | 488 | req->rq_resp_wct = wct; |
491 | hdrlen = SMB_HEADER_LEN + wct*2 + 2; | 489 | hdrlen = SMB_HEADER_LEN + wct*2 + 2; |
492 | VERBOSE("header length: %d smb_wct: %2d\n", hdrlen, wct); | 490 | VERBOSE("header length: %d smb_wct: %2d\n", hdrlen, wct); |
493 | 491 | ||
494 | req->rq_bytes_recvd = SMB_HEADER_LEN; | 492 | req->rq_bytes_recvd = SMB_HEADER_LEN; |
495 | req->rq_rlen = hdrlen; | 493 | req->rq_rlen = hdrlen; |
496 | req->rq_iov[0].iov_base = req->rq_header; | 494 | req->rq_iov[0].iov_base = req->rq_header; |
497 | req->rq_iov[0].iov_len = hdrlen; | 495 | req->rq_iov[0].iov_len = hdrlen; |
498 | req->rq_iovlen = 1; | 496 | req->rq_iovlen = 1; |
499 | server->rstate = SMB_RECV_PARAM; | 497 | server->rstate = SMB_RECV_PARAM; |
500 | 498 | ||
501 | #ifdef SMB_DEBUG_PACKET_SIZE | 499 | #ifdef SMB_DEBUG_PACKET_SIZE |
502 | add_recv_stats(smb_len(server->header)); | 500 | add_recv_stats(smb_len(server->header)); |
503 | #endif | 501 | #endif |
504 | return 0; | 502 | return 0; |
505 | } | 503 | } |
506 | 504 | ||
507 | /* | 505 | /* |
508 | * Reads the SMB parameters | 506 | * Reads the SMB parameters |
509 | */ | 507 | */ |
510 | static int smb_recv_param(struct smb_sb_info *server, struct smb_request *req) | 508 | static int smb_recv_param(struct smb_sb_info *server, struct smb_request *req) |
511 | { | 509 | { |
512 | int result; | 510 | int result; |
513 | 511 | ||
514 | result = smb_receive(server, req); | 512 | result = smb_receive(server, req); |
515 | if (result < 0) | 513 | if (result < 0) |
516 | return result; | 514 | return result; |
517 | if (req->rq_bytes_recvd < req->rq_rlen) | 515 | if (req->rq_bytes_recvd < req->rq_rlen) |
518 | return 0; | 516 | return 0; |
519 | 517 | ||
520 | VERBOSE("result: %d smb_bcc: %04x\n", result, | 518 | VERBOSE("result: %d smb_bcc: %04x\n", result, |
521 | WVAL(req->rq_header, SMB_HEADER_LEN + | 519 | WVAL(req->rq_header, SMB_HEADER_LEN + |
522 | (*(req->rq_header + smb_wct) * 2))); | 520 | (*(req->rq_header + smb_wct) * 2))); |
523 | 521 | ||
524 | result = 0; | 522 | result = 0; |
525 | req->rq_iov[0].iov_base = NULL; | 523 | req->rq_iov[0].iov_base = NULL; |
526 | req->rq_rlen = 0; | 524 | req->rq_rlen = 0; |
527 | if (req->rq_callback) | 525 | if (req->rq_callback) |
528 | req->rq_callback(req); | 526 | req->rq_callback(req); |
529 | else if (req->rq_setup_read) | 527 | else if (req->rq_setup_read) |
530 | result = req->rq_setup_read(req); | 528 | result = req->rq_setup_read(req); |
531 | if (result < 0) { | 529 | if (result < 0) { |
532 | server->rstate = SMB_RECV_DROP; | 530 | server->rstate = SMB_RECV_DROP; |
533 | return result; | 531 | return result; |
534 | } | 532 | } |
535 | 533 | ||
536 | server->rstate = req->rq_rlen > 0 ? SMB_RECV_DATA : SMB_RECV_END; | 534 | server->rstate = req->rq_rlen > 0 ? SMB_RECV_DATA : SMB_RECV_END; |
537 | 535 | ||
538 | req->rq_bytes_recvd = 0; // recvd out of the iov | 536 | req->rq_bytes_recvd = 0; // recvd out of the iov |
539 | 537 | ||
540 | VERBOSE("rlen: %d\n", req->rq_rlen); | 538 | VERBOSE("rlen: %d\n", req->rq_rlen); |
541 | if (req->rq_rlen < 0) { | 539 | if (req->rq_rlen < 0) { |
542 | PARANOIA("Parameters read beyond end of packet!\n"); | 540 | PARANOIA("Parameters read beyond end of packet!\n"); |
543 | server->rstate = SMB_RECV_END; | 541 | server->rstate = SMB_RECV_END; |
544 | return -EIO; | 542 | return -EIO; |
545 | } | 543 | } |
546 | return 0; | 544 | return 0; |
547 | } | 545 | } |
548 | 546 | ||
549 | /* | 547 | /* |
550 | * Reads the SMB data | 548 | * Reads the SMB data |
551 | */ | 549 | */ |
552 | static int smb_recv_data(struct smb_sb_info *server, struct smb_request *req) | 550 | static int smb_recv_data(struct smb_sb_info *server, struct smb_request *req) |
553 | { | 551 | { |
554 | int result; | 552 | int result; |
555 | 553 | ||
556 | result = smb_receive(server, req); | 554 | result = smb_receive(server, req); |
557 | if (result < 0) | 555 | if (result < 0) |
558 | goto out; | 556 | goto out; |
559 | if (req->rq_bytes_recvd < req->rq_rlen) | 557 | if (req->rq_bytes_recvd < req->rq_rlen) |
560 | goto out; | 558 | goto out; |
561 | server->rstate = SMB_RECV_END; | 559 | server->rstate = SMB_RECV_END; |
562 | out: | 560 | out: |
563 | VERBOSE("result: %d\n", result); | 561 | VERBOSE("result: %d\n", result); |
564 | return result; | 562 | return result; |
565 | } | 563 | } |
566 | 564 | ||
567 | /* | 565 | /* |
568 | * Receive a transaction2 response | 566 | * Receive a transaction2 response |
569 | * Return: 0 if the response has been fully read | 567 | * Return: 0 if the response has been fully read |
570 | * 1 if there are further "fragments" to read | 568 | * 1 if there are further "fragments" to read |
571 | * <0 if there is an error | 569 | * <0 if there is an error |
572 | */ | 570 | */ |
573 | static int smb_recv_trans2(struct smb_sb_info *server, struct smb_request *req) | 571 | static int smb_recv_trans2(struct smb_sb_info *server, struct smb_request *req) |
574 | { | 572 | { |
575 | unsigned char *inbuf; | 573 | unsigned char *inbuf; |
576 | unsigned int parm_disp, parm_offset, parm_count, parm_tot; | 574 | unsigned int parm_disp, parm_offset, parm_count, parm_tot; |
577 | unsigned int data_disp, data_offset, data_count, data_tot; | 575 | unsigned int data_disp, data_offset, data_count, data_tot; |
578 | int hdrlen = SMB_HEADER_LEN + req->rq_resp_wct*2 - 2; | 576 | int hdrlen = SMB_HEADER_LEN + req->rq_resp_wct*2 - 2; |
579 | 577 | ||
580 | VERBOSE("handling trans2\n"); | 578 | VERBOSE("handling trans2\n"); |
581 | 579 | ||
582 | inbuf = req->rq_header; | 580 | inbuf = req->rq_header; |
583 | data_tot = WVAL(inbuf, smb_tdrcnt); | 581 | data_tot = WVAL(inbuf, smb_tdrcnt); |
584 | parm_tot = WVAL(inbuf, smb_tprcnt); | 582 | parm_tot = WVAL(inbuf, smb_tprcnt); |
585 | parm_disp = WVAL(inbuf, smb_prdisp); | 583 | parm_disp = WVAL(inbuf, smb_prdisp); |
586 | parm_offset = WVAL(inbuf, smb_proff); | 584 | parm_offset = WVAL(inbuf, smb_proff); |
587 | parm_count = WVAL(inbuf, smb_prcnt); | 585 | parm_count = WVAL(inbuf, smb_prcnt); |
588 | data_disp = WVAL(inbuf, smb_drdisp); | 586 | data_disp = WVAL(inbuf, smb_drdisp); |
589 | data_offset = WVAL(inbuf, smb_droff); | 587 | data_offset = WVAL(inbuf, smb_droff); |
590 | data_count = WVAL(inbuf, smb_drcnt); | 588 | data_count = WVAL(inbuf, smb_drcnt); |
591 | 589 | ||
592 | /* Modify offset for the split header/buffer we use */ | 590 | /* Modify offset for the split header/buffer we use */ |
593 | if (data_count || data_offset) { | 591 | if (data_count || data_offset) { |
594 | if (unlikely(data_offset < hdrlen)) | 592 | if (unlikely(data_offset < hdrlen)) |
595 | goto out_bad_data; | 593 | goto out_bad_data; |
596 | else | 594 | else |
597 | data_offset -= hdrlen; | 595 | data_offset -= hdrlen; |
598 | } | 596 | } |
599 | if (parm_count || parm_offset) { | 597 | if (parm_count || parm_offset) { |
600 | if (unlikely(parm_offset < hdrlen)) | 598 | if (unlikely(parm_offset < hdrlen)) |
601 | goto out_bad_parm; | 599 | goto out_bad_parm; |
602 | else | 600 | else |
603 | parm_offset -= hdrlen; | 601 | parm_offset -= hdrlen; |
604 | } | 602 | } |
605 | 603 | ||
606 | if (parm_count == parm_tot && data_count == data_tot) { | 604 | if (parm_count == parm_tot && data_count == data_tot) { |
607 | /* | 605 | /* |
608 | * This packet has all the trans2 data. | 606 | * This packet has all the trans2 data. |
609 | * | 607 | * |
610 | * We setup the request so that this will be the common | 608 | * We setup the request so that this will be the common |
611 | * case. It may be a server error to not return a | 609 | * case. It may be a server error to not return a |
612 | * response that fits. | 610 | * response that fits. |
613 | */ | 611 | */ |
614 | VERBOSE("single trans2 response " | 612 | VERBOSE("single trans2 response " |
615 | "dcnt=%u, pcnt=%u, doff=%u, poff=%u\n", | 613 | "dcnt=%u, pcnt=%u, doff=%u, poff=%u\n", |
616 | data_count, parm_count, | 614 | data_count, parm_count, |
617 | data_offset, parm_offset); | 615 | data_offset, parm_offset); |
618 | req->rq_ldata = data_count; | 616 | req->rq_ldata = data_count; |
619 | req->rq_lparm = parm_count; | 617 | req->rq_lparm = parm_count; |
620 | req->rq_data = req->rq_buffer + data_offset; | 618 | req->rq_data = req->rq_buffer + data_offset; |
621 | req->rq_parm = req->rq_buffer + parm_offset; | 619 | req->rq_parm = req->rq_buffer + parm_offset; |
622 | if (unlikely(parm_offset + parm_count > req->rq_rlen)) | 620 | if (unlikely(parm_offset + parm_count > req->rq_rlen)) |
623 | goto out_bad_parm; | 621 | goto out_bad_parm; |
624 | if (unlikely(data_offset + data_count > req->rq_rlen)) | 622 | if (unlikely(data_offset + data_count > req->rq_rlen)) |
625 | goto out_bad_data; | 623 | goto out_bad_data; |
626 | return 0; | 624 | return 0; |
627 | } | 625 | } |
628 | 626 | ||
629 | VERBOSE("multi trans2 response " | 627 | VERBOSE("multi trans2 response " |
630 | "frag=%d, dcnt=%u, pcnt=%u, doff=%u, poff=%u\n", | 628 | "frag=%d, dcnt=%u, pcnt=%u, doff=%u, poff=%u\n", |
631 | req->rq_fragment, | 629 | req->rq_fragment, |
632 | data_count, parm_count, | 630 | data_count, parm_count, |
633 | data_offset, parm_offset); | 631 | data_offset, parm_offset); |
634 | 632 | ||
635 | if (!req->rq_fragment) { | 633 | if (!req->rq_fragment) { |
636 | int buf_len; | 634 | int buf_len; |
637 | 635 | ||
638 | /* We got the first trans2 fragment */ | 636 | /* We got the first trans2 fragment */ |
639 | req->rq_fragment = 1; | 637 | req->rq_fragment = 1; |
640 | req->rq_total_data = data_tot; | 638 | req->rq_total_data = data_tot; |
641 | req->rq_total_parm = parm_tot; | 639 | req->rq_total_parm = parm_tot; |
642 | req->rq_ldata = 0; | 640 | req->rq_ldata = 0; |
643 | req->rq_lparm = 0; | 641 | req->rq_lparm = 0; |
644 | 642 | ||
645 | buf_len = data_tot + parm_tot; | 643 | buf_len = data_tot + parm_tot; |
646 | if (buf_len > SMB_MAX_PACKET_SIZE) | 644 | if (buf_len > SMB_MAX_PACKET_SIZE) |
647 | goto out_too_long; | 645 | goto out_too_long; |
648 | 646 | ||
649 | req->rq_trans2bufsize = buf_len; | 647 | req->rq_trans2bufsize = buf_len; |
650 | req->rq_trans2buffer = smb_kmalloc(buf_len, GFP_NOFS); | 648 | req->rq_trans2buffer = kzalloc(buf_len, GFP_NOFS); |
651 | if (!req->rq_trans2buffer) | 649 | if (!req->rq_trans2buffer) |
652 | goto out_no_mem; | 650 | goto out_no_mem; |
653 | memset(req->rq_trans2buffer, 0, buf_len); | ||
654 | 651 | ||
655 | req->rq_parm = req->rq_trans2buffer; | 652 | req->rq_parm = req->rq_trans2buffer; |
656 | req->rq_data = req->rq_trans2buffer + parm_tot; | 653 | req->rq_data = req->rq_trans2buffer + parm_tot; |
657 | } else if (unlikely(req->rq_total_data < data_tot || | 654 | } else if (unlikely(req->rq_total_data < data_tot || |
658 | req->rq_total_parm < parm_tot)) | 655 | req->rq_total_parm < parm_tot)) |
659 | goto out_data_grew; | 656 | goto out_data_grew; |
660 | 657 | ||
661 | if (unlikely(parm_disp + parm_count > req->rq_total_parm || | 658 | if (unlikely(parm_disp + parm_count > req->rq_total_parm || |
662 | parm_offset + parm_count > req->rq_rlen)) | 659 | parm_offset + parm_count > req->rq_rlen)) |
663 | goto out_bad_parm; | 660 | goto out_bad_parm; |
664 | if (unlikely(data_disp + data_count > req->rq_total_data || | 661 | if (unlikely(data_disp + data_count > req->rq_total_data || |
665 | data_offset + data_count > req->rq_rlen)) | 662 | data_offset + data_count > req->rq_rlen)) |
666 | goto out_bad_data; | 663 | goto out_bad_data; |
667 | 664 | ||
668 | inbuf = req->rq_buffer; | 665 | inbuf = req->rq_buffer; |
669 | memcpy(req->rq_parm + parm_disp, inbuf + parm_offset, parm_count); | 666 | memcpy(req->rq_parm + parm_disp, inbuf + parm_offset, parm_count); |
670 | memcpy(req->rq_data + data_disp, inbuf + data_offset, data_count); | 667 | memcpy(req->rq_data + data_disp, inbuf + data_offset, data_count); |
671 | 668 | ||
672 | req->rq_ldata += data_count; | 669 | req->rq_ldata += data_count; |
673 | req->rq_lparm += parm_count; | 670 | req->rq_lparm += parm_count; |
674 | 671 | ||
675 | /* | 672 | /* |
676 | * Check whether we've received all of the data. Note that | 673 | * Check whether we've received all of the data. Note that |
677 | * we use the packet totals -- total lengths might shrink! | 674 | * we use the packet totals -- total lengths might shrink! |
678 | */ | 675 | */ |
679 | if (req->rq_ldata >= data_tot && req->rq_lparm >= parm_tot) { | 676 | if (req->rq_ldata >= data_tot && req->rq_lparm >= parm_tot) { |
680 | req->rq_ldata = data_tot; | 677 | req->rq_ldata = data_tot; |
681 | req->rq_lparm = parm_tot; | 678 | req->rq_lparm = parm_tot; |
682 | return 0; | 679 | return 0; |
683 | } | 680 | } |
684 | return 1; | 681 | return 1; |
685 | 682 | ||
686 | out_too_long: | 683 | out_too_long: |
687 | printk(KERN_ERR "smb_trans2: data/param too long, data=%u, parm=%u\n", | 684 | printk(KERN_ERR "smb_trans2: data/param too long, data=%u, parm=%u\n", |
688 | data_tot, parm_tot); | 685 | data_tot, parm_tot); |
689 | goto out_EIO; | 686 | goto out_EIO; |
690 | out_no_mem: | 687 | out_no_mem: |
691 | printk(KERN_ERR "smb_trans2: couldn't allocate data area of %d bytes\n", | 688 | printk(KERN_ERR "smb_trans2: couldn't allocate data area of %d bytes\n", |
692 | req->rq_trans2bufsize); | 689 | req->rq_trans2bufsize); |
693 | req->rq_errno = -ENOMEM; | 690 | req->rq_errno = -ENOMEM; |
694 | goto out; | 691 | goto out; |
695 | out_data_grew: | 692 | out_data_grew: |
696 | printk(KERN_ERR "smb_trans2: data/params grew!\n"); | 693 | printk(KERN_ERR "smb_trans2: data/params grew!\n"); |
697 | goto out_EIO; | 694 | goto out_EIO; |
698 | out_bad_parm: | 695 | out_bad_parm: |
699 | printk(KERN_ERR "smb_trans2: invalid parms, disp=%u, cnt=%u, tot=%u, ofs=%u\n", | 696 | printk(KERN_ERR "smb_trans2: invalid parms, disp=%u, cnt=%u, tot=%u, ofs=%u\n", |
700 | parm_disp, parm_count, parm_tot, parm_offset); | 697 | parm_disp, parm_count, parm_tot, parm_offset); |
701 | goto out_EIO; | 698 | goto out_EIO; |
702 | out_bad_data: | 699 | out_bad_data: |
703 | printk(KERN_ERR "smb_trans2: invalid data, disp=%u, cnt=%u, tot=%u, ofs=%u\n", | 700 | printk(KERN_ERR "smb_trans2: invalid data, disp=%u, cnt=%u, tot=%u, ofs=%u\n", |
704 | data_disp, data_count, data_tot, data_offset); | 701 | data_disp, data_count, data_tot, data_offset); |
705 | out_EIO: | 702 | out_EIO: |
706 | req->rq_errno = -EIO; | 703 | req->rq_errno = -EIO; |
707 | out: | 704 | out: |
708 | return req->rq_errno; | 705 | return req->rq_errno; |
709 | } | 706 | } |
710 | 707 | ||
711 | /* | 708 | /* |
712 | * State machine for receiving responses. We handle the fact that we can't | 709 | * State machine for receiving responses. We handle the fact that we can't |
713 | * read the full response in one try by having states telling us how much we | 710 | * read the full response in one try by having states telling us how much we |
714 | * have read. | 711 | * have read. |
715 | * | 712 | * |
716 | * Must be called with the server lock held (only called from smbiod). | 713 | * Must be called with the server lock held (only called from smbiod). |
717 | * | 714 | * |
718 | * Return: <0 on error | 715 | * Return: <0 on error |
719 | */ | 716 | */ |
720 | int smb_request_recv(struct smb_sb_info *server) | 717 | int smb_request_recv(struct smb_sb_info *server) |
721 | { | 718 | { |
722 | struct smb_request *req = NULL; | 719 | struct smb_request *req = NULL; |
723 | int result = 0; | 720 | int result = 0; |
724 | 721 | ||
725 | if (smb_recv_available(server) <= 0) | 722 | if (smb_recv_available(server) <= 0) |
726 | return 0; | 723 | return 0; |
727 | 724 | ||
728 | VERBOSE("state: %d\n", server->rstate); | 725 | VERBOSE("state: %d\n", server->rstate); |
729 | switch (server->rstate) { | 726 | switch (server->rstate) { |
730 | case SMB_RECV_DROP: | 727 | case SMB_RECV_DROP: |
731 | result = smb_receive_drop(server); | 728 | result = smb_receive_drop(server); |
732 | if (result < 0) | 729 | if (result < 0) |
733 | break; | 730 | break; |
734 | if (server->rstate == SMB_RECV_DROP) | 731 | if (server->rstate == SMB_RECV_DROP) |
735 | break; | 732 | break; |
736 | server->rstate = SMB_RECV_START; | 733 | server->rstate = SMB_RECV_START; |
737 | /* fallthrough */ | 734 | /* fallthrough */ |
738 | case SMB_RECV_START: | 735 | case SMB_RECV_START: |
739 | server->smb_read = 0; | 736 | server->smb_read = 0; |
740 | server->rstate = SMB_RECV_HEADER; | 737 | server->rstate = SMB_RECV_HEADER; |
741 | /* fallthrough */ | 738 | /* fallthrough */ |
742 | case SMB_RECV_HEADER: | 739 | case SMB_RECV_HEADER: |
743 | result = smb_receive_header(server); | 740 | result = smb_receive_header(server); |
744 | if (result < 0) | 741 | if (result < 0) |
745 | break; | 742 | break; |
746 | if (server->rstate == SMB_RECV_HEADER) | 743 | if (server->rstate == SMB_RECV_HEADER) |
747 | break; | 744 | break; |
748 | if (! (*(server->header + smb_flg) & SMB_FLAGS_REPLY) ) { | 745 | if (! (*(server->header + smb_flg) & SMB_FLAGS_REPLY) ) { |
749 | server->rstate = SMB_RECV_REQUEST; | 746 | server->rstate = SMB_RECV_REQUEST; |
750 | break; | 747 | break; |
751 | } | 748 | } |
752 | if (server->rstate != SMB_RECV_HCOMPLETE) | 749 | if (server->rstate != SMB_RECV_HCOMPLETE) |
753 | break; | 750 | break; |
754 | /* fallthrough */ | 751 | /* fallthrough */ |
755 | case SMB_RECV_HCOMPLETE: | 752 | case SMB_RECV_HCOMPLETE: |
756 | req = find_request(server, WVAL(server->header, smb_mid)); | 753 | req = find_request(server, WVAL(server->header, smb_mid)); |
757 | if (!req) | 754 | if (!req) |
758 | break; | 755 | break; |
759 | smb_init_request(server, req); | 756 | smb_init_request(server, req); |
760 | req->rq_rcls = *(req->rq_header + smb_rcls); | 757 | req->rq_rcls = *(req->rq_header + smb_rcls); |
761 | req->rq_err = WVAL(req->rq_header, smb_err); | 758 | req->rq_err = WVAL(req->rq_header, smb_err); |
762 | if (server->rstate != SMB_RECV_PARAM) | 759 | if (server->rstate != SMB_RECV_PARAM) |
763 | break; | 760 | break; |
764 | /* fallthrough */ | 761 | /* fallthrough */ |
765 | case SMB_RECV_PARAM: | 762 | case SMB_RECV_PARAM: |
766 | if (!req) | 763 | if (!req) |
767 | req = find_request(server,WVAL(server->header,smb_mid)); | 764 | req = find_request(server,WVAL(server->header,smb_mid)); |
768 | if (!req) | 765 | if (!req) |
769 | break; | 766 | break; |
770 | result = smb_recv_param(server, req); | 767 | result = smb_recv_param(server, req); |
771 | if (result < 0) | 768 | if (result < 0) |
772 | break; | 769 | break; |
773 | if (server->rstate != SMB_RECV_DATA) | 770 | if (server->rstate != SMB_RECV_DATA) |
774 | break; | 771 | break; |
775 | /* fallthrough */ | 772 | /* fallthrough */ |
776 | case SMB_RECV_DATA: | 773 | case SMB_RECV_DATA: |
777 | if (!req) | 774 | if (!req) |
778 | req = find_request(server,WVAL(server->header,smb_mid)); | 775 | req = find_request(server,WVAL(server->header,smb_mid)); |
779 | if (!req) | 776 | if (!req) |
780 | break; | 777 | break; |
781 | result = smb_recv_data(server, req); | 778 | result = smb_recv_data(server, req); |
782 | if (result < 0) | 779 | if (result < 0) |
783 | break; | 780 | break; |
784 | break; | 781 | break; |
785 | 782 | ||
786 | /* We should never be called with any of these states */ | 783 | /* We should never be called with any of these states */ |
787 | case SMB_RECV_END: | 784 | case SMB_RECV_END: |
788 | case SMB_RECV_REQUEST: | 785 | case SMB_RECV_REQUEST: |
789 | BUG(); | 786 | BUG(); |
790 | } | 787 | } |
791 | 788 | ||
792 | if (result < 0) { | 789 | if (result < 0) { |
793 | /* We saw an error */ | 790 | /* We saw an error */ |
794 | return result; | 791 | return result; |
795 | } | 792 | } |
796 | 793 | ||
797 | if (server->rstate != SMB_RECV_END) | 794 | if (server->rstate != SMB_RECV_END) |
798 | return 0; | 795 | return 0; |
799 | 796 | ||
800 | result = 0; | 797 | result = 0; |
801 | if (req->rq_trans2_command && req->rq_rcls == SUCCESS) | 798 | if (req->rq_trans2_command && req->rq_rcls == SUCCESS) |
802 | result = smb_recv_trans2(server, req); | 799 | result = smb_recv_trans2(server, req); |
803 | 800 | ||
804 | /* | 801 | /* |
805 | * Response completely read. Drop any extra bytes sent by the server. | 802 | * Response completely read. Drop any extra bytes sent by the server. |
806 | * (Yes, servers sometimes add extra bytes to responses) | 803 | * (Yes, servers sometimes add extra bytes to responses) |
807 | */ | 804 | */ |
808 | VERBOSE("smb_len: %d smb_read: %d\n", | 805 | VERBOSE("smb_len: %d smb_read: %d\n", |
809 | server->smb_len, server->smb_read); | 806 | server->smb_len, server->smb_read); |
810 | if (server->smb_read < server->smb_len) | 807 | if (server->smb_read < server->smb_len) |
811 | smb_receive_drop(server); | 808 | smb_receive_drop(server); |
812 | 809 | ||
813 | server->rstate = SMB_RECV_START; | 810 | server->rstate = SMB_RECV_START; |
814 | 811 | ||
815 | if (!result) { | 812 | if (!result) { |
816 | list_del_init(&req->rq_queue); | 813 | list_del_init(&req->rq_queue); |
817 | req->rq_flags |= SMB_REQ_RECEIVED; | 814 | req->rq_flags |= SMB_REQ_RECEIVED; |
818 | smb_rput(req); | 815 | smb_rput(req); |
819 | wake_up_interruptible(&req->rq_wait); | 816 | wake_up_interruptible(&req->rq_wait); |
820 | } | 817 | } |
821 | return 0; | 818 | return 0; |
822 | } | 819 | } |
823 | 820 |
include/linux/smb_fs.h
1 | /* | 1 | /* |
2 | * smb_fs.h | 2 | * smb_fs.h |
3 | * | 3 | * |
4 | * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke | 4 | * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke |
5 | * Copyright (C) 1997 by Volker Lendecke | 5 | * Copyright (C) 1997 by Volker Lendecke |
6 | * | 6 | * |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #ifndef _LINUX_SMB_FS_H | 9 | #ifndef _LINUX_SMB_FS_H |
10 | #define _LINUX_SMB_FS_H | 10 | #define _LINUX_SMB_FS_H |
11 | 11 | ||
12 | #include <linux/smb.h> | 12 | #include <linux/smb.h> |
13 | #include <linux/smb_fs_i.h> | 13 | #include <linux/smb_fs_i.h> |
14 | #include <linux/smb_fs_sb.h> | 14 | #include <linux/smb_fs_sb.h> |
15 | 15 | ||
16 | /* | 16 | /* |
17 | * ioctl commands | 17 | * ioctl commands |
18 | */ | 18 | */ |
19 | #define SMB_IOC_GETMOUNTUID _IOR('u', 1, __kernel_old_uid_t) | 19 | #define SMB_IOC_GETMOUNTUID _IOR('u', 1, __kernel_old_uid_t) |
20 | #define SMB_IOC_NEWCONN _IOW('u', 2, struct smb_conn_opt) | 20 | #define SMB_IOC_NEWCONN _IOW('u', 2, struct smb_conn_opt) |
21 | 21 | ||
22 | /* __kernel_uid_t can never change, so we have to use __kernel_uid32_t */ | 22 | /* __kernel_uid_t can never change, so we have to use __kernel_uid32_t */ |
23 | #define SMB_IOC_GETMOUNTUID32 _IOR('u', 3, __kernel_uid32_t) | 23 | #define SMB_IOC_GETMOUNTUID32 _IOR('u', 3, __kernel_uid32_t) |
24 | 24 | ||
25 | 25 | ||
26 | #ifdef __KERNEL__ | 26 | #ifdef __KERNEL__ |
27 | 27 | ||
28 | #include <linux/fs.h> | 28 | #include <linux/fs.h> |
29 | #include <linux/pagemap.h> | 29 | #include <linux/pagemap.h> |
30 | #include <linux/vmalloc.h> | 30 | #include <linux/vmalloc.h> |
31 | #include <linux/smb_mount.h> | 31 | #include <linux/smb_mount.h> |
32 | #include <asm/unaligned.h> | 32 | #include <asm/unaligned.h> |
33 | 33 | ||
34 | static inline struct smb_sb_info *SMB_SB(struct super_block *sb) | 34 | static inline struct smb_sb_info *SMB_SB(struct super_block *sb) |
35 | { | 35 | { |
36 | return sb->s_fs_info; | 36 | return sb->s_fs_info; |
37 | } | 37 | } |
38 | 38 | ||
39 | static inline struct smb_inode_info *SMB_I(struct inode *inode) | 39 | static inline struct smb_inode_info *SMB_I(struct inode *inode) |
40 | { | 40 | { |
41 | return container_of(inode, struct smb_inode_info, vfs_inode); | 41 | return container_of(inode, struct smb_inode_info, vfs_inode); |
42 | } | 42 | } |
43 | 43 | ||
44 | /* macro names are short for word, double-word, long value (?) */ | 44 | /* macro names are short for word, double-word, long value (?) */ |
45 | #define WVAL(buf,pos) \ | 45 | #define WVAL(buf,pos) \ |
46 | (le16_to_cpu(get_unaligned((u16 *)((u8 *)(buf) + (pos))))) | 46 | (le16_to_cpu(get_unaligned((u16 *)((u8 *)(buf) + (pos))))) |
47 | #define DVAL(buf,pos) \ | 47 | #define DVAL(buf,pos) \ |
48 | (le32_to_cpu(get_unaligned((u32 *)((u8 *)(buf) + (pos))))) | 48 | (le32_to_cpu(get_unaligned((u32 *)((u8 *)(buf) + (pos))))) |
49 | #define LVAL(buf,pos) \ | 49 | #define LVAL(buf,pos) \ |
50 | (le64_to_cpu(get_unaligned((u64 *)((u8 *)(buf) + (pos))))) | 50 | (le64_to_cpu(get_unaligned((u64 *)((u8 *)(buf) + (pos))))) |
51 | #define WSET(buf,pos,val) \ | 51 | #define WSET(buf,pos,val) \ |
52 | put_unaligned(cpu_to_le16((u16)(val)), (u16 *)((u8 *)(buf) + (pos))) | 52 | put_unaligned(cpu_to_le16((u16)(val)), (u16 *)((u8 *)(buf) + (pos))) |
53 | #define DSET(buf,pos,val) \ | 53 | #define DSET(buf,pos,val) \ |
54 | put_unaligned(cpu_to_le32((u32)(val)), (u32 *)((u8 *)(buf) + (pos))) | 54 | put_unaligned(cpu_to_le32((u32)(val)), (u32 *)((u8 *)(buf) + (pos))) |
55 | #define LSET(buf,pos,val) \ | 55 | #define LSET(buf,pos,val) \ |
56 | put_unaligned(cpu_to_le64((u64)(val)), (u64 *)((u8 *)(buf) + (pos))) | 56 | put_unaligned(cpu_to_le64((u64)(val)), (u64 *)((u8 *)(buf) + (pos))) |
57 | 57 | ||
58 | /* where to find the base of the SMB packet proper */ | 58 | /* where to find the base of the SMB packet proper */ |
59 | #define smb_base(buf) ((u8 *)(((u8 *)(buf))+4)) | 59 | #define smb_base(buf) ((u8 *)(((u8 *)(buf))+4)) |
60 | 60 | ||
61 | #ifdef DEBUG_SMB_MALLOC | ||
62 | |||
63 | #include <linux/slab.h> | ||
64 | |||
65 | extern int smb_malloced; | ||
66 | extern int smb_current_vmalloced; | ||
67 | extern int smb_current_kmalloced; | ||
68 | |||
69 | static inline void * | ||
70 | smb_vmalloc(unsigned int size) | ||
71 | { | ||
72 | smb_malloced += 1; | ||
73 | smb_current_vmalloced += 1; | ||
74 | return vmalloc(size); | ||
75 | } | ||
76 | |||
77 | static inline void | ||
78 | smb_vfree(void *obj) | ||
79 | { | ||
80 | smb_current_vmalloced -= 1; | ||
81 | vfree(obj); | ||
82 | } | ||
83 | |||
84 | static inline void * | ||
85 | smb_kmalloc(size_t size, int flags) | ||
86 | { | ||
87 | smb_malloced += 1; | ||
88 | smb_current_kmalloced += 1; | ||
89 | return kmalloc(size, flags); | ||
90 | } | ||
91 | |||
92 | static inline void | ||
93 | smb_kfree(void *obj) | ||
94 | { | ||
95 | smb_current_kmalloced -= 1; | ||
96 | kfree(obj); | ||
97 | } | ||
98 | |||
99 | #else /* DEBUG_SMB_MALLOC */ | ||
100 | |||
101 | #define smb_kmalloc(s,p) kmalloc(s,p) | ||
102 | #define smb_kfree(o) kfree(o) | ||
103 | #define smb_vmalloc(s) vmalloc(s) | ||
104 | #define smb_vfree(o) vfree(o) | ||
105 | |||
106 | #endif /* DEBUG_SMB_MALLOC */ | ||
107 | |||
108 | /* | 61 | /* |
109 | * Flags for the in-memory inode | 62 | * Flags for the in-memory inode |
110 | */ | 63 | */ |
111 | #define SMB_F_LOCALWRITE 0x02 /* file modified locally */ | 64 | #define SMB_F_LOCALWRITE 0x02 /* file modified locally */ |
112 | 65 | ||
113 | 66 | ||
114 | /* NT1 protocol capability bits */ | 67 | /* NT1 protocol capability bits */ |
115 | #define SMB_CAP_RAW_MODE 0x00000001 | 68 | #define SMB_CAP_RAW_MODE 0x00000001 |
116 | #define SMB_CAP_MPX_MODE 0x00000002 | 69 | #define SMB_CAP_MPX_MODE 0x00000002 |
117 | #define SMB_CAP_UNICODE 0x00000004 | 70 | #define SMB_CAP_UNICODE 0x00000004 |
118 | #define SMB_CAP_LARGE_FILES 0x00000008 | 71 | #define SMB_CAP_LARGE_FILES 0x00000008 |
119 | #define SMB_CAP_NT_SMBS 0x00000010 | 72 | #define SMB_CAP_NT_SMBS 0x00000010 |
120 | #define SMB_CAP_RPC_REMOTE_APIS 0x00000020 | 73 | #define SMB_CAP_RPC_REMOTE_APIS 0x00000020 |
121 | #define SMB_CAP_STATUS32 0x00000040 | 74 | #define SMB_CAP_STATUS32 0x00000040 |
122 | #define SMB_CAP_LEVEL_II_OPLOCKS 0x00000080 | 75 | #define SMB_CAP_LEVEL_II_OPLOCKS 0x00000080 |
123 | #define SMB_CAP_LOCK_AND_READ 0x00000100 | 76 | #define SMB_CAP_LOCK_AND_READ 0x00000100 |
124 | #define SMB_CAP_NT_FIND 0x00000200 | 77 | #define SMB_CAP_NT_FIND 0x00000200 |
125 | #define SMB_CAP_DFS 0x00001000 | 78 | #define SMB_CAP_DFS 0x00001000 |
126 | #define SMB_CAP_LARGE_READX 0x00004000 | 79 | #define SMB_CAP_LARGE_READX 0x00004000 |
127 | #define SMB_CAP_LARGE_WRITEX 0x00008000 | 80 | #define SMB_CAP_LARGE_WRITEX 0x00008000 |
128 | #define SMB_CAP_UNIX 0x00800000 /* unofficial ... */ | 81 | #define SMB_CAP_UNIX 0x00800000 /* unofficial ... */ |
129 | 82 | ||
130 | 83 | ||
131 | /* | 84 | /* |
132 | * This is the time we allow an inode, dentry or dir cache to live. It is bad | 85 | * This is the time we allow an inode, dentry or dir cache to live. It is bad |
133 | * for performance to have shorter ttl on an inode than on the cache. It can | 86 | * for performance to have shorter ttl on an inode than on the cache. It can |
134 | * cause refresh on each inode for a dir listing ... one-by-one | 87 | * cause refresh on each inode for a dir listing ... one-by-one |
135 | */ | 88 | */ |
136 | #define SMB_MAX_AGE(server) (((server)->mnt->ttl * HZ) / 1000) | 89 | #define SMB_MAX_AGE(server) (((server)->mnt->ttl * HZ) / 1000) |
137 | 90 | ||
138 | static inline void | 91 | static inline void |
139 | smb_age_dentry(struct smb_sb_info *server, struct dentry *dentry) | 92 | smb_age_dentry(struct smb_sb_info *server, struct dentry *dentry) |
140 | { | 93 | { |
141 | dentry->d_time = jiffies - SMB_MAX_AGE(server); | 94 | dentry->d_time = jiffies - SMB_MAX_AGE(server); |
142 | } | 95 | } |
143 | 96 | ||
144 | struct smb_cache_head { | 97 | struct smb_cache_head { |
145 | time_t mtime; /* unused */ | 98 | time_t mtime; /* unused */ |
146 | unsigned long time; /* cache age */ | 99 | unsigned long time; /* cache age */ |
147 | unsigned long end; /* last valid fpos in cache */ | 100 | unsigned long end; /* last valid fpos in cache */ |
148 | int eof; | 101 | int eof; |
149 | }; | 102 | }; |
150 | 103 | ||
151 | #define SMB_DIRCACHE_SIZE ((int)(PAGE_CACHE_SIZE/sizeof(struct dentry *))) | 104 | #define SMB_DIRCACHE_SIZE ((int)(PAGE_CACHE_SIZE/sizeof(struct dentry *))) |
152 | union smb_dir_cache { | 105 | union smb_dir_cache { |
153 | struct smb_cache_head head; | 106 | struct smb_cache_head head; |
154 | struct dentry *dentry[SMB_DIRCACHE_SIZE]; | 107 | struct dentry *dentry[SMB_DIRCACHE_SIZE]; |
155 | }; | 108 | }; |
156 | 109 | ||
157 | #define SMB_FIRSTCACHE_SIZE ((int)((SMB_DIRCACHE_SIZE * \ | 110 | #define SMB_FIRSTCACHE_SIZE ((int)((SMB_DIRCACHE_SIZE * \ |
158 | sizeof(struct dentry *) - sizeof(struct smb_cache_head)) / \ | 111 | sizeof(struct dentry *) - sizeof(struct smb_cache_head)) / \ |
159 | sizeof(struct dentry *))) | 112 | sizeof(struct dentry *))) |
160 | 113 | ||
161 | #define SMB_DIRCACHE_START (SMB_DIRCACHE_SIZE - SMB_FIRSTCACHE_SIZE) | 114 | #define SMB_DIRCACHE_START (SMB_DIRCACHE_SIZE - SMB_FIRSTCACHE_SIZE) |
162 | 115 | ||
163 | struct smb_cache_control { | 116 | struct smb_cache_control { |
164 | struct smb_cache_head head; | 117 | struct smb_cache_head head; |
165 | struct page *page; | 118 | struct page *page; |
166 | union smb_dir_cache *cache; | 119 | union smb_dir_cache *cache; |
167 | unsigned long fpos, ofs; | 120 | unsigned long fpos, ofs; |
168 | int filled, valid, idx; | 121 | int filled, valid, idx; |
169 | }; | 122 | }; |
170 | 123 | ||
171 | #define SMB_OPS_NUM_STATIC 5 | 124 | #define SMB_OPS_NUM_STATIC 5 |
172 | struct smb_ops { | 125 | struct smb_ops { |
173 | int (*read)(struct inode *inode, loff_t offset, int count, | 126 | int (*read)(struct inode *inode, loff_t offset, int count, |
174 | char *data); | 127 | char *data); |
175 | int (*write)(struct inode *inode, loff_t offset, int count, const | 128 | int (*write)(struct inode *inode, loff_t offset, int count, const |
176 | char *data); | 129 | char *data); |
177 | int (*readdir)(struct file *filp, void *dirent, filldir_t filldir, | 130 | int (*readdir)(struct file *filp, void *dirent, filldir_t filldir, |
178 | struct smb_cache_control *ctl); | 131 | struct smb_cache_control *ctl); |
179 | 132 | ||
180 | int (*getattr)(struct smb_sb_info *server, struct dentry *dir, | 133 | int (*getattr)(struct smb_sb_info *server, struct dentry *dir, |
181 | struct smb_fattr *fattr); | 134 | struct smb_fattr *fattr); |
182 | /* int (*setattr)(...); */ /* setattr is really icky! */ | 135 | /* int (*setattr)(...); */ /* setattr is really icky! */ |
183 | 136 | ||
184 | int (*truncate)(struct inode *inode, loff_t length); | 137 | int (*truncate)(struct inode *inode, loff_t length); |
185 | 138 | ||
186 | 139 | ||
187 | /* --- --- --- end of "static" entries --- --- --- */ | 140 | /* --- --- --- end of "static" entries --- --- --- */ |
188 | 141 | ||
189 | int (*convert)(unsigned char *output, int olen, | 142 | int (*convert)(unsigned char *output, int olen, |
190 | const unsigned char *input, int ilen, | 143 | const unsigned char *input, int ilen, |
191 | struct nls_table *nls_from, | 144 | struct nls_table *nls_from, |
192 | struct nls_table *nls_to); | 145 | struct nls_table *nls_to); |
193 | }; | 146 | }; |
194 | 147 | ||
195 | static inline int | 148 | static inline int |
196 | smb_is_open(struct inode *i) | 149 | smb_is_open(struct inode *i) |
197 | { | 150 | { |
198 | return (SMB_I(i)->open == server_from_inode(i)->generation); | 151 | return (SMB_I(i)->open == server_from_inode(i)->generation); |
199 | } | 152 | } |
200 | 153 | ||
201 | extern void smb_install_null_ops(struct smb_ops *); | 154 | extern void smb_install_null_ops(struct smb_ops *); |
202 | #endif /* __KERNEL__ */ | 155 | #endif /* __KERNEL__ */ |
203 | 156 | ||
204 | #endif /* _LINUX_SMB_FS_H */ | 157 | #endif /* _LINUX_SMB_FS_H */ |
205 | 158 |