diff options
-rw-r--r-- | fs/cifs/Kconfig | 10 | ||||
-rw-r--r-- | fs/cifs/cifs_debug.h | 72 | ||||
-rw-r--r-- | fs/cifs/cifsacl.c | 746 | ||||
-rw-r--r-- | fs/cifs/cifsacl.h | 66 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 17 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 36 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 10 | ||||
-rw-r--r-- | fs/cifs/connect.c | 310 | ||||
-rw-r--r-- | fs/cifs/dir.c | 32 | ||||
-rw-r--r-- | fs/cifs/file.c | 200 | ||||
-rw-r--r-- | fs/cifs/inode.c | 7 | ||||
-rw-r--r-- | fs/cifs/netmisc.c | 14 | ||||
-rw-r--r-- | fs/cifs/readdir.c | 52 | ||||
-rw-r--r-- | fs/cifs/smb1ops.c | 32 | ||||
-rw-r--r-- | fs/cifs/smb2file.c | 12 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 103 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 5 | ||||
-rw-r--r-- | fs/cifs/smb2proto.h | 4 | ||||
-rw-r--r-- | fs/cifs/smb2transport.c | 13 |
19 files changed, 787 insertions, 954 deletions
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 2075ddfffa73..21ff76c22a17 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig | |||
@@ -122,9 +122,17 @@ config CIFS_ACL | |||
122 | Allows fetching CIFS/NTFS ACL from the server. The DACL blob | 122 | Allows fetching CIFS/NTFS ACL from the server. The DACL blob |
123 | is handed over to the application/caller. | 123 | is handed over to the application/caller. |
124 | 124 | ||
125 | config CIFS_DEBUG | ||
126 | bool "Enable CIFS debugging routines" | ||
127 | default y | ||
128 | depends on CIFS | ||
129 | help | ||
130 | Enabling this option adds helpful debugging messages to | ||
131 | the cifs code which increases the size of the cifs module. | ||
132 | If unsure, say Y. | ||
125 | config CIFS_DEBUG2 | 133 | config CIFS_DEBUG2 |
126 | bool "Enable additional CIFS debugging routines" | 134 | bool "Enable additional CIFS debugging routines" |
127 | depends on CIFS | 135 | depends on CIFS_DEBUG |
128 | help | 136 | help |
129 | Enabling this option adds a few more debugging routines | 137 | Enabling this option adds a few more debugging routines |
130 | to the cifs code which slightly increases the size of | 138 | to the cifs code which slightly increases the size of |
diff --git a/fs/cifs/cifs_debug.h b/fs/cifs/cifs_debug.h index c0c68bb492d7..86e92ef2abc1 100644 --- a/fs/cifs/cifs_debug.h +++ b/fs/cifs/cifs_debug.h | |||
@@ -18,7 +18,6 @@ | |||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | #define CIFS_DEBUG /* BB temporary */ | ||
22 | 21 | ||
23 | #ifndef _H_CIFS_DEBUG | 22 | #ifndef _H_CIFS_DEBUG |
24 | #define _H_CIFS_DEBUG | 23 | #define _H_CIFS_DEBUG |
@@ -37,49 +36,43 @@ void dump_smb(void *, int); | |||
37 | #define CIFS_RC 0x02 | 36 | #define CIFS_RC 0x02 |
38 | #define CIFS_TIMER 0x04 | 37 | #define CIFS_TIMER 0x04 |
39 | 38 | ||
39 | extern int cifsFYI; | ||
40 | extern int cifsERROR; | ||
41 | |||
40 | /* | 42 | /* |
41 | * debug ON | 43 | * debug ON |
42 | * -------- | 44 | * -------- |
43 | */ | 45 | */ |
44 | #ifdef CIFS_DEBUG | 46 | #ifdef CONFIG_CIFS_DEBUG |
45 | 47 | ||
46 | /* information message: e.g., configuration, major event */ | 48 | /* information message: e.g., configuration, major event */ |
47 | extern int cifsFYI; | 49 | #define cifsfyi(fmt, ...) \ |
48 | #define cifsfyi(fmt, arg...) \ | ||
49 | do { \ | 50 | do { \ |
50 | if (cifsFYI & CIFS_INFO) \ | 51 | if (cifsFYI & CIFS_INFO) \ |
51 | printk(KERN_DEBUG "%s: " fmt "\n", __FILE__, ##arg); \ | 52 | printk(KERN_DEBUG "%s: " fmt "\n", \ |
53 | __FILE__, ##__VA_ARGS__); \ | ||
52 | } while (0) | 54 | } while (0) |
53 | 55 | ||
54 | #define cFYI(set, fmt, arg...) \ | 56 | #define cFYI(set, fmt, ...) \ |
55 | do { \ | 57 | do { \ |
56 | if (set) \ | 58 | if (set) \ |
57 | cifsfyi(fmt, ##arg); \ | 59 | cifsfyi(fmt, ##__VA_ARGS__); \ |
58 | } while (0) | 60 | } while (0) |
59 | 61 | ||
60 | #define cifswarn(fmt, arg...) \ | 62 | #define cifswarn(fmt, ...) \ |
61 | printk(KERN_WARNING fmt "\n", ##arg) | 63 | printk(KERN_WARNING fmt "\n", ##__VA_ARGS__) |
62 | 64 | ||
63 | /* debug event message: */ | 65 | /* error event message: e.g., i/o error */ |
64 | extern int cifsERROR; | 66 | #define cifserror(fmt, ...) \ |
65 | |||
66 | #define cEVENT(fmt, arg...) \ | ||
67 | do { \ | 67 | do { \ |
68 | if (cifsERROR) \ | 68 | if (cifsERROR) \ |
69 | printk(KERN_EVENT "%s: " fmt "\n", __FILE__, ##arg); \ | 69 | printk(KERN_ERR "CIFS VFS: " fmt "\n", ##__VA_ARGS__); \ |
70 | } while (0) | ||
71 | |||
72 | /* error event message: e.g., i/o error */ | ||
73 | #define cifserror(fmt, arg...) \ | ||
74 | do { \ | ||
75 | if (cifsERROR) \ | ||
76 | printk(KERN_ERR "CIFS VFS: " fmt "\n", ##arg); \ | ||
77 | } while (0) | 70 | } while (0) |
78 | 71 | ||
79 | #define cERROR(set, fmt, arg...) \ | 72 | #define cERROR(set, fmt, ...) \ |
80 | do { \ | 73 | do { \ |
81 | if (set) \ | 74 | if (set) \ |
82 | cifserror(fmt, ##arg); \ | 75 | cifserror(fmt, ##__VA_ARGS__); \ |
83 | } while (0) | 76 | } while (0) |
84 | 77 | ||
85 | /* | 78 | /* |
@@ -87,10 +80,27 @@ do { \ | |||
87 | * --------- | 80 | * --------- |
88 | */ | 81 | */ |
89 | #else /* _CIFS_DEBUG */ | 82 | #else /* _CIFS_DEBUG */ |
90 | #define cERROR(set, fmt, arg...) | 83 | #define cifsfyi(fmt, ...) \ |
91 | #define cEVENT(fmt, arg...) | 84 | do { \ |
92 | #define cFYI(set, fmt, arg...) | 85 | if (0) \ |
93 | #define cifserror(fmt, arg...) | 86 | printk(KERN_DEBUG "%s: " fmt "\n", \ |
87 | __FILE__, ##__VA_ARGS__); \ | ||
88 | } while (0) | ||
89 | #define cFYI(set, fmt, ...) \ | ||
90 | do { \ | ||
91 | if (0 && set) \ | ||
92 | cifsfyi(fmt, ##__VA_ARGS__); \ | ||
93 | } while (0) | ||
94 | #define cifserror(fmt, ...) \ | ||
95 | do { \ | ||
96 | if (0) \ | ||
97 | printk(KERN_ERR "CIFS VFS: " fmt "\n", ##__VA_ARGS__); \ | ||
98 | } while (0) | ||
99 | #define cERROR(set, fmt, ...) \ | ||
100 | do { \ | ||
101 | if (0 && set) \ | ||
102 | cifserror(fmt, ##__VA_ARGS__); \ | ||
103 | } while (0) | ||
94 | #endif /* _CIFS_DEBUG */ | 104 | #endif /* _CIFS_DEBUG */ |
95 | 105 | ||
96 | #endif /* _H_CIFS_DEBUG */ | 106 | #endif /* _H_CIFS_DEBUG */ |
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 0fb15bbbe43c..75c1ee699143 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c | |||
@@ -42,135 +42,27 @@ static const struct cifs_sid sid_authusers = { | |||
42 | /* group users */ | 42 | /* group users */ |
43 | static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} }; | 43 | static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} }; |
44 | 44 | ||
45 | const struct cred *root_cred; | 45 | static const struct cred *root_cred; |
46 | |||
47 | static void | ||
48 | shrink_idmap_tree(struct rb_root *root, int nr_to_scan, int *nr_rem, | ||
49 | int *nr_del) | ||
50 | { | ||
51 | struct rb_node *node; | ||
52 | struct rb_node *tmp; | ||
53 | struct cifs_sid_id *psidid; | ||
54 | |||
55 | node = rb_first(root); | ||
56 | while (node) { | ||
57 | tmp = node; | ||
58 | node = rb_next(tmp); | ||
59 | psidid = rb_entry(tmp, struct cifs_sid_id, rbnode); | ||
60 | if (nr_to_scan == 0 || *nr_del == nr_to_scan) | ||
61 | ++(*nr_rem); | ||
62 | else { | ||
63 | if (time_after(jiffies, psidid->time + SID_MAP_EXPIRE) | ||
64 | && psidid->refcount == 0) { | ||
65 | rb_erase(tmp, root); | ||
66 | ++(*nr_del); | ||
67 | } else | ||
68 | ++(*nr_rem); | ||
69 | } | ||
70 | } | ||
71 | } | ||
72 | |||
73 | /* | ||
74 | * Run idmap cache shrinker. | ||
75 | */ | ||
76 | static int | ||
77 | cifs_idmap_shrinker(struct shrinker *shrink, struct shrink_control *sc) | ||
78 | { | ||
79 | int nr_to_scan = sc->nr_to_scan; | ||
80 | int nr_del = 0; | ||
81 | int nr_rem = 0; | ||
82 | struct rb_root *root; | ||
83 | |||
84 | root = &uidtree; | ||
85 | spin_lock(&siduidlock); | ||
86 | shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del); | ||
87 | spin_unlock(&siduidlock); | ||
88 | |||
89 | root = &gidtree; | ||
90 | spin_lock(&sidgidlock); | ||
91 | shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del); | ||
92 | spin_unlock(&sidgidlock); | ||
93 | |||
94 | root = &siduidtree; | ||
95 | spin_lock(&uidsidlock); | ||
96 | shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del); | ||
97 | spin_unlock(&uidsidlock); | ||
98 | |||
99 | root = &sidgidtree; | ||
100 | spin_lock(&gidsidlock); | ||
101 | shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del); | ||
102 | spin_unlock(&gidsidlock); | ||
103 | |||
104 | return nr_rem; | ||
105 | } | ||
106 | |||
107 | static void | ||
108 | sid_rb_insert(struct rb_root *root, unsigned long cid, | ||
109 | struct cifs_sid_id **psidid, char *typestr) | ||
110 | { | ||
111 | char *strptr; | ||
112 | struct rb_node *node = root->rb_node; | ||
113 | struct rb_node *parent = NULL; | ||
114 | struct rb_node **linkto = &(root->rb_node); | ||
115 | struct cifs_sid_id *lsidid; | ||
116 | |||
117 | while (node) { | ||
118 | lsidid = rb_entry(node, struct cifs_sid_id, rbnode); | ||
119 | parent = node; | ||
120 | if (cid > lsidid->id) { | ||
121 | linkto = &(node->rb_left); | ||
122 | node = node->rb_left; | ||
123 | } | ||
124 | if (cid < lsidid->id) { | ||
125 | linkto = &(node->rb_right); | ||
126 | node = node->rb_right; | ||
127 | } | ||
128 | } | ||
129 | |||
130 | (*psidid)->id = cid; | ||
131 | (*psidid)->time = jiffies - (SID_MAP_RETRY + 1); | ||
132 | (*psidid)->refcount = 0; | ||
133 | |||
134 | sprintf((*psidid)->sidstr, "%s", typestr); | ||
135 | strptr = (*psidid)->sidstr + strlen((*psidid)->sidstr); | ||
136 | sprintf(strptr, "%ld", cid); | ||
137 | |||
138 | clear_bit(SID_ID_PENDING, &(*psidid)->state); | ||
139 | clear_bit(SID_ID_MAPPED, &(*psidid)->state); | ||
140 | |||
141 | rb_link_node(&(*psidid)->rbnode, parent, linkto); | ||
142 | rb_insert_color(&(*psidid)->rbnode, root); | ||
143 | } | ||
144 | |||
145 | static struct cifs_sid_id * | ||
146 | sid_rb_search(struct rb_root *root, unsigned long cid) | ||
147 | { | ||
148 | struct rb_node *node = root->rb_node; | ||
149 | struct cifs_sid_id *lsidid; | ||
150 | |||
151 | while (node) { | ||
152 | lsidid = rb_entry(node, struct cifs_sid_id, rbnode); | ||
153 | if (cid > lsidid->id) | ||
154 | node = node->rb_left; | ||
155 | else if (cid < lsidid->id) | ||
156 | node = node->rb_right; | ||
157 | else /* node found */ | ||
158 | return lsidid; | ||
159 | } | ||
160 | |||
161 | return NULL; | ||
162 | } | ||
163 | |||
164 | static struct shrinker cifs_shrinker = { | ||
165 | .shrink = cifs_idmap_shrinker, | ||
166 | .seeks = DEFAULT_SEEKS, | ||
167 | }; | ||
168 | 46 | ||
169 | static int | 47 | static int |
170 | cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep) | 48 | cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep) |
171 | { | 49 | { |
172 | char *payload; | 50 | char *payload; |
173 | 51 | ||
52 | /* | ||
53 | * If the payload is less than or equal to the size of a pointer, then | ||
54 | * an allocation here is wasteful. Just copy the data directly to the | ||
55 | * payload.value union member instead. | ||
56 | * | ||
57 | * With this however, you must check the datalen before trying to | ||
58 | * dereference payload.data! | ||
59 | */ | ||
60 | if (prep->datalen <= sizeof(key->payload)) { | ||
61 | key->payload.value = 0; | ||
62 | memcpy(&key->payload.value, prep->data, prep->datalen); | ||
63 | key->datalen = prep->datalen; | ||
64 | return 0; | ||
65 | } | ||
174 | payload = kmalloc(prep->datalen, GFP_KERNEL); | 66 | payload = kmalloc(prep->datalen, GFP_KERNEL); |
175 | if (!payload) | 67 | if (!payload) |
176 | return -ENOMEM; | 68 | return -ENOMEM; |
@@ -184,10 +76,11 @@ cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep) | |||
184 | static inline void | 76 | static inline void |
185 | cifs_idmap_key_destroy(struct key *key) | 77 | cifs_idmap_key_destroy(struct key *key) |
186 | { | 78 | { |
187 | kfree(key->payload.data); | 79 | if (key->datalen > sizeof(key->payload)) |
80 | kfree(key->payload.data); | ||
188 | } | 81 | } |
189 | 82 | ||
190 | struct key_type cifs_idmap_key_type = { | 83 | static struct key_type cifs_idmap_key_type = { |
191 | .name = "cifs.idmap", | 84 | .name = "cifs.idmap", |
192 | .instantiate = cifs_idmap_key_instantiate, | 85 | .instantiate = cifs_idmap_key_instantiate, |
193 | .destroy = cifs_idmap_key_destroy, | 86 | .destroy = cifs_idmap_key_destroy, |
@@ -195,221 +88,174 @@ struct key_type cifs_idmap_key_type = { | |||
195 | .match = user_match, | 88 | .match = user_match, |
196 | }; | 89 | }; |
197 | 90 | ||
198 | static void | 91 | static char * |
199 | sid_to_str(struct cifs_sid *sidptr, char *sidstr) | 92 | sid_to_key_str(struct cifs_sid *sidptr, unsigned int type) |
200 | { | 93 | { |
201 | int i; | 94 | int i, len; |
202 | unsigned long saval; | 95 | unsigned int saval; |
203 | char *strptr; | 96 | char *sidstr, *strptr; |
97 | unsigned long long id_auth_val; | ||
98 | |||
99 | /* 3 bytes for prefix */ | ||
100 | sidstr = kmalloc(3 + SID_STRING_BASE_SIZE + | ||
101 | (SID_STRING_SUBAUTH_SIZE * sidptr->num_subauth), | ||
102 | GFP_KERNEL); | ||
103 | if (!sidstr) | ||
104 | return sidstr; | ||
204 | 105 | ||
205 | strptr = sidstr; | 106 | strptr = sidstr; |
107 | len = sprintf(strptr, "%cs:S-%hhu", type == SIDOWNER ? 'o' : 'g', | ||
108 | sidptr->revision); | ||
109 | strptr += len; | ||
110 | |||
111 | /* The authority field is a single 48-bit number */ | ||
112 | id_auth_val = (unsigned long long)sidptr->authority[5]; | ||
113 | id_auth_val |= (unsigned long long)sidptr->authority[4] << 8; | ||
114 | id_auth_val |= (unsigned long long)sidptr->authority[3] << 16; | ||
115 | id_auth_val |= (unsigned long long)sidptr->authority[2] << 24; | ||
116 | id_auth_val |= (unsigned long long)sidptr->authority[1] << 32; | ||
117 | id_auth_val |= (unsigned long long)sidptr->authority[0] << 48; | ||
206 | 118 | ||
207 | sprintf(strptr, "%s", "S"); | 119 | /* |
208 | strptr = sidstr + strlen(sidstr); | 120 | * MS-DTYP states that if the authority is >= 2^32, then it should be |
209 | 121 | * expressed as a hex value. | |
210 | sprintf(strptr, "-%d", sidptr->revision); | 122 | */ |
211 | strptr = sidstr + strlen(sidstr); | 123 | if (id_auth_val <= UINT_MAX) |
124 | len = sprintf(strptr, "-%llu", id_auth_val); | ||
125 | else | ||
126 | len = sprintf(strptr, "-0x%llx", id_auth_val); | ||
212 | 127 | ||
213 | for (i = 0; i < 6; ++i) { | 128 | strptr += len; |
214 | if (sidptr->authority[i]) { | ||
215 | sprintf(strptr, "-%d", sidptr->authority[i]); | ||
216 | strptr = sidstr + strlen(sidstr); | ||
217 | } | ||
218 | } | ||
219 | 129 | ||
220 | for (i = 0; i < sidptr->num_subauth; ++i) { | 130 | for (i = 0; i < sidptr->num_subauth; ++i) { |
221 | saval = le32_to_cpu(sidptr->sub_auth[i]); | 131 | saval = le32_to_cpu(sidptr->sub_auth[i]); |
222 | sprintf(strptr, "-%ld", saval); | 132 | len = sprintf(strptr, "-%u", saval); |
223 | strptr = sidstr + strlen(sidstr); | 133 | strptr += len; |
224 | } | 134 | } |
225 | } | ||
226 | 135 | ||
227 | static void | 136 | return sidstr; |
228 | cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src) | ||
229 | { | ||
230 | memcpy(dst, src, sizeof(*dst)); | ||
231 | dst->num_subauth = min_t(u8, src->num_subauth, NUM_SUBAUTHS); | ||
232 | } | 137 | } |
233 | 138 | ||
234 | static void | 139 | /* |
235 | id_rb_insert(struct rb_root *root, struct cifs_sid *sidptr, | 140 | * if the two SIDs (roughly equivalent to a UUID for a user or group) are |
236 | struct cifs_sid_id **psidid, char *typestr) | 141 | * the same returns zero, if they do not match returns non-zero. |
142 | */ | ||
143 | static int | ||
144 | compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid) | ||
237 | { | 145 | { |
238 | int rc; | 146 | int i; |
239 | char *strptr; | 147 | int num_subauth, num_sat, num_saw; |
240 | struct rb_node *node = root->rb_node; | ||
241 | struct rb_node *parent = NULL; | ||
242 | struct rb_node **linkto = &(root->rb_node); | ||
243 | struct cifs_sid_id *lsidid; | ||
244 | |||
245 | while (node) { | ||
246 | lsidid = rb_entry(node, struct cifs_sid_id, rbnode); | ||
247 | parent = node; | ||
248 | rc = compare_sids(sidptr, &((lsidid)->sid)); | ||
249 | if (rc > 0) { | ||
250 | linkto = &(node->rb_left); | ||
251 | node = node->rb_left; | ||
252 | } else if (rc < 0) { | ||
253 | linkto = &(node->rb_right); | ||
254 | node = node->rb_right; | ||
255 | } | ||
256 | } | ||
257 | |||
258 | cifs_copy_sid(&(*psidid)->sid, sidptr); | ||
259 | (*psidid)->time = jiffies - (SID_MAP_RETRY + 1); | ||
260 | (*psidid)->refcount = 0; | ||
261 | 148 | ||
262 | sprintf((*psidid)->sidstr, "%s", typestr); | 149 | if ((!ctsid) || (!cwsid)) |
263 | strptr = (*psidid)->sidstr + strlen((*psidid)->sidstr); | 150 | return 1; |
264 | sid_to_str(&(*psidid)->sid, strptr); | ||
265 | 151 | ||
266 | clear_bit(SID_ID_PENDING, &(*psidid)->state); | 152 | /* compare the revision */ |
267 | clear_bit(SID_ID_MAPPED, &(*psidid)->state); | 153 | if (ctsid->revision != cwsid->revision) { |
154 | if (ctsid->revision > cwsid->revision) | ||
155 | return 1; | ||
156 | else | ||
157 | return -1; | ||
158 | } | ||
268 | 159 | ||
269 | rb_link_node(&(*psidid)->rbnode, parent, linkto); | 160 | /* compare all of the six auth values */ |
270 | rb_insert_color(&(*psidid)->rbnode, root); | 161 | for (i = 0; i < NUM_AUTHS; ++i) { |
271 | } | 162 | if (ctsid->authority[i] != cwsid->authority[i]) { |
163 | if (ctsid->authority[i] > cwsid->authority[i]) | ||
164 | return 1; | ||
165 | else | ||
166 | return -1; | ||
167 | } | ||
168 | } | ||
272 | 169 | ||
273 | static struct cifs_sid_id * | 170 | /* compare all of the subauth values if any */ |
274 | id_rb_search(struct rb_root *root, struct cifs_sid *sidptr) | 171 | num_sat = ctsid->num_subauth; |
275 | { | 172 | num_saw = cwsid->num_subauth; |
276 | int rc; | 173 | num_subauth = num_sat < num_saw ? num_sat : num_saw; |
277 | struct rb_node *node = root->rb_node; | 174 | if (num_subauth) { |
278 | struct cifs_sid_id *lsidid; | 175 | for (i = 0; i < num_subauth; ++i) { |
279 | 176 | if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) { | |
280 | while (node) { | 177 | if (le32_to_cpu(ctsid->sub_auth[i]) > |
281 | lsidid = rb_entry(node, struct cifs_sid_id, rbnode); | 178 | le32_to_cpu(cwsid->sub_auth[i])) |
282 | rc = compare_sids(sidptr, &((lsidid)->sid)); | 179 | return 1; |
283 | if (rc > 0) { | 180 | else |
284 | node = node->rb_left; | 181 | return -1; |
285 | } else if (rc < 0) { | 182 | } |
286 | node = node->rb_right; | 183 | } |
287 | } else /* node found */ | ||
288 | return lsidid; | ||
289 | } | 184 | } |
290 | 185 | ||
291 | return NULL; | 186 | return 0; /* sids compare/match */ |
292 | } | 187 | } |
293 | 188 | ||
294 | static int | 189 | static void |
295 | sidid_pending_wait(void *unused) | 190 | cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src) |
296 | { | 191 | { |
297 | schedule(); | 192 | int i; |
298 | return signal_pending(current) ? -ERESTARTSYS : 0; | 193 | |
194 | dst->revision = src->revision; | ||
195 | dst->num_subauth = min_t(u8, src->num_subauth, SID_MAX_SUB_AUTHORITIES); | ||
196 | for (i = 0; i < NUM_AUTHS; ++i) | ||
197 | dst->authority[i] = src->authority[i]; | ||
198 | for (i = 0; i < dst->num_subauth; ++i) | ||
199 | dst->sub_auth[i] = src->sub_auth[i]; | ||
299 | } | 200 | } |
300 | 201 | ||
301 | static int | 202 | static int |
302 | id_to_sid(unsigned long cid, uint sidtype, struct cifs_sid *ssid) | 203 | id_to_sid(unsigned int cid, uint sidtype, struct cifs_sid *ssid) |
303 | { | 204 | { |
304 | int rc = 0; | 205 | int rc; |
305 | struct key *sidkey; | 206 | struct key *sidkey; |
207 | struct cifs_sid *ksid; | ||
208 | unsigned int ksid_size; | ||
209 | char desc[3 + 10 + 1]; /* 3 byte prefix + 10 bytes for value + NULL */ | ||
306 | const struct cred *saved_cred; | 210 | const struct cred *saved_cred; |
307 | struct cifs_sid *lsid; | ||
308 | struct cifs_sid_id *psidid, *npsidid; | ||
309 | struct rb_root *cidtree; | ||
310 | spinlock_t *cidlock; | ||
311 | |||
312 | if (sidtype == SIDOWNER) { | ||
313 | cidlock = &siduidlock; | ||
314 | cidtree = &uidtree; | ||
315 | } else if (sidtype == SIDGROUP) { | ||
316 | cidlock = &sidgidlock; | ||
317 | cidtree = &gidtree; | ||
318 | } else | ||
319 | return -EINVAL; | ||
320 | |||
321 | spin_lock(cidlock); | ||
322 | psidid = sid_rb_search(cidtree, cid); | ||
323 | 211 | ||
324 | if (!psidid) { /* node does not exist, allocate one & attempt adding */ | 212 | rc = snprintf(desc, sizeof(desc), "%ci:%u", |
325 | spin_unlock(cidlock); | 213 | sidtype == SIDOWNER ? 'o' : 'g', cid); |
326 | npsidid = kzalloc(sizeof(struct cifs_sid_id), GFP_KERNEL); | 214 | if (rc >= sizeof(desc)) |
327 | if (!npsidid) | 215 | return -EINVAL; |
328 | return -ENOMEM; | ||
329 | |||
330 | npsidid->sidstr = kmalloc(SIDLEN, GFP_KERNEL); | ||
331 | if (!npsidid->sidstr) { | ||
332 | kfree(npsidid); | ||
333 | return -ENOMEM; | ||
334 | } | ||
335 | 216 | ||
336 | spin_lock(cidlock); | 217 | rc = 0; |
337 | psidid = sid_rb_search(cidtree, cid); | 218 | saved_cred = override_creds(root_cred); |
338 | if (psidid) { /* node happened to get inserted meanwhile */ | 219 | sidkey = request_key(&cifs_idmap_key_type, desc, ""); |
339 | ++psidid->refcount; | 220 | if (IS_ERR(sidkey)) { |
340 | spin_unlock(cidlock); | 221 | rc = -EINVAL; |
341 | kfree(npsidid->sidstr); | 222 | cFYI(1, "%s: Can't map %cid %u to a SID", __func__, |
342 | kfree(npsidid); | 223 | sidtype == SIDOWNER ? 'u' : 'g', cid); |
343 | } else { | 224 | goto out_revert_creds; |
344 | psidid = npsidid; | 225 | } else if (sidkey->datalen < CIFS_SID_BASE_SIZE) { |
345 | sid_rb_insert(cidtree, cid, &psidid, | 226 | rc = -EIO; |
346 | sidtype == SIDOWNER ? "oi:" : "gi:"); | 227 | cFYI(1, "%s: Downcall contained malformed key " |
347 | ++psidid->refcount; | 228 | "(datalen=%hu)", __func__, sidkey->datalen); |
348 | spin_unlock(cidlock); | 229 | goto invalidate_key; |
349 | } | ||
350 | } else { | ||
351 | ++psidid->refcount; | ||
352 | spin_unlock(cidlock); | ||
353 | } | 230 | } |
354 | 231 | ||
355 | /* | 232 | /* |
356 | * If we are here, it is safe to access psidid and its fields | 233 | * A sid is usually too large to be embedded in payload.value, but if |
357 | * since a reference was taken earlier while holding the spinlock. | 234 | * there are no subauthorities and the host has 8-byte pointers, then |
358 | * A reference on the node is put without holding the spinlock | 235 | * it could be. |
359 | * and it is OK to do so in this case, shrinker will not erase | ||
360 | * this node until all references are put and we do not access | ||
361 | * any fields of the node after a reference is put . | ||
362 | */ | 236 | */ |
363 | if (test_bit(SID_ID_MAPPED, &psidid->state)) { | 237 | ksid = sidkey->datalen <= sizeof(sidkey->payload) ? |
364 | cifs_copy_sid(ssid, &psidid->sid); | 238 | (struct cifs_sid *)&sidkey->payload.value : |
365 | psidid->time = jiffies; /* update ts for accessing */ | 239 | (struct cifs_sid *)sidkey->payload.data; |
366 | goto id_sid_out; | 240 | |
241 | ksid_size = CIFS_SID_BASE_SIZE + (ksid->num_subauth * sizeof(__le32)); | ||
242 | if (ksid_size > sidkey->datalen) { | ||
243 | rc = -EIO; | ||
244 | cFYI(1, "%s: Downcall contained malformed key (datalen=%hu, " | ||
245 | "ksid_size=%u)", __func__, sidkey->datalen, ksid_size); | ||
246 | goto invalidate_key; | ||
367 | } | 247 | } |
368 | 248 | ||
369 | if (time_after(psidid->time + SID_MAP_RETRY, jiffies)) { | 249 | cifs_copy_sid(ssid, ksid); |
370 | rc = -EINVAL; | 250 | out_key_put: |
371 | goto id_sid_out; | 251 | key_put(sidkey); |
372 | } | 252 | out_revert_creds: |
373 | 253 | revert_creds(saved_cred); | |
374 | if (!test_and_set_bit(SID_ID_PENDING, &psidid->state)) { | ||
375 | saved_cred = override_creds(root_cred); | ||
376 | sidkey = request_key(&cifs_idmap_key_type, psidid->sidstr, ""); | ||
377 | if (IS_ERR(sidkey)) { | ||
378 | rc = -EINVAL; | ||
379 | cFYI(1, "%s: Can't map and id to a SID", __func__); | ||
380 | } else if (sidkey->datalen < sizeof(struct cifs_sid)) { | ||
381 | rc = -EIO; | ||
382 | cFYI(1, "%s: Downcall contained malformed key " | ||
383 | "(datalen=%hu)", __func__, sidkey->datalen); | ||
384 | } else { | ||
385 | lsid = (struct cifs_sid *)sidkey->payload.data; | ||
386 | cifs_copy_sid(&psidid->sid, lsid); | ||
387 | cifs_copy_sid(ssid, &psidid->sid); | ||
388 | set_bit(SID_ID_MAPPED, &psidid->state); | ||
389 | key_put(sidkey); | ||
390 | kfree(psidid->sidstr); | ||
391 | } | ||
392 | psidid->time = jiffies; /* update ts for accessing */ | ||
393 | revert_creds(saved_cred); | ||
394 | clear_bit(SID_ID_PENDING, &psidid->state); | ||
395 | wake_up_bit(&psidid->state, SID_ID_PENDING); | ||
396 | } else { | ||
397 | rc = wait_on_bit(&psidid->state, SID_ID_PENDING, | ||
398 | sidid_pending_wait, TASK_INTERRUPTIBLE); | ||
399 | if (rc) { | ||
400 | cFYI(1, "%s: sidid_pending_wait interrupted %d", | ||
401 | __func__, rc); | ||
402 | --psidid->refcount; | ||
403 | return rc; | ||
404 | } | ||
405 | if (test_bit(SID_ID_MAPPED, &psidid->state)) | ||
406 | cifs_copy_sid(ssid, &psidid->sid); | ||
407 | else | ||
408 | rc = -EINVAL; | ||
409 | } | ||
410 | id_sid_out: | ||
411 | --psidid->refcount; | ||
412 | return rc; | 254 | return rc; |
255 | |||
256 | invalidate_key: | ||
257 | key_invalidate(sidkey); | ||
258 | goto out_key_put; | ||
413 | } | 259 | } |
414 | 260 | ||
415 | static int | 261 | static int |
@@ -417,111 +263,67 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid, | |||
417 | struct cifs_fattr *fattr, uint sidtype) | 263 | struct cifs_fattr *fattr, uint sidtype) |
418 | { | 264 | { |
419 | int rc; | 265 | int rc; |
420 | unsigned long cid; | 266 | struct key *sidkey; |
421 | struct key *idkey; | 267 | char *sidstr; |
422 | const struct cred *saved_cred; | 268 | const struct cred *saved_cred; |
423 | struct cifs_sid_id *psidid, *npsidid; | 269 | uid_t fuid = cifs_sb->mnt_uid; |
424 | struct rb_root *cidtree; | 270 | gid_t fgid = cifs_sb->mnt_gid; |
425 | spinlock_t *cidlock; | ||
426 | |||
427 | if (sidtype == SIDOWNER) { | ||
428 | cid = cifs_sb->mnt_uid; /* default uid, in case upcall fails */ | ||
429 | cidlock = &siduidlock; | ||
430 | cidtree = &uidtree; | ||
431 | } else if (sidtype == SIDGROUP) { | ||
432 | cid = cifs_sb->mnt_gid; /* default gid, in case upcall fails */ | ||
433 | cidlock = &sidgidlock; | ||
434 | cidtree = &gidtree; | ||
435 | } else | ||
436 | return -ENOENT; | ||
437 | |||
438 | spin_lock(cidlock); | ||
439 | psidid = id_rb_search(cidtree, psid); | ||
440 | |||
441 | if (!psidid) { /* node does not exist, allocate one & attempt adding */ | ||
442 | spin_unlock(cidlock); | ||
443 | npsidid = kzalloc(sizeof(struct cifs_sid_id), GFP_KERNEL); | ||
444 | if (!npsidid) | ||
445 | return -ENOMEM; | ||
446 | |||
447 | npsidid->sidstr = kmalloc(SIDLEN, GFP_KERNEL); | ||
448 | if (!npsidid->sidstr) { | ||
449 | kfree(npsidid); | ||
450 | return -ENOMEM; | ||
451 | } | ||
452 | |||
453 | spin_lock(cidlock); | ||
454 | psidid = id_rb_search(cidtree, psid); | ||
455 | if (psidid) { /* node happened to get inserted meanwhile */ | ||
456 | ++psidid->refcount; | ||
457 | spin_unlock(cidlock); | ||
458 | kfree(npsidid->sidstr); | ||
459 | kfree(npsidid); | ||
460 | } else { | ||
461 | psidid = npsidid; | ||
462 | id_rb_insert(cidtree, psid, &psidid, | ||
463 | sidtype == SIDOWNER ? "os:" : "gs:"); | ||
464 | ++psidid->refcount; | ||
465 | spin_unlock(cidlock); | ||
466 | } | ||
467 | } else { | ||
468 | ++psidid->refcount; | ||
469 | spin_unlock(cidlock); | ||
470 | } | ||
471 | 271 | ||
472 | /* | 272 | /* |
473 | * If we are here, it is safe to access psidid and its fields | 273 | * If we have too many subauthorities, then something is really wrong. |
474 | * since a reference was taken earlier while holding the spinlock. | 274 | * Just return an error. |
475 | * A reference on the node is put without holding the spinlock | ||
476 | * and it is OK to do so in this case, shrinker will not erase | ||
477 | * this node until all references are put and we do not access | ||
478 | * any fields of the node after a reference is put . | ||
479 | */ | 275 | */ |
480 | if (test_bit(SID_ID_MAPPED, &psidid->state)) { | 276 | if (unlikely(psid->num_subauth > SID_MAX_SUB_AUTHORITIES)) { |
481 | cid = psidid->id; | 277 | cFYI(1, "%s: %u subauthorities is too many!", __func__, |
482 | psidid->time = jiffies; /* update ts for accessing */ | 278 | psid->num_subauth); |
483 | goto sid_to_id_out; | 279 | return -EIO; |
484 | } | 280 | } |
485 | 281 | ||
486 | if (time_after(psidid->time + SID_MAP_RETRY, jiffies)) | 282 | sidstr = sid_to_key_str(psid, sidtype); |
487 | goto sid_to_id_out; | 283 | if (!sidstr) |
488 | 284 | return -ENOMEM; | |
489 | if (!test_and_set_bit(SID_ID_PENDING, &psidid->state)) { | 285 | |
490 | saved_cred = override_creds(root_cred); | 286 | saved_cred = override_creds(root_cred); |
491 | idkey = request_key(&cifs_idmap_key_type, psidid->sidstr, ""); | 287 | sidkey = request_key(&cifs_idmap_key_type, sidstr, ""); |
492 | if (IS_ERR(idkey)) | 288 | if (IS_ERR(sidkey)) { |
493 | cFYI(1, "%s: Can't map SID to an id", __func__); | 289 | rc = -EINVAL; |
494 | else { | 290 | cFYI(1, "%s: Can't map SID %s to a %cid", __func__, sidstr, |
495 | cid = *(unsigned long *)idkey->payload.value; | 291 | sidtype == SIDOWNER ? 'u' : 'g'); |
496 | psidid->id = cid; | 292 | goto out_revert_creds; |
497 | set_bit(SID_ID_MAPPED, &psidid->state); | 293 | } |
498 | key_put(idkey); | 294 | |
499 | kfree(psidid->sidstr); | 295 | /* |
500 | } | 296 | * FIXME: Here we assume that uid_t and gid_t are same size. It's |
501 | revert_creds(saved_cred); | 297 | * probably a safe assumption but might be better to check based on |
502 | psidid->time = jiffies; /* update ts for accessing */ | 298 | * sidtype. |
503 | clear_bit(SID_ID_PENDING, &psidid->state); | 299 | */ |
504 | wake_up_bit(&psidid->state, SID_ID_PENDING); | 300 | if (sidkey->datalen != sizeof(uid_t)) { |
505 | } else { | 301 | rc = -EIO; |
506 | rc = wait_on_bit(&psidid->state, SID_ID_PENDING, | 302 | cFYI(1, "%s: Downcall contained malformed key " |
507 | sidid_pending_wait, TASK_INTERRUPTIBLE); | 303 | "(datalen=%hu)", __func__, sidkey->datalen); |
508 | if (rc) { | 304 | key_invalidate(sidkey); |
509 | cFYI(1, "%s: sidid_pending_wait interrupted %d", | 305 | goto out_key_put; |
510 | __func__, rc); | ||
511 | --psidid->refcount; /* decremented without spinlock */ | ||
512 | return rc; | ||
513 | } | ||
514 | if (test_bit(SID_ID_MAPPED, &psidid->state)) | ||
515 | cid = psidid->id; | ||
516 | } | 306 | } |
517 | 307 | ||
518 | sid_to_id_out: | ||
519 | --psidid->refcount; /* decremented without spinlock */ | ||
520 | if (sidtype == SIDOWNER) | 308 | if (sidtype == SIDOWNER) |
521 | fattr->cf_uid = cid; | 309 | memcpy(&fuid, &sidkey->payload.value, sizeof(uid_t)); |
522 | else | 310 | else |
523 | fattr->cf_gid = cid; | 311 | memcpy(&fgid, &sidkey->payload.value, sizeof(gid_t)); |
312 | |||
313 | out_key_put: | ||
314 | key_put(sidkey); | ||
315 | out_revert_creds: | ||
316 | revert_creds(saved_cred); | ||
317 | kfree(sidstr); | ||
524 | 318 | ||
319 | /* | ||
320 | * Note that we return 0 here unconditionally. If the mapping | ||
321 | * fails then we just fall back to using the mnt_uid/mnt_gid. | ||
322 | */ | ||
323 | if (sidtype == SIDOWNER) | ||
324 | fattr->cf_uid = fuid; | ||
325 | else | ||
326 | fattr->cf_gid = fgid; | ||
525 | return 0; | 327 | return 0; |
526 | } | 328 | } |
527 | 329 | ||
@@ -568,17 +370,6 @@ init_cifs_idmap(void) | |||
568 | cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; | 370 | cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; |
569 | root_cred = cred; | 371 | root_cred = cred; |
570 | 372 | ||
571 | spin_lock_init(&siduidlock); | ||
572 | uidtree = RB_ROOT; | ||
573 | spin_lock_init(&sidgidlock); | ||
574 | gidtree = RB_ROOT; | ||
575 | |||
576 | spin_lock_init(&uidsidlock); | ||
577 | siduidtree = RB_ROOT; | ||
578 | spin_lock_init(&gidsidlock); | ||
579 | sidgidtree = RB_ROOT; | ||
580 | register_shrinker(&cifs_shrinker); | ||
581 | |||
582 | cFYI(1, "cifs idmap keyring: %d", key_serial(keyring)); | 373 | cFYI(1, "cifs idmap keyring: %d", key_serial(keyring)); |
583 | return 0; | 374 | return 0; |
584 | 375 | ||
@@ -595,89 +386,9 @@ exit_cifs_idmap(void) | |||
595 | key_revoke(root_cred->thread_keyring); | 386 | key_revoke(root_cred->thread_keyring); |
596 | unregister_key_type(&cifs_idmap_key_type); | 387 | unregister_key_type(&cifs_idmap_key_type); |
597 | put_cred(root_cred); | 388 | put_cred(root_cred); |
598 | unregister_shrinker(&cifs_shrinker); | ||
599 | cFYI(1, "Unregistered %s key type", cifs_idmap_key_type.name); | 389 | cFYI(1, "Unregistered %s key type", cifs_idmap_key_type.name); |
600 | } | 390 | } |
601 | 391 | ||
602 | void | ||
603 | cifs_destroy_idmaptrees(void) | ||
604 | { | ||
605 | struct rb_root *root; | ||
606 | struct rb_node *node; | ||
607 | |||
608 | root = &uidtree; | ||
609 | spin_lock(&siduidlock); | ||
610 | while ((node = rb_first(root))) | ||
611 | rb_erase(node, root); | ||
612 | spin_unlock(&siduidlock); | ||
613 | |||
614 | root = &gidtree; | ||
615 | spin_lock(&sidgidlock); | ||
616 | while ((node = rb_first(root))) | ||
617 | rb_erase(node, root); | ||
618 | spin_unlock(&sidgidlock); | ||
619 | |||
620 | root = &siduidtree; | ||
621 | spin_lock(&uidsidlock); | ||
622 | while ((node = rb_first(root))) | ||
623 | rb_erase(node, root); | ||
624 | spin_unlock(&uidsidlock); | ||
625 | |||
626 | root = &sidgidtree; | ||
627 | spin_lock(&gidsidlock); | ||
628 | while ((node = rb_first(root))) | ||
629 | rb_erase(node, root); | ||
630 | spin_unlock(&gidsidlock); | ||
631 | } | ||
632 | |||
633 | /* if the two SIDs (roughly equivalent to a UUID for a user or group) are | ||
634 | the same returns 1, if they do not match returns 0 */ | ||
635 | int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid) | ||
636 | { | ||
637 | int i; | ||
638 | int num_subauth, num_sat, num_saw; | ||
639 | |||
640 | if ((!ctsid) || (!cwsid)) | ||
641 | return 1; | ||
642 | |||
643 | /* compare the revision */ | ||
644 | if (ctsid->revision != cwsid->revision) { | ||
645 | if (ctsid->revision > cwsid->revision) | ||
646 | return 1; | ||
647 | else | ||
648 | return -1; | ||
649 | } | ||
650 | |||
651 | /* compare all of the six auth values */ | ||
652 | for (i = 0; i < 6; ++i) { | ||
653 | if (ctsid->authority[i] != cwsid->authority[i]) { | ||
654 | if (ctsid->authority[i] > cwsid->authority[i]) | ||
655 | return 1; | ||
656 | else | ||
657 | return -1; | ||
658 | } | ||
659 | } | ||
660 | |||
661 | /* compare all of the subauth values if any */ | ||
662 | num_sat = ctsid->num_subauth; | ||
663 | num_saw = cwsid->num_subauth; | ||
664 | num_subauth = num_sat < num_saw ? num_sat : num_saw; | ||
665 | if (num_subauth) { | ||
666 | for (i = 0; i < num_subauth; ++i) { | ||
667 | if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) { | ||
668 | if (le32_to_cpu(ctsid->sub_auth[i]) > | ||
669 | le32_to_cpu(cwsid->sub_auth[i])) | ||
670 | return 1; | ||
671 | else | ||
672 | return -1; | ||
673 | } | ||
674 | } | ||
675 | } | ||
676 | |||
677 | return 0; /* sids compare/match */ | ||
678 | } | ||
679 | |||
680 | |||
681 | /* copy ntsd, owner sid, and group sid from a security descriptor to another */ | 392 | /* copy ntsd, owner sid, and group sid from a security descriptor to another */ |
682 | static void copy_sec_desc(const struct cifs_ntsd *pntsd, | 393 | static void copy_sec_desc(const struct cifs_ntsd *pntsd, |
683 | struct cifs_ntsd *pnntsd, __u32 sidsoffset) | 394 | struct cifs_ntsd *pnntsd, __u32 sidsoffset) |
@@ -811,7 +522,7 @@ static __u16 fill_ace_for_sid(struct cifs_ace *pntace, | |||
811 | 522 | ||
812 | pntace->sid.revision = psid->revision; | 523 | pntace->sid.revision = psid->revision; |
813 | pntace->sid.num_subauth = psid->num_subauth; | 524 | pntace->sid.num_subauth = psid->num_subauth; |
814 | for (i = 0; i < 6; i++) | 525 | for (i = 0; i < NUM_AUTHS; i++) |
815 | pntace->sid.authority[i] = psid->authority[i]; | 526 | pntace->sid.authority[i] = psid->authority[i]; |
816 | for (i = 0; i < psid->num_subauth; i++) | 527 | for (i = 0; i < psid->num_subauth; i++) |
817 | pntace->sid.sub_auth[i] = psid->sub_auth[i]; | 528 | pntace->sid.sub_auth[i] = psid->sub_auth[i]; |
@@ -987,8 +698,8 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl) | |||
987 | return -EINVAL; | 698 | return -EINVAL; |
988 | } | 699 | } |
989 | 700 | ||
990 | if (psid->num_subauth) { | ||
991 | #ifdef CONFIG_CIFS_DEBUG2 | 701 | #ifdef CONFIG_CIFS_DEBUG2 |
702 | if (psid->num_subauth) { | ||
992 | int i; | 703 | int i; |
993 | cFYI(1, "SID revision %d num_auth %d", | 704 | cFYI(1, "SID revision %d num_auth %d", |
994 | psid->revision, psid->num_subauth); | 705 | psid->revision, psid->num_subauth); |
@@ -1002,8 +713,8 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl) | |||
1002 | num auths and therefore go off the end */ | 713 | num auths and therefore go off the end */ |
1003 | cFYI(1, "RID 0x%x", | 714 | cFYI(1, "RID 0x%x", |
1004 | le32_to_cpu(psid->sub_auth[psid->num_subauth-1])); | 715 | le32_to_cpu(psid->sub_auth[psid->num_subauth-1])); |
1005 | #endif | ||
1006 | } | 716 | } |
717 | #endif | ||
1007 | 718 | ||
1008 | return 0; | 719 | return 0; |
1009 | } | 720 | } |
@@ -1307,42 +1018,39 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode, | |||
1307 | 1018 | ||
1308 | /* Get the security descriptor */ | 1019 | /* Get the security descriptor */ |
1309 | pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen); | 1020 | pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen); |
1310 | |||
1311 | /* Add three ACEs for owner, group, everyone getting rid of | ||
1312 | other ACEs as chmod disables ACEs and set the security descriptor */ | ||
1313 | |||
1314 | if (IS_ERR(pntsd)) { | 1021 | if (IS_ERR(pntsd)) { |
1315 | rc = PTR_ERR(pntsd); | 1022 | rc = PTR_ERR(pntsd); |
1316 | cERROR(1, "%s: error %d getting sec desc", __func__, rc); | 1023 | cERROR(1, "%s: error %d getting sec desc", __func__, rc); |
1317 | } else { | 1024 | goto out; |
1318 | /* allocate memory for the smb header, | 1025 | } |
1319 | set security descriptor request security descriptor | ||
1320 | parameters, and secuirty descriptor itself */ | ||
1321 | |||
1322 | secdesclen = secdesclen < DEFSECDESCLEN ? | ||
1323 | DEFSECDESCLEN : secdesclen; | ||
1324 | pnntsd = kmalloc(secdesclen, GFP_KERNEL); | ||
1325 | if (!pnntsd) { | ||
1326 | cERROR(1, "Unable to allocate security descriptor"); | ||
1327 | kfree(pntsd); | ||
1328 | return -ENOMEM; | ||
1329 | } | ||
1330 | 1026 | ||
1331 | rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid, | 1027 | /* |
1332 | &aclflag); | 1028 | * Add three ACEs for owner, group, everyone getting rid of other ACEs |
1029 | * as chmod disables ACEs and set the security descriptor. Allocate | ||
1030 | * memory for the smb header, set security descriptor request security | ||
1031 | * descriptor parameters, and secuirty descriptor itself | ||
1032 | */ | ||
1033 | secdesclen = max_t(u32, secdesclen, DEFAULT_SEC_DESC_LEN); | ||
1034 | pnntsd = kmalloc(secdesclen, GFP_KERNEL); | ||
1035 | if (!pnntsd) { | ||
1036 | cERROR(1, "Unable to allocate security descriptor"); | ||
1037 | kfree(pntsd); | ||
1038 | return -ENOMEM; | ||
1039 | } | ||
1333 | 1040 | ||
1334 | cFYI(DBG2, "build_sec_desc rc: %d", rc); | 1041 | rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid, |
1042 | &aclflag); | ||
1335 | 1043 | ||
1336 | if (!rc) { | 1044 | cFYI(DBG2, "build_sec_desc rc: %d", rc); |
1337 | /* Set the security descriptor */ | ||
1338 | rc = set_cifs_acl(pnntsd, secdesclen, inode, | ||
1339 | path, aclflag); | ||
1340 | cFYI(DBG2, "set_cifs_acl rc: %d", rc); | ||
1341 | } | ||
1342 | 1045 | ||
1343 | kfree(pnntsd); | 1046 | if (!rc) { |
1344 | kfree(pntsd); | 1047 | /* Set the security descriptor */ |
1048 | rc = set_cifs_acl(pnntsd, secdesclen, inode, path, aclflag); | ||
1049 | cFYI(DBG2, "set_cifs_acl rc: %d", rc); | ||
1345 | } | 1050 | } |
1346 | 1051 | ||
1052 | kfree(pnntsd); | ||
1053 | kfree(pntsd); | ||
1054 | out: | ||
1347 | return rc; | 1055 | return rc; |
1348 | } | 1056 | } |
diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h index 5c902c7ce524..4f3884835267 100644 --- a/fs/cifs/cifsacl.h +++ b/fs/cifs/cifsacl.h | |||
@@ -23,11 +23,8 @@ | |||
23 | #define _CIFSACL_H | 23 | #define _CIFSACL_H |
24 | 24 | ||
25 | 25 | ||
26 | #define NUM_AUTHS 6 /* number of authority fields */ | 26 | #define NUM_AUTHS (6) /* number of authority fields */ |
27 | #define NUM_SUBAUTHS 5 /* number of sub authority fields */ | 27 | #define SID_MAX_SUB_AUTHORITIES (15) /* max number of sub authority fields */ |
28 | #define NUM_WK_SIDS 7 /* number of well known sids */ | ||
29 | #define SIDNAMELENGTH 20 /* long enough for the ones we care about */ | ||
30 | #define DEFSECDESCLEN 192 /* sec desc len contaiting a dacl with three aces */ | ||
31 | 28 | ||
32 | #define READ_BIT 0x4 | 29 | #define READ_BIT 0x4 |
33 | #define WRITE_BIT 0x2 | 30 | #define WRITE_BIT 0x2 |
@@ -41,12 +38,32 @@ | |||
41 | 38 | ||
42 | #define SIDOWNER 1 | 39 | #define SIDOWNER 1 |
43 | #define SIDGROUP 2 | 40 | #define SIDGROUP 2 |
44 | #define SIDLEN 150 /* S- 1 revision- 6 authorities- max 5 sub authorities */ | ||
45 | 41 | ||
46 | #define SID_ID_MAPPED 0 | 42 | /* |
47 | #define SID_ID_PENDING 1 | 43 | * Security Descriptor length containing DACL with 3 ACEs (one each for |
48 | #define SID_MAP_EXPIRE (3600 * HZ) /* map entry expires after one hour */ | 44 | * owner, group and world). |
49 | #define SID_MAP_RETRY (300 * HZ) /* wait 5 minutes for next attempt to map */ | 45 | */ |
46 | #define DEFAULT_SEC_DESC_LEN (sizeof(struct cifs_ntsd) + \ | ||
47 | sizeof(struct cifs_acl) + \ | ||
48 | (sizeof(struct cifs_ace) * 3)) | ||
49 | |||
50 | /* | ||
51 | * Maximum size of a string representation of a SID: | ||
52 | * | ||
53 | * The fields are unsigned values in decimal. So: | ||
54 | * | ||
55 | * u8: max 3 bytes in decimal | ||
56 | * u32: max 10 bytes in decimal | ||
57 | * | ||
58 | * "S-" + 3 bytes for version field + 15 for authority field + NULL terminator | ||
59 | * | ||
60 | * For authority field, max is when all 6 values are non-zero and it must be | ||
61 | * represented in hex. So "-0x" + 12 hex digits. | ||
62 | * | ||
63 | * Add 11 bytes for each subauthority field (10 bytes each + 1 for '-') | ||
64 | */ | ||
65 | #define SID_STRING_BASE_SIZE (2 + 3 + 15 + 1) | ||
66 | #define SID_STRING_SUBAUTH_SIZE (11) /* size of a single subauth string */ | ||
50 | 67 | ||
51 | struct cifs_ntsd { | 68 | struct cifs_ntsd { |
52 | __le16 revision; /* revision level */ | 69 | __le16 revision; /* revision level */ |
@@ -60,10 +77,13 @@ struct cifs_ntsd { | |||
60 | struct cifs_sid { | 77 | struct cifs_sid { |
61 | __u8 revision; /* revision level */ | 78 | __u8 revision; /* revision level */ |
62 | __u8 num_subauth; | 79 | __u8 num_subauth; |
63 | __u8 authority[6]; | 80 | __u8 authority[NUM_AUTHS]; |
64 | __le32 sub_auth[5]; /* sub_auth[num_subauth] */ | 81 | __le32 sub_auth[SID_MAX_SUB_AUTHORITIES]; /* sub_auth[num_subauth] */ |
65 | } __attribute__((packed)); | 82 | } __attribute__((packed)); |
66 | 83 | ||
84 | /* size of a struct cifs_sid, sans sub_auth array */ | ||
85 | #define CIFS_SID_BASE_SIZE (1 + 1 + NUM_AUTHS) | ||
86 | |||
67 | struct cifs_acl { | 87 | struct cifs_acl { |
68 | __le16 revision; /* revision level */ | 88 | __le16 revision; /* revision level */ |
69 | __le16 size; | 89 | __le16 size; |
@@ -78,26 +98,4 @@ struct cifs_ace { | |||
78 | struct cifs_sid sid; /* ie UUID of user or group who gets these perms */ | 98 | struct cifs_sid sid; /* ie UUID of user or group who gets these perms */ |
79 | } __attribute__((packed)); | 99 | } __attribute__((packed)); |
80 | 100 | ||
81 | struct cifs_wksid { | ||
82 | struct cifs_sid cifssid; | ||
83 | char sidname[SIDNAMELENGTH]; | ||
84 | } __attribute__((packed)); | ||
85 | |||
86 | struct cifs_sid_id { | ||
87 | unsigned int refcount; /* increment with spinlock, decrement without */ | ||
88 | unsigned long id; | ||
89 | unsigned long time; | ||
90 | unsigned long state; | ||
91 | char *sidstr; | ||
92 | struct rb_node rbnode; | ||
93 | struct cifs_sid sid; | ||
94 | }; | ||
95 | |||
96 | #ifdef __KERNEL__ | ||
97 | extern struct key_type cifs_idmap_key_type; | ||
98 | extern const struct cred *root_cred; | ||
99 | #endif /* KERNEL */ | ||
100 | |||
101 | extern int compare_sids(const struct cifs_sid *, const struct cifs_sid *); | ||
102 | |||
103 | #endif /* _CIFSACL_H */ | 101 | #endif /* _CIFSACL_H */ |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index e7931cc55d0c..210f0af83fc4 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -64,24 +64,23 @@ unsigned int global_secflags = CIFSSEC_DEF; | |||
64 | unsigned int sign_CIFS_PDUs = 1; | 64 | unsigned int sign_CIFS_PDUs = 1; |
65 | static const struct super_operations cifs_super_ops; | 65 | static const struct super_operations cifs_super_ops; |
66 | unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; | 66 | unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; |
67 | module_param(CIFSMaxBufSize, int, 0); | 67 | module_param(CIFSMaxBufSize, uint, 0); |
68 | MODULE_PARM_DESC(CIFSMaxBufSize, "Network buffer size (not including header). " | 68 | MODULE_PARM_DESC(CIFSMaxBufSize, "Network buffer size (not including header). " |
69 | "Default: 16384 Range: 8192 to 130048"); | 69 | "Default: 16384 Range: 8192 to 130048"); |
70 | unsigned int cifs_min_rcv = CIFS_MIN_RCV_POOL; | 70 | unsigned int cifs_min_rcv = CIFS_MIN_RCV_POOL; |
71 | module_param(cifs_min_rcv, int, 0); | 71 | module_param(cifs_min_rcv, uint, 0); |
72 | MODULE_PARM_DESC(cifs_min_rcv, "Network buffers in pool. Default: 4 Range: " | 72 | MODULE_PARM_DESC(cifs_min_rcv, "Network buffers in pool. Default: 4 Range: " |
73 | "1 to 64"); | 73 | "1 to 64"); |
74 | unsigned int cifs_min_small = 30; | 74 | unsigned int cifs_min_small = 30; |
75 | module_param(cifs_min_small, int, 0); | 75 | module_param(cifs_min_small, uint, 0); |
76 | MODULE_PARM_DESC(cifs_min_small, "Small network buffers in pool. Default: 30 " | 76 | MODULE_PARM_DESC(cifs_min_small, "Small network buffers in pool. Default: 30 " |
77 | "Range: 2 to 256"); | 77 | "Range: 2 to 256"); |
78 | unsigned int cifs_max_pending = CIFS_MAX_REQ; | 78 | unsigned int cifs_max_pending = CIFS_MAX_REQ; |
79 | module_param(cifs_max_pending, int, 0444); | 79 | module_param(cifs_max_pending, uint, 0444); |
80 | MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. " | 80 | MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. " |
81 | "Default: 32767 Range: 2 to 32767."); | 81 | "Default: 32767 Range: 2 to 32767."); |
82 | module_param(enable_oplocks, bool, 0644); | 82 | module_param(enable_oplocks, bool, 0644); |
83 | MODULE_PARM_DESC(enable_oplocks, "Enable or disable oplocks (bool). Default:" | 83 | MODULE_PARM_DESC(enable_oplocks, "Enable or disable oplocks. Default: y/Y/1"); |
84 | "y/Y/1"); | ||
85 | 84 | ||
86 | extern mempool_t *cifs_sm_req_poolp; | 85 | extern mempool_t *cifs_sm_req_poolp; |
87 | extern mempool_t *cifs_req_poolp; | 86 | extern mempool_t *cifs_req_poolp; |
@@ -230,6 +229,7 @@ cifs_alloc_inode(struct super_block *sb) | |||
230 | cifs_set_oplock_level(cifs_inode, 0); | 229 | cifs_set_oplock_level(cifs_inode, 0); |
231 | cifs_inode->delete_pending = false; | 230 | cifs_inode->delete_pending = false; |
232 | cifs_inode->invalid_mapping = false; | 231 | cifs_inode->invalid_mapping = false; |
232 | cifs_inode->leave_pages_clean = false; | ||
233 | cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ | 233 | cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ |
234 | cifs_inode->server_eof = 0; | 234 | cifs_inode->server_eof = 0; |
235 | cifs_inode->uniqueid = 0; | 235 | cifs_inode->uniqueid = 0; |
@@ -540,8 +540,8 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb) | |||
540 | char *s, *p; | 540 | char *s, *p; |
541 | char sep; | 541 | char sep; |
542 | 542 | ||
543 | full_path = build_path_to_root(vol, cifs_sb, | 543 | full_path = cifs_build_path_to_root(vol, cifs_sb, |
544 | cifs_sb_master_tcon(cifs_sb)); | 544 | cifs_sb_master_tcon(cifs_sb)); |
545 | if (full_path == NULL) | 545 | if (full_path == NULL) |
546 | return ERR_PTR(-ENOMEM); | 546 | return ERR_PTR(-ENOMEM); |
547 | 547 | ||
@@ -1205,7 +1205,6 @@ exit_cifs(void) | |||
1205 | unregister_filesystem(&cifs_fs_type); | 1205 | unregister_filesystem(&cifs_fs_type); |
1206 | cifs_dfs_release_automount_timer(); | 1206 | cifs_dfs_release_automount_timer(); |
1207 | #ifdef CONFIG_CIFS_ACL | 1207 | #ifdef CONFIG_CIFS_ACL |
1208 | cifs_destroy_idmaptrees(); | ||
1209 | exit_cifs_idmap(); | 1208 | exit_cifs_idmap(); |
1210 | #endif | 1209 | #endif |
1211 | #ifdef CONFIG_CIFS_UPCALL | 1210 | #ifdef CONFIG_CIFS_UPCALL |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index f5af2527fc69..aea1eec64911 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -178,6 +178,7 @@ struct smb_rqst { | |||
178 | 178 | ||
179 | enum smb_version { | 179 | enum smb_version { |
180 | Smb_1 = 1, | 180 | Smb_1 = 1, |
181 | Smb_20, | ||
181 | Smb_21, | 182 | Smb_21, |
182 | Smb_30, | 183 | Smb_30, |
183 | }; | 184 | }; |
@@ -280,9 +281,6 @@ struct smb_version_operations { | |||
280 | /* set attributes */ | 281 | /* set attributes */ |
281 | int (*set_file_info)(struct inode *, const char *, FILE_BASIC_INFO *, | 282 | int (*set_file_info)(struct inode *, const char *, FILE_BASIC_INFO *, |
282 | const unsigned int); | 283 | const unsigned int); |
283 | /* build a full path to the root of the mount */ | ||
284 | char * (*build_path_to_root)(struct smb_vol *, struct cifs_sb_info *, | ||
285 | struct cifs_tcon *); | ||
286 | /* check if we can send an echo or nor */ | 284 | /* check if we can send an echo or nor */ |
287 | bool (*can_echo)(struct TCP_Server_Info *); | 285 | bool (*can_echo)(struct TCP_Server_Info *); |
288 | /* send echo request */ | 286 | /* send echo request */ |
@@ -369,6 +367,8 @@ struct smb_version_operations { | |||
369 | void (*set_lease_key)(struct inode *, struct cifs_fid *fid); | 367 | void (*set_lease_key)(struct inode *, struct cifs_fid *fid); |
370 | /* generate new lease key */ | 368 | /* generate new lease key */ |
371 | void (*new_lease_key)(struct cifs_fid *fid); | 369 | void (*new_lease_key)(struct cifs_fid *fid); |
370 | int (*calc_signature)(struct smb_rqst *rqst, | ||
371 | struct TCP_Server_Info *server); | ||
372 | }; | 372 | }; |
373 | 373 | ||
374 | struct smb_version_values { | 374 | struct smb_version_values { |
@@ -396,7 +396,6 @@ struct smb_vol { | |||
396 | char *password; | 396 | char *password; |
397 | char *domainname; | 397 | char *domainname; |
398 | char *UNC; | 398 | char *UNC; |
399 | char *UNCip; | ||
400 | char *iocharset; /* local code page for mapping to and from Unicode */ | 399 | char *iocharset; /* local code page for mapping to and from Unicode */ |
401 | char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */ | 400 | char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */ |
402 | char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */ | 401 | char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */ |
@@ -444,11 +443,11 @@ struct smb_vol { | |||
444 | unsigned int rsize; | 443 | unsigned int rsize; |
445 | unsigned int wsize; | 444 | unsigned int wsize; |
446 | bool sockopt_tcp_nodelay:1; | 445 | bool sockopt_tcp_nodelay:1; |
447 | unsigned short int port; | ||
448 | unsigned long actimeo; /* attribute cache timeout (jiffies) */ | 446 | unsigned long actimeo; /* attribute cache timeout (jiffies) */ |
449 | struct smb_version_operations *ops; | 447 | struct smb_version_operations *ops; |
450 | struct smb_version_values *vals; | 448 | struct smb_version_values *vals; |
451 | char *prepath; | 449 | char *prepath; |
450 | struct sockaddr_storage dstaddr; /* destination address */ | ||
452 | struct sockaddr_storage srcaddr; /* allow binding to a local IP */ | 451 | struct sockaddr_storage srcaddr; /* allow binding to a local IP */ |
453 | struct nls_table *local_nls; | 452 | struct nls_table *local_nls; |
454 | }; | 453 | }; |
@@ -1031,6 +1030,7 @@ struct cifsInodeInfo { | |||
1031 | bool clientCanCacheAll; /* read and writebehind oplock */ | 1030 | bool clientCanCacheAll; /* read and writebehind oplock */ |
1032 | bool delete_pending; /* DELETE_ON_CLOSE is set */ | 1031 | bool delete_pending; /* DELETE_ON_CLOSE is set */ |
1033 | bool invalid_mapping; /* pagecache is invalid */ | 1032 | bool invalid_mapping; /* pagecache is invalid */ |
1033 | bool leave_pages_clean; /* protected by i_mutex, not set pages dirty */ | ||
1034 | unsigned long time; /* jiffies of last update of inode */ | 1034 | unsigned long time; /* jiffies of last update of inode */ |
1035 | u64 server_eof; /* current file size on server -- protected by i_lock */ | 1035 | u64 server_eof; /* current file size on server -- protected by i_lock */ |
1036 | u64 uniqueid; /* server inode number */ | 1036 | u64 uniqueid; /* server inode number */ |
@@ -1067,30 +1067,16 @@ static inline char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb) | |||
1067 | static inline void | 1067 | static inline void |
1068 | convert_delimiter(char *path, char delim) | 1068 | convert_delimiter(char *path, char delim) |
1069 | { | 1069 | { |
1070 | int i; | 1070 | char old_delim, *pos; |
1071 | char old_delim; | ||
1072 | |||
1073 | if (path == NULL) | ||
1074 | return; | ||
1075 | 1071 | ||
1076 | if (delim == '/') | 1072 | if (delim == '/') |
1077 | old_delim = '\\'; | 1073 | old_delim = '\\'; |
1078 | else | 1074 | else |
1079 | old_delim = '/'; | 1075 | old_delim = '/'; |
1080 | 1076 | ||
1081 | for (i = 0; path[i] != '\0'; i++) { | 1077 | pos = path; |
1082 | if (path[i] == old_delim) | 1078 | while ((pos = strchr(pos, old_delim))) |
1083 | path[i] = delim; | 1079 | *pos = delim; |
1084 | } | ||
1085 | } | ||
1086 | |||
1087 | static inline char * | ||
1088 | build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb, | ||
1089 | struct cifs_tcon *tcon) | ||
1090 | { | ||
1091 | if (!vol->ops->build_path_to_root) | ||
1092 | return NULL; | ||
1093 | return vol->ops->build_path_to_root(vol, cifs_sb, tcon); | ||
1094 | } | 1080 | } |
1095 | 1081 | ||
1096 | #ifdef CONFIG_CIFS_STATS | 1082 | #ifdef CONFIG_CIFS_STATS |
@@ -1362,7 +1348,7 @@ require use of the stronger protocol */ | |||
1362 | #define CIFSSEC_MUST_SEAL 0x40040 /* not supported yet */ | 1348 | #define CIFSSEC_MUST_SEAL 0x40040 /* not supported yet */ |
1363 | #define CIFSSEC_MUST_NTLMSSP 0x80080 /* raw ntlmssp with ntlmv2 */ | 1349 | #define CIFSSEC_MUST_NTLMSSP 0x80080 /* raw ntlmssp with ntlmv2 */ |
1364 | 1350 | ||
1365 | #define CIFSSEC_DEF (CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_NTLMSSP) | 1351 | #define CIFSSEC_DEF (CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLMSSP) |
1366 | #define CIFSSEC_MAX (CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2) | 1352 | #define CIFSSEC_MAX (CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2) |
1367 | #define CIFSSEC_AUTH_MASK (CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_LANMAN | CIFSSEC_MAY_PLNTXT | CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP) | 1353 | #define CIFSSEC_AUTH_MASK (CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_LANMAN | CIFSSEC_MAY_PLNTXT | CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP) |
1368 | /* | 1354 | /* |
@@ -1506,6 +1492,6 @@ extern struct smb_version_values smb20_values; | |||
1506 | extern struct smb_version_operations smb21_operations; | 1492 | extern struct smb_version_operations smb21_operations; |
1507 | extern struct smb_version_values smb21_values; | 1493 | extern struct smb_version_values smb21_values; |
1508 | #define SMB30_VERSION_STRING "3.0" | 1494 | #define SMB30_VERSION_STRING "3.0" |
1509 | /*extern struct smb_version_operations smb30_operations; */ /* not needed yet */ | 1495 | extern struct smb_version_operations smb30_operations; |
1510 | extern struct smb_version_values smb30_values; | 1496 | extern struct smb_version_values smb30_values; |
1511 | #endif /* _CIFS_GLOB_H */ | 1497 | #endif /* _CIFS_GLOB_H */ |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 5144e9fbeb8c..1988c1baa224 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -58,8 +58,10 @@ do { \ | |||
58 | } while (0) | 58 | } while (0) |
59 | extern int init_cifs_idmap(void); | 59 | extern int init_cifs_idmap(void); |
60 | extern void exit_cifs_idmap(void); | 60 | extern void exit_cifs_idmap(void); |
61 | extern void cifs_destroy_idmaptrees(void); | ||
62 | extern char *build_path_from_dentry(struct dentry *); | 61 | extern char *build_path_from_dentry(struct dentry *); |
62 | extern char *cifs_build_path_to_root(struct smb_vol *vol, | ||
63 | struct cifs_sb_info *cifs_sb, | ||
64 | struct cifs_tcon *tcon); | ||
63 | extern char *build_wildcard_path_from_dentry(struct dentry *direntry); | 65 | extern char *build_wildcard_path_from_dentry(struct dentry *direntry); |
64 | extern char *cifs_compose_mount_options(const char *sb_mountdata, | 66 | extern char *cifs_compose_mount_options(const char *sb_mountdata, |
65 | const char *fullpath, const struct dfs_info3_param *ref, | 67 | const char *fullpath, const struct dfs_info3_param *ref, |
@@ -107,9 +109,7 @@ extern unsigned int smbCalcSize(void *buf); | |||
107 | extern int decode_negTokenInit(unsigned char *security_blob, int length, | 109 | extern int decode_negTokenInit(unsigned char *security_blob, int length, |
108 | struct TCP_Server_Info *server); | 110 | struct TCP_Server_Info *server); |
109 | extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len); | 111 | extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len); |
110 | extern int cifs_set_port(struct sockaddr *addr, const unsigned short int port); | 112 | extern void cifs_set_port(struct sockaddr *addr, const unsigned short int port); |
111 | extern int cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len, | ||
112 | const unsigned short int port); | ||
113 | extern int map_smb_to_linux_error(char *buf, bool logErr); | 113 | extern int map_smb_to_linux_error(char *buf, bool logErr); |
114 | extern void header_assemble(struct smb_hdr *, char /* command */ , | 114 | extern void header_assemble(struct smb_hdr *, char /* command */ , |
115 | const struct cifs_tcon *, int /* length of | 115 | const struct cifs_tcon *, int /* length of |
@@ -185,7 +185,7 @@ extern void cifs_mark_open_files_invalid(struct cifs_tcon *tcon); | |||
185 | extern bool cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, | 185 | extern bool cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, |
186 | __u64 length, __u8 type, | 186 | __u64 length, __u8 type, |
187 | struct cifsLockInfo **conf_lock, | 187 | struct cifsLockInfo **conf_lock, |
188 | bool rw_check); | 188 | int rw_check); |
189 | extern void cifs_add_pending_open(struct cifs_fid *fid, | 189 | extern void cifs_add_pending_open(struct cifs_fid *fid, |
190 | struct tcon_link *tlink, | 190 | struct tcon_link *tlink, |
191 | struct cifs_pending_open *open); | 191 | struct cifs_pending_open *open); |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 5c670b998ffb..7635b5db26a7 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -186,6 +186,7 @@ static const match_table_t cifs_mount_option_tokens = { | |||
186 | { Opt_user, "user=%s" }, | 186 | { Opt_user, "user=%s" }, |
187 | { Opt_user, "username=%s" }, | 187 | { Opt_user, "username=%s" }, |
188 | { Opt_blank_pass, "pass=" }, | 188 | { Opt_blank_pass, "pass=" }, |
189 | { Opt_blank_pass, "password=" }, | ||
189 | { Opt_pass, "pass=%s" }, | 190 | { Opt_pass, "pass=%s" }, |
190 | { Opt_pass, "password=%s" }, | 191 | { Opt_pass, "password=%s" }, |
191 | { Opt_blank_ip, "ip=" }, | 192 | { Opt_blank_ip, "ip=" }, |
@@ -274,6 +275,7 @@ static const match_table_t cifs_cacheflavor_tokens = { | |||
274 | 275 | ||
275 | static const match_table_t cifs_smb_version_tokens = { | 276 | static const match_table_t cifs_smb_version_tokens = { |
276 | { Smb_1, SMB1_VERSION_STRING }, | 277 | { Smb_1, SMB1_VERSION_STRING }, |
278 | { Smb_20, SMB20_VERSION_STRING}, | ||
277 | { Smb_21, SMB21_VERSION_STRING }, | 279 | { Smb_21, SMB21_VERSION_STRING }, |
278 | { Smb_30, SMB30_VERSION_STRING }, | 280 | { Smb_30, SMB30_VERSION_STRING }, |
279 | }; | 281 | }; |
@@ -1074,12 +1076,16 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol) | |||
1074 | vol->vals = &smb1_values; | 1076 | vol->vals = &smb1_values; |
1075 | break; | 1077 | break; |
1076 | #ifdef CONFIG_CIFS_SMB2 | 1078 | #ifdef CONFIG_CIFS_SMB2 |
1079 | case Smb_20: | ||
1080 | vol->ops = &smb21_operations; /* currently identical with 2.1 */ | ||
1081 | vol->vals = &smb20_values; | ||
1082 | break; | ||
1077 | case Smb_21: | 1083 | case Smb_21: |
1078 | vol->ops = &smb21_operations; | 1084 | vol->ops = &smb21_operations; |
1079 | vol->vals = &smb21_values; | 1085 | vol->vals = &smb21_values; |
1080 | break; | 1086 | break; |
1081 | case Smb_30: | 1087 | case Smb_30: |
1082 | vol->ops = &smb21_operations; /* currently identical with 2.1 */ | 1088 | vol->ops = &smb30_operations; |
1083 | vol->vals = &smb30_values; | 1089 | vol->vals = &smb30_values; |
1084 | break; | 1090 | break; |
1085 | #endif | 1091 | #endif |
@@ -1090,6 +1096,52 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol) | |||
1090 | return 0; | 1096 | return 0; |
1091 | } | 1097 | } |
1092 | 1098 | ||
1099 | /* | ||
1100 | * Parse a devname into substrings and populate the vol->UNC and vol->prepath | ||
1101 | * fields with the result. Returns 0 on success and an error otherwise. | ||
1102 | */ | ||
1103 | static int | ||
1104 | cifs_parse_devname(const char *devname, struct smb_vol *vol) | ||
1105 | { | ||
1106 | char *pos; | ||
1107 | const char *delims = "/\\"; | ||
1108 | size_t len; | ||
1109 | |||
1110 | /* make sure we have a valid UNC double delimiter prefix */ | ||
1111 | len = strspn(devname, delims); | ||
1112 | if (len != 2) | ||
1113 | return -EINVAL; | ||
1114 | |||
1115 | /* find delimiter between host and sharename */ | ||
1116 | pos = strpbrk(devname + 2, delims); | ||
1117 | if (!pos) | ||
1118 | return -EINVAL; | ||
1119 | |||
1120 | /* skip past delimiter */ | ||
1121 | ++pos; | ||
1122 | |||
1123 | /* now go until next delimiter or end of string */ | ||
1124 | len = strcspn(pos, delims); | ||
1125 | |||
1126 | /* move "pos" up to delimiter or NULL */ | ||
1127 | pos += len; | ||
1128 | vol->UNC = kstrndup(devname, pos - devname, GFP_KERNEL); | ||
1129 | if (!vol->UNC) | ||
1130 | return -ENOMEM; | ||
1131 | |||
1132 | convert_delimiter(vol->UNC, '\\'); | ||
1133 | |||
1134 | /* If pos is NULL, or is a bogus trailing delimiter then no prepath */ | ||
1135 | if (!*pos++ || !*pos) | ||
1136 | return 0; | ||
1137 | |||
1138 | vol->prepath = kstrdup(pos, GFP_KERNEL); | ||
1139 | if (!vol->prepath) | ||
1140 | return -ENOMEM; | ||
1141 | |||
1142 | return 0; | ||
1143 | } | ||
1144 | |||
1093 | static int | 1145 | static int |
1094 | cifs_parse_mount_options(const char *mountdata, const char *devname, | 1146 | cifs_parse_mount_options(const char *mountdata, const char *devname, |
1095 | struct smb_vol *vol) | 1147 | struct smb_vol *vol) |
@@ -1108,11 +1160,17 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1108 | char *string = NULL; | 1160 | char *string = NULL; |
1109 | char *tmp_end, *value; | 1161 | char *tmp_end, *value; |
1110 | char delim; | 1162 | char delim; |
1163 | bool got_ip = false; | ||
1164 | unsigned short port = 0; | ||
1165 | struct sockaddr *dstaddr = (struct sockaddr *)&vol->dstaddr; | ||
1111 | 1166 | ||
1112 | separator[0] = ','; | 1167 | separator[0] = ','; |
1113 | separator[1] = 0; | 1168 | separator[1] = 0; |
1114 | delim = separator[0]; | 1169 | delim = separator[0]; |
1115 | 1170 | ||
1171 | /* ensure we always start with zeroed-out smb_vol */ | ||
1172 | memset(vol, 0, sizeof(*vol)); | ||
1173 | |||
1116 | /* | 1174 | /* |
1117 | * does not have to be perfect mapping since field is | 1175 | * does not have to be perfect mapping since field is |
1118 | * informational, only used for servers that do not support | 1176 | * informational, only used for servers that do not support |
@@ -1169,6 +1227,16 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1169 | vol->backupuid_specified = false; /* no backup intent for a user */ | 1227 | vol->backupuid_specified = false; /* no backup intent for a user */ |
1170 | vol->backupgid_specified = false; /* no backup intent for a group */ | 1228 | vol->backupgid_specified = false; /* no backup intent for a group */ |
1171 | 1229 | ||
1230 | /* | ||
1231 | * For now, we ignore -EINVAL errors under the assumption that the | ||
1232 | * unc= and prefixpath= options will be usable. | ||
1233 | */ | ||
1234 | if (cifs_parse_devname(devname, vol) == -ENOMEM) { | ||
1235 | printk(KERN_ERR "CIFS: Unable to allocate memory to parse " | ||
1236 | "device string.\n"); | ||
1237 | goto out_nomem; | ||
1238 | } | ||
1239 | |||
1172 | while ((data = strsep(&options, separator)) != NULL) { | 1240 | while ((data = strsep(&options, separator)) != NULL) { |
1173 | substring_t args[MAX_OPT_ARGS]; | 1241 | substring_t args[MAX_OPT_ARGS]; |
1174 | unsigned long option; | 1242 | unsigned long option; |
@@ -1416,12 +1484,12 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1416 | vol->dir_mode = option; | 1484 | vol->dir_mode = option; |
1417 | break; | 1485 | break; |
1418 | case Opt_port: | 1486 | case Opt_port: |
1419 | if (get_option_ul(args, &option)) { | 1487 | if (get_option_ul(args, &option) || |
1420 | cERROR(1, "%s: Invalid port value", | 1488 | option > USHRT_MAX) { |
1421 | __func__); | 1489 | cERROR(1, "%s: Invalid port value", __func__); |
1422 | goto cifs_parse_mount_err; | 1490 | goto cifs_parse_mount_err; |
1423 | } | 1491 | } |
1424 | vol->port = option; | 1492 | port = (unsigned short)option; |
1425 | break; | 1493 | break; |
1426 | case Opt_rsize: | 1494 | case Opt_rsize: |
1427 | if (get_option_ul(args, &option)) { | 1495 | if (get_option_ul(args, &option)) { |
@@ -1537,53 +1605,48 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1537 | vol->password[j] = '\0'; | 1605 | vol->password[j] = '\0'; |
1538 | break; | 1606 | break; |
1539 | case Opt_blank_ip: | 1607 | case Opt_blank_ip: |
1540 | vol->UNCip = NULL; | 1608 | /* FIXME: should this be an error instead? */ |
1609 | got_ip = false; | ||
1541 | break; | 1610 | break; |
1542 | case Opt_ip: | 1611 | case Opt_ip: |
1543 | string = match_strdup(args); | 1612 | string = match_strdup(args); |
1544 | if (string == NULL) | 1613 | if (string == NULL) |
1545 | goto out_nomem; | 1614 | goto out_nomem; |
1546 | 1615 | ||
1547 | if (strnlen(string, INET6_ADDRSTRLEN) > | 1616 | if (!cifs_convert_address(dstaddr, string, |
1548 | INET6_ADDRSTRLEN) { | 1617 | strlen(string))) { |
1549 | printk(KERN_WARNING "CIFS: ip address " | 1618 | printk(KERN_ERR "CIFS: bad ip= option (%s).\n", |
1550 | "too long\n"); | 1619 | string); |
1551 | goto cifs_parse_mount_err; | ||
1552 | } | ||
1553 | vol->UNCip = kstrdup(string, GFP_KERNEL); | ||
1554 | if (!vol->UNCip) { | ||
1555 | printk(KERN_WARNING "CIFS: no memory " | ||
1556 | "for UNC IP\n"); | ||
1557 | goto cifs_parse_mount_err; | 1620 | goto cifs_parse_mount_err; |
1558 | } | 1621 | } |
1622 | got_ip = true; | ||
1559 | break; | 1623 | break; |
1560 | case Opt_unc: | 1624 | case Opt_unc: |
1561 | string = match_strdup(args); | 1625 | string = vol->UNC; |
1562 | if (string == NULL) | 1626 | vol->UNC = match_strdup(args); |
1627 | if (vol->UNC == NULL) { | ||
1628 | kfree(string); | ||
1563 | goto out_nomem; | 1629 | goto out_nomem; |
1564 | |||
1565 | temp_len = strnlen(string, 300); | ||
1566 | if (temp_len == 300) { | ||
1567 | printk(KERN_WARNING "CIFS: UNC name too long\n"); | ||
1568 | goto cifs_parse_mount_err; | ||
1569 | } | 1630 | } |
1570 | 1631 | ||
1571 | vol->UNC = kmalloc(temp_len+1, GFP_KERNEL); | 1632 | convert_delimiter(vol->UNC, '\\'); |
1572 | if (vol->UNC == NULL) { | 1633 | if (vol->UNC[0] != '\\' || vol->UNC[1] != '\\') { |
1573 | printk(KERN_WARNING "CIFS: no memory for UNC\n"); | 1634 | kfree(string); |
1574 | goto cifs_parse_mount_err; | 1635 | printk(KERN_ERR "CIFS: UNC Path does not " |
1575 | } | 1636 | "begin with // or \\\\\n"); |
1576 | strcpy(vol->UNC, string); | ||
1577 | |||
1578 | if (strncmp(string, "//", 2) == 0) { | ||
1579 | vol->UNC[0] = '\\'; | ||
1580 | vol->UNC[1] = '\\'; | ||
1581 | } else if (strncmp(string, "\\\\", 2) != 0) { | ||
1582 | printk(KERN_WARNING "CIFS: UNC Path does not " | ||
1583 | "begin with // or \\\\\n"); | ||
1584 | goto cifs_parse_mount_err; | 1637 | goto cifs_parse_mount_err; |
1585 | } | 1638 | } |
1586 | 1639 | ||
1640 | /* Compare old unc= option to new one */ | ||
1641 | if (!string || strcmp(string, vol->UNC)) | ||
1642 | printk(KERN_WARNING "CIFS: the value of the " | ||
1643 | "unc= mount option does not match the " | ||
1644 | "device string. Using the unc= option " | ||
1645 | "for now. In 3.10, that option will " | ||
1646 | "be ignored and the contents of the " | ||
1647 | "device string will be used " | ||
1648 | "instead. (%s != %s)\n", string, | ||
1649 | vol->UNC); | ||
1587 | break; | 1650 | break; |
1588 | case Opt_domain: | 1651 | case Opt_domain: |
1589 | string = match_strdup(args); | 1652 | string = match_strdup(args); |
@@ -1618,31 +1681,26 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1618 | } | 1681 | } |
1619 | break; | 1682 | break; |
1620 | case Opt_prefixpath: | 1683 | case Opt_prefixpath: |
1621 | string = match_strdup(args); | 1684 | /* skip over any leading delimiter */ |
1622 | if (string == NULL) | 1685 | if (*args[0].from == '/' || *args[0].from == '\\') |
1623 | goto out_nomem; | 1686 | args[0].from++; |
1624 | |||
1625 | temp_len = strnlen(string, 1024); | ||
1626 | if (string[0] != '/') | ||
1627 | temp_len++; /* missing leading slash */ | ||
1628 | if (temp_len > 1024) { | ||
1629 | printk(KERN_WARNING "CIFS: prefix too long\n"); | ||
1630 | goto cifs_parse_mount_err; | ||
1631 | } | ||
1632 | 1687 | ||
1633 | vol->prepath = kmalloc(temp_len+1, GFP_KERNEL); | 1688 | string = vol->prepath; |
1689 | vol->prepath = match_strdup(args); | ||
1634 | if (vol->prepath == NULL) { | 1690 | if (vol->prepath == NULL) { |
1635 | printk(KERN_WARNING "CIFS: no memory " | 1691 | kfree(string); |
1636 | "for path prefix\n"); | 1692 | goto out_nomem; |
1637 | goto cifs_parse_mount_err; | ||
1638 | } | 1693 | } |
1639 | 1694 | /* Compare old prefixpath= option to new one */ | |
1640 | if (string[0] != '/') { | 1695 | if (!string || strcmp(string, vol->prepath)) |
1641 | vol->prepath[0] = '/'; | 1696 | printk(KERN_WARNING "CIFS: the value of the " |
1642 | strcpy(vol->prepath+1, string); | 1697 | "prefixpath= mount option does not " |
1643 | } else | 1698 | "match the device string. Using the " |
1644 | strcpy(vol->prepath, string); | 1699 | "prefixpath= option for now. In 3.10, " |
1645 | 1700 | "that option will be ignored and the " | |
1701 | "contents of the device string will be " | ||
1702 | "used instead.(%s != %s)\n", string, | ||
1703 | vol->prepath); | ||
1646 | break; | 1704 | break; |
1647 | case Opt_iocharset: | 1705 | case Opt_iocharset: |
1648 | string = match_strdup(args); | 1706 | string = match_strdup(args); |
@@ -1799,9 +1857,30 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1799 | goto cifs_parse_mount_err; | 1857 | goto cifs_parse_mount_err; |
1800 | } | 1858 | } |
1801 | #endif | 1859 | #endif |
1860 | if (!vol->UNC) { | ||
1861 | cERROR(1, "CIFS mount error: No usable UNC path provided in " | ||
1862 | "device string or in unc= option!"); | ||
1863 | goto cifs_parse_mount_err; | ||
1864 | } | ||
1802 | 1865 | ||
1803 | if (vol->UNCip == NULL) | 1866 | /* make sure UNC has a share name */ |
1804 | vol->UNCip = &vol->UNC[2]; | 1867 | if (!strchr(vol->UNC + 3, '\\')) { |
1868 | cERROR(1, "Malformed UNC. Unable to find share name."); | ||
1869 | goto cifs_parse_mount_err; | ||
1870 | } | ||
1871 | |||
1872 | if (!got_ip) { | ||
1873 | /* No ip= option specified? Try to get it from UNC */ | ||
1874 | if (!cifs_convert_address(dstaddr, &vol->UNC[2], | ||
1875 | strlen(&vol->UNC[2]))) { | ||
1876 | printk(KERN_ERR "Unable to determine destination " | ||
1877 | "address.\n"); | ||
1878 | goto cifs_parse_mount_err; | ||
1879 | } | ||
1880 | } | ||
1881 | |||
1882 | /* set the port that we got earlier */ | ||
1883 | cifs_set_port(dstaddr, port); | ||
1805 | 1884 | ||
1806 | if (uid_specified) | 1885 | if (uid_specified) |
1807 | vol->override_uid = override_uid; | 1886 | vol->override_uid = override_uid; |
@@ -1972,9 +2051,10 @@ match_security(struct TCP_Server_Info *server, struct smb_vol *vol) | |||
1972 | return true; | 2051 | return true; |
1973 | } | 2052 | } |
1974 | 2053 | ||
1975 | static int match_server(struct TCP_Server_Info *server, struct sockaddr *addr, | 2054 | static int match_server(struct TCP_Server_Info *server, struct smb_vol *vol) |
1976 | struct smb_vol *vol) | ||
1977 | { | 2055 | { |
2056 | struct sockaddr *addr = (struct sockaddr *)&vol->dstaddr; | ||
2057 | |||
1978 | if ((server->vals != vol->vals) || (server->ops != vol->ops)) | 2058 | if ((server->vals != vol->vals) || (server->ops != vol->ops)) |
1979 | return 0; | 2059 | return 0; |
1980 | 2060 | ||
@@ -1995,13 +2075,13 @@ static int match_server(struct TCP_Server_Info *server, struct sockaddr *addr, | |||
1995 | } | 2075 | } |
1996 | 2076 | ||
1997 | static struct TCP_Server_Info * | 2077 | static struct TCP_Server_Info * |
1998 | cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol) | 2078 | cifs_find_tcp_session(struct smb_vol *vol) |
1999 | { | 2079 | { |
2000 | struct TCP_Server_Info *server; | 2080 | struct TCP_Server_Info *server; |
2001 | 2081 | ||
2002 | spin_lock(&cifs_tcp_ses_lock); | 2082 | spin_lock(&cifs_tcp_ses_lock); |
2003 | list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { | 2083 | list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { |
2004 | if (!match_server(server, addr, vol)) | 2084 | if (!match_server(server, vol)) |
2005 | continue; | 2085 | continue; |
2006 | 2086 | ||
2007 | ++server->srv_count; | 2087 | ++server->srv_count; |
@@ -2051,40 +2131,12 @@ static struct TCP_Server_Info * | |||
2051 | cifs_get_tcp_session(struct smb_vol *volume_info) | 2131 | cifs_get_tcp_session(struct smb_vol *volume_info) |
2052 | { | 2132 | { |
2053 | struct TCP_Server_Info *tcp_ses = NULL; | 2133 | struct TCP_Server_Info *tcp_ses = NULL; |
2054 | struct sockaddr_storage addr; | ||
2055 | struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr; | ||
2056 | struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr; | ||
2057 | int rc; | 2134 | int rc; |
2058 | 2135 | ||
2059 | memset(&addr, 0, sizeof(struct sockaddr_storage)); | 2136 | cFYI(1, "UNC: %s", volume_info->UNC); |
2060 | |||
2061 | cFYI(1, "UNC: %s ip: %s", volume_info->UNC, volume_info->UNCip); | ||
2062 | |||
2063 | if (volume_info->UNCip && volume_info->UNC) { | ||
2064 | rc = cifs_fill_sockaddr((struct sockaddr *)&addr, | ||
2065 | volume_info->UNCip, | ||
2066 | strlen(volume_info->UNCip), | ||
2067 | volume_info->port); | ||
2068 | if (!rc) { | ||
2069 | /* we failed translating address */ | ||
2070 | rc = -EINVAL; | ||
2071 | goto out_err; | ||
2072 | } | ||
2073 | } else if (volume_info->UNCip) { | ||
2074 | /* BB using ip addr as tcp_ses name to connect to the | ||
2075 | DFS root below */ | ||
2076 | cERROR(1, "Connecting to DFS root not implemented yet"); | ||
2077 | rc = -EINVAL; | ||
2078 | goto out_err; | ||
2079 | } else /* which tcp_sess DFS root would we conect to */ { | ||
2080 | cERROR(1, "CIFS mount error: No UNC path (e.g. -o " | ||
2081 | "unc=//192.168.1.100/public) specified"); | ||
2082 | rc = -EINVAL; | ||
2083 | goto out_err; | ||
2084 | } | ||
2085 | 2137 | ||
2086 | /* see if we already have a matching tcp_ses */ | 2138 | /* see if we already have a matching tcp_ses */ |
2087 | tcp_ses = cifs_find_tcp_session((struct sockaddr *)&addr, volume_info); | 2139 | tcp_ses = cifs_find_tcp_session(volume_info); |
2088 | if (tcp_ses) | 2140 | if (tcp_ses) |
2089 | return tcp_ses; | 2141 | return tcp_ses; |
2090 | 2142 | ||
@@ -2129,27 +2181,18 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
2129 | INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); | 2181 | INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); |
2130 | INIT_LIST_HEAD(&tcp_ses->smb_ses_list); | 2182 | INIT_LIST_HEAD(&tcp_ses->smb_ses_list); |
2131 | INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request); | 2183 | INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request); |
2132 | 2184 | memcpy(&tcp_ses->srcaddr, &volume_info->srcaddr, | |
2185 | sizeof(tcp_ses->srcaddr)); | ||
2186 | memcpy(&tcp_ses->dstaddr, &volume_info->dstaddr, | ||
2187 | sizeof(tcp_ses->dstaddr)); | ||
2133 | /* | 2188 | /* |
2134 | * at this point we are the only ones with the pointer | 2189 | * at this point we are the only ones with the pointer |
2135 | * to the struct since the kernel thread not created yet | 2190 | * to the struct since the kernel thread not created yet |
2136 | * no need to spinlock this init of tcpStatus or srv_count | 2191 | * no need to spinlock this init of tcpStatus or srv_count |
2137 | */ | 2192 | */ |
2138 | tcp_ses->tcpStatus = CifsNew; | 2193 | tcp_ses->tcpStatus = CifsNew; |
2139 | memcpy(&tcp_ses->srcaddr, &volume_info->srcaddr, | ||
2140 | sizeof(tcp_ses->srcaddr)); | ||
2141 | ++tcp_ses->srv_count; | 2194 | ++tcp_ses->srv_count; |
2142 | 2195 | ||
2143 | if (addr.ss_family == AF_INET6) { | ||
2144 | cFYI(1, "attempting ipv6 connect"); | ||
2145 | /* BB should we allow ipv6 on port 139? */ | ||
2146 | /* other OS never observed in Wild doing 139 with v6 */ | ||
2147 | memcpy(&tcp_ses->dstaddr, sin_server6, | ||
2148 | sizeof(struct sockaddr_in6)); | ||
2149 | } else | ||
2150 | memcpy(&tcp_ses->dstaddr, sin_server, | ||
2151 | sizeof(struct sockaddr_in)); | ||
2152 | |||
2153 | rc = ip_connect(tcp_ses); | 2196 | rc = ip_connect(tcp_ses); |
2154 | if (rc < 0) { | 2197 | if (rc < 0) { |
2155 | cERROR(1, "Error connecting to socket. Aborting operation"); | 2198 | cERROR(1, "Error connecting to socket. Aborting operation"); |
@@ -2397,8 +2440,6 @@ cifs_set_cifscreds(struct smb_vol *vol __attribute__((unused)), | |||
2397 | } | 2440 | } |
2398 | #endif /* CONFIG_KEYS */ | 2441 | #endif /* CONFIG_KEYS */ |
2399 | 2442 | ||
2400 | static bool warned_on_ntlm; /* globals init to false automatically */ | ||
2401 | |||
2402 | static struct cifs_ses * | 2443 | static struct cifs_ses * |
2403 | cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | 2444 | cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) |
2404 | { | 2445 | { |
@@ -2475,14 +2516,6 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | |||
2475 | ses->cred_uid = volume_info->cred_uid; | 2516 | ses->cred_uid = volume_info->cred_uid; |
2476 | ses->linux_uid = volume_info->linux_uid; | 2517 | ses->linux_uid = volume_info->linux_uid; |
2477 | 2518 | ||
2478 | /* ntlmv2 is much stronger than ntlm security, and has been broadly | ||
2479 | supported for many years, time to update default security mechanism */ | ||
2480 | if ((volume_info->secFlg == 0) && warned_on_ntlm == false) { | ||
2481 | warned_on_ntlm = true; | ||
2482 | cERROR(1, "default security mechanism requested. The default " | ||
2483 | "security mechanism will be upgraded from ntlm to " | ||
2484 | "ntlmv2 in kernel release 3.3"); | ||
2485 | } | ||
2486 | ses->overrideSecFlg = volume_info->secFlg; | 2519 | ses->overrideSecFlg = volume_info->secFlg; |
2487 | 2520 | ||
2488 | mutex_lock(&ses->session_mutex); | 2521 | mutex_lock(&ses->session_mutex); |
@@ -2598,13 +2631,6 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) | |||
2598 | } | 2631 | } |
2599 | } | 2632 | } |
2600 | 2633 | ||
2601 | if (strchr(volume_info->UNC + 3, '\\') == NULL | ||
2602 | && strchr(volume_info->UNC + 3, '/') == NULL) { | ||
2603 | cERROR(1, "Missing share name"); | ||
2604 | rc = -ENODEV; | ||
2605 | goto out_fail; | ||
2606 | } | ||
2607 | |||
2608 | /* | 2634 | /* |
2609 | * BB Do we need to wrap session_mutex around this TCon call and Unix | 2635 | * BB Do we need to wrap session_mutex around this TCon call and Unix |
2610 | * SetFS as we do on SessSetup and reconnect? | 2636 | * SetFS as we do on SessSetup and reconnect? |
@@ -2718,11 +2744,8 @@ cifs_match_super(struct super_block *sb, void *data) | |||
2718 | struct cifs_ses *ses; | 2744 | struct cifs_ses *ses; |
2719 | struct cifs_tcon *tcon; | 2745 | struct cifs_tcon *tcon; |
2720 | struct tcon_link *tlink; | 2746 | struct tcon_link *tlink; |
2721 | struct sockaddr_storage addr; | ||
2722 | int rc = 0; | 2747 | int rc = 0; |
2723 | 2748 | ||
2724 | memset(&addr, 0, sizeof(struct sockaddr_storage)); | ||
2725 | |||
2726 | spin_lock(&cifs_tcp_ses_lock); | 2749 | spin_lock(&cifs_tcp_ses_lock); |
2727 | cifs_sb = CIFS_SB(sb); | 2750 | cifs_sb = CIFS_SB(sb); |
2728 | tlink = cifs_get_tlink(cifs_sb_master_tlink(cifs_sb)); | 2751 | tlink = cifs_get_tlink(cifs_sb_master_tlink(cifs_sb)); |
@@ -2736,17 +2759,7 @@ cifs_match_super(struct super_block *sb, void *data) | |||
2736 | 2759 | ||
2737 | volume_info = mnt_data->vol; | 2760 | volume_info = mnt_data->vol; |
2738 | 2761 | ||
2739 | if (!volume_info->UNCip || !volume_info->UNC) | 2762 | if (!match_server(tcp_srv, volume_info) || |
2740 | goto out; | ||
2741 | |||
2742 | rc = cifs_fill_sockaddr((struct sockaddr *)&addr, | ||
2743 | volume_info->UNCip, | ||
2744 | strlen(volume_info->UNCip), | ||
2745 | volume_info->port); | ||
2746 | if (!rc) | ||
2747 | goto out; | ||
2748 | |||
2749 | if (!match_server(tcp_srv, (struct sockaddr *)&addr, volume_info) || | ||
2750 | !match_session(ses, volume_info) || | 2763 | !match_session(ses, volume_info) || |
2751 | !match_tcon(tcon, volume_info->UNC)) { | 2764 | !match_tcon(tcon, volume_info->UNC)) { |
2752 | rc = 0; | 2765 | rc = 0; |
@@ -3261,8 +3274,6 @@ cleanup_volume_info_contents(struct smb_vol *volume_info) | |||
3261 | { | 3274 | { |
3262 | kfree(volume_info->username); | 3275 | kfree(volume_info->username); |
3263 | kzfree(volume_info->password); | 3276 | kzfree(volume_info->password); |
3264 | if (volume_info->UNCip != volume_info->UNC + 2) | ||
3265 | kfree(volume_info->UNCip); | ||
3266 | kfree(volume_info->UNC); | 3277 | kfree(volume_info->UNC); |
3267 | kfree(volume_info->domainname); | 3278 | kfree(volume_info->domainname); |
3268 | kfree(volume_info->iocharset); | 3279 | kfree(volume_info->iocharset); |
@@ -3280,14 +3291,16 @@ cifs_cleanup_volume_info(struct smb_vol *volume_info) | |||
3280 | 3291 | ||
3281 | 3292 | ||
3282 | #ifdef CONFIG_CIFS_DFS_UPCALL | 3293 | #ifdef CONFIG_CIFS_DFS_UPCALL |
3283 | /* build_path_to_root returns full path to root when | 3294 | /* |
3284 | * we do not have an exiting connection (tcon) */ | 3295 | * cifs_build_path_to_root returns full path to root when we do not have an |
3296 | * exiting connection (tcon) | ||
3297 | */ | ||
3285 | static char * | 3298 | static char * |
3286 | build_unc_path_to_root(const struct smb_vol *vol, | 3299 | build_unc_path_to_root(const struct smb_vol *vol, |
3287 | const struct cifs_sb_info *cifs_sb) | 3300 | const struct cifs_sb_info *cifs_sb) |
3288 | { | 3301 | { |
3289 | char *full_path, *pos; | 3302 | char *full_path, *pos; |
3290 | unsigned int pplen = vol->prepath ? strlen(vol->prepath) : 0; | 3303 | unsigned int pplen = vol->prepath ? strlen(vol->prepath) + 1 : 0; |
3291 | unsigned int unc_len = strnlen(vol->UNC, MAX_TREE_SIZE + 1); | 3304 | unsigned int unc_len = strnlen(vol->UNC, MAX_TREE_SIZE + 1); |
3292 | 3305 | ||
3293 | full_path = kmalloc(unc_len + pplen + 1, GFP_KERNEL); | 3306 | full_path = kmalloc(unc_len + pplen + 1, GFP_KERNEL); |
@@ -3298,6 +3311,7 @@ build_unc_path_to_root(const struct smb_vol *vol, | |||
3298 | pos = full_path + unc_len; | 3311 | pos = full_path + unc_len; |
3299 | 3312 | ||
3300 | if (pplen) { | 3313 | if (pplen) { |
3314 | *pos++ = CIFS_DIR_SEP(cifs_sb); | ||
3301 | strncpy(pos, vol->prepath, pplen); | 3315 | strncpy(pos, vol->prepath, pplen); |
3302 | pos += pplen; | 3316 | pos += pplen; |
3303 | } | 3317 | } |
@@ -3353,7 +3367,6 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses, | |||
3353 | mdata = NULL; | 3367 | mdata = NULL; |
3354 | } else { | 3368 | } else { |
3355 | cleanup_volume_info_contents(volume_info); | 3369 | cleanup_volume_info_contents(volume_info); |
3356 | memset(volume_info, '\0', sizeof(*volume_info)); | ||
3357 | rc = cifs_setup_volume_info(volume_info, mdata, | 3370 | rc = cifs_setup_volume_info(volume_info, mdata, |
3358 | fake_devname); | 3371 | fake_devname); |
3359 | } | 3372 | } |
@@ -3375,7 +3388,6 @@ cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data, | |||
3375 | if (cifs_parse_mount_options(mount_data, devname, volume_info)) | 3388 | if (cifs_parse_mount_options(mount_data, devname, volume_info)) |
3376 | return -EINVAL; | 3389 | return -EINVAL; |
3377 | 3390 | ||
3378 | |||
3379 | if (volume_info->nullauth) { | 3391 | if (volume_info->nullauth) { |
3380 | cFYI(1, "Anonymous login"); | 3392 | cFYI(1, "Anonymous login"); |
3381 | kfree(volume_info->username); | 3393 | kfree(volume_info->username); |
@@ -3412,7 +3424,7 @@ cifs_get_volume_info(char *mount_data, const char *devname) | |||
3412 | int rc; | 3424 | int rc; |
3413 | struct smb_vol *volume_info; | 3425 | struct smb_vol *volume_info; |
3414 | 3426 | ||
3415 | volume_info = kzalloc(sizeof(struct smb_vol), GFP_KERNEL); | 3427 | volume_info = kmalloc(sizeof(struct smb_vol), GFP_KERNEL); |
3416 | if (!volume_info) | 3428 | if (!volume_info) |
3417 | return ERR_PTR(-ENOMEM); | 3429 | return ERR_PTR(-ENOMEM); |
3418 | 3430 | ||
@@ -3537,8 +3549,10 @@ remote_path_check: | |||
3537 | rc = -ENOSYS; | 3549 | rc = -ENOSYS; |
3538 | goto mount_fail_check; | 3550 | goto mount_fail_check; |
3539 | } | 3551 | } |
3540 | /* build_path_to_root works only when we have a valid tcon */ | 3552 | /* |
3541 | full_path = build_path_to_root(volume_info, cifs_sb, tcon); | 3553 | * cifs_build_path_to_root works only when we have a valid tcon |
3554 | */ | ||
3555 | full_path = cifs_build_path_to_root(volume_info, cifs_sb, tcon); | ||
3542 | if (full_path == NULL) { | 3556 | if (full_path == NULL) { |
3543 | rc = -ENOMEM; | 3557 | rc = -ENOMEM; |
3544 | goto mount_fail_check; | 3558 | goto mount_fail_check; |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index d3671f2acb29..8719bbe0dcc3 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -44,6 +44,38 @@ renew_parental_timestamps(struct dentry *direntry) | |||
44 | } while (!IS_ROOT(direntry)); | 44 | } while (!IS_ROOT(direntry)); |
45 | } | 45 | } |
46 | 46 | ||
47 | char * | ||
48 | cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb, | ||
49 | struct cifs_tcon *tcon) | ||
50 | { | ||
51 | int pplen = vol->prepath ? strlen(vol->prepath) + 1 : 0; | ||
52 | int dfsplen; | ||
53 | char *full_path = NULL; | ||
54 | |||
55 | /* if no prefix path, simply set path to the root of share to "" */ | ||
56 | if (pplen == 0) { | ||
57 | full_path = kzalloc(1, GFP_KERNEL); | ||
58 | return full_path; | ||
59 | } | ||
60 | |||
61 | if (tcon->Flags & SMB_SHARE_IS_IN_DFS) | ||
62 | dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1); | ||
63 | else | ||
64 | dfsplen = 0; | ||
65 | |||
66 | full_path = kmalloc(dfsplen + pplen + 1, GFP_KERNEL); | ||
67 | if (full_path == NULL) | ||
68 | return full_path; | ||
69 | |||
70 | if (dfsplen) | ||
71 | strncpy(full_path, tcon->treeName, dfsplen); | ||
72 | full_path[dfsplen] = CIFS_DIR_SEP(cifs_sb); | ||
73 | strncpy(full_path + dfsplen + 1, vol->prepath, pplen); | ||
74 | convert_delimiter(full_path, CIFS_DIR_SEP(cifs_sb)); | ||
75 | full_path[dfsplen + pplen] = 0; /* add trailing null */ | ||
76 | return full_path; | ||
77 | } | ||
78 | |||
47 | /* Note: caller must free return buffer */ | 79 | /* Note: caller must free return buffer */ |
48 | char * | 80 | char * |
49 | build_path_from_dentry(struct dentry *direntry) | 81 | build_path_from_dentry(struct dentry *direntry) |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 70b6f4c3a0c1..0a6677ba212b 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -505,16 +505,36 @@ out: | |||
505 | return rc; | 505 | return rc; |
506 | } | 506 | } |
507 | 507 | ||
508 | static int cifs_push_posix_locks(struct cifsFileInfo *cfile); | ||
509 | |||
508 | /* | 510 | /* |
509 | * Try to reacquire byte range locks that were released when session | 511 | * Try to reacquire byte range locks that were released when session |
510 | * to server was lost | 512 | * to server was lost. |
511 | */ | 513 | */ |
512 | static int cifs_relock_file(struct cifsFileInfo *cifsFile) | 514 | static int |
515 | cifs_relock_file(struct cifsFileInfo *cfile) | ||
513 | { | 516 | { |
517 | struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb); | ||
518 | struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); | ||
519 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | ||
514 | int rc = 0; | 520 | int rc = 0; |
515 | 521 | ||
516 | /* BB list all locks open on this file and relock */ | 522 | /* we are going to update can_cache_brlcks here - need a write access */ |
523 | down_write(&cinode->lock_sem); | ||
524 | if (cinode->can_cache_brlcks) { | ||
525 | /* can cache locks - no need to push them */ | ||
526 | up_write(&cinode->lock_sem); | ||
527 | return rc; | ||
528 | } | ||
517 | 529 | ||
530 | if (cap_unix(tcon->ses) && | ||
531 | (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && | ||
532 | ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) | ||
533 | rc = cifs_push_posix_locks(cfile); | ||
534 | else | ||
535 | rc = tcon->ses->server->ops->push_mand_locks(cfile); | ||
536 | |||
537 | up_write(&cinode->lock_sem); | ||
518 | return rc; | 538 | return rc; |
519 | } | 539 | } |
520 | 540 | ||
@@ -739,10 +759,15 @@ cifs_del_lock_waiters(struct cifsLockInfo *lock) | |||
739 | } | 759 | } |
740 | } | 760 | } |
741 | 761 | ||
762 | #define CIFS_LOCK_OP 0 | ||
763 | #define CIFS_READ_OP 1 | ||
764 | #define CIFS_WRITE_OP 2 | ||
765 | |||
766 | /* @rw_check : 0 - no op, 1 - read, 2 - write */ | ||
742 | static bool | 767 | static bool |
743 | cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset, | 768 | cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset, |
744 | __u64 length, __u8 type, struct cifsFileInfo *cfile, | 769 | __u64 length, __u8 type, struct cifsFileInfo *cfile, |
745 | struct cifsLockInfo **conf_lock, bool rw_check) | 770 | struct cifsLockInfo **conf_lock, int rw_check) |
746 | { | 771 | { |
747 | struct cifsLockInfo *li; | 772 | struct cifsLockInfo *li; |
748 | struct cifsFileInfo *cur_cfile = fdlocks->cfile; | 773 | struct cifsFileInfo *cur_cfile = fdlocks->cfile; |
@@ -752,9 +777,13 @@ cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset, | |||
752 | if (offset + length <= li->offset || | 777 | if (offset + length <= li->offset || |
753 | offset >= li->offset + li->length) | 778 | offset >= li->offset + li->length) |
754 | continue; | 779 | continue; |
755 | if (rw_check && server->ops->compare_fids(cfile, cur_cfile) && | 780 | if (rw_check != CIFS_LOCK_OP && current->tgid == li->pid && |
756 | current->tgid == li->pid) | 781 | server->ops->compare_fids(cfile, cur_cfile)) { |
757 | continue; | 782 | /* shared lock prevents write op through the same fid */ |
783 | if (!(li->type & server->vals->shared_lock_type) || | ||
784 | rw_check != CIFS_WRITE_OP) | ||
785 | continue; | ||
786 | } | ||
758 | if ((type & server->vals->shared_lock_type) && | 787 | if ((type & server->vals->shared_lock_type) && |
759 | ((server->ops->compare_fids(cfile, cur_cfile) && | 788 | ((server->ops->compare_fids(cfile, cur_cfile) && |
760 | current->tgid == li->pid) || type == li->type)) | 789 | current->tgid == li->pid) || type == li->type)) |
@@ -769,7 +798,7 @@ cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset, | |||
769 | bool | 798 | bool |
770 | cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, __u64 length, | 799 | cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, __u64 length, |
771 | __u8 type, struct cifsLockInfo **conf_lock, | 800 | __u8 type, struct cifsLockInfo **conf_lock, |
772 | bool rw_check) | 801 | int rw_check) |
773 | { | 802 | { |
774 | bool rc = false; | 803 | bool rc = false; |
775 | struct cifs_fid_locks *cur; | 804 | struct cifs_fid_locks *cur; |
@@ -805,7 +834,7 @@ cifs_lock_test(struct cifsFileInfo *cfile, __u64 offset, __u64 length, | |||
805 | down_read(&cinode->lock_sem); | 834 | down_read(&cinode->lock_sem); |
806 | 835 | ||
807 | exist = cifs_find_lock_conflict(cfile, offset, length, type, | 836 | exist = cifs_find_lock_conflict(cfile, offset, length, type, |
808 | &conf_lock, false); | 837 | &conf_lock, CIFS_LOCK_OP); |
809 | if (exist) { | 838 | if (exist) { |
810 | flock->fl_start = conf_lock->offset; | 839 | flock->fl_start = conf_lock->offset; |
811 | flock->fl_end = conf_lock->offset + conf_lock->length - 1; | 840 | flock->fl_end = conf_lock->offset + conf_lock->length - 1; |
@@ -852,7 +881,7 @@ try_again: | |||
852 | down_write(&cinode->lock_sem); | 881 | down_write(&cinode->lock_sem); |
853 | 882 | ||
854 | exist = cifs_find_lock_conflict(cfile, lock->offset, lock->length, | 883 | exist = cifs_find_lock_conflict(cfile, lock->offset, lock->length, |
855 | lock->type, &conf_lock, false); | 884 | lock->type, &conf_lock, CIFS_LOCK_OP); |
856 | if (!exist && cinode->can_cache_brlcks) { | 885 | if (!exist && cinode->can_cache_brlcks) { |
857 | list_add_tail(&lock->llist, &cfile->llist->locks); | 886 | list_add_tail(&lock->llist, &cfile->llist->locks); |
858 | up_write(&cinode->lock_sem); | 887 | up_write(&cinode->lock_sem); |
@@ -948,7 +977,6 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile) | |||
948 | int rc = 0, stored_rc; | 977 | int rc = 0, stored_rc; |
949 | struct cifsLockInfo *li, *tmp; | 978 | struct cifsLockInfo *li, *tmp; |
950 | struct cifs_tcon *tcon; | 979 | struct cifs_tcon *tcon; |
951 | struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); | ||
952 | unsigned int num, max_num, max_buf; | 980 | unsigned int num, max_num, max_buf; |
953 | LOCKING_ANDX_RANGE *buf, *cur; | 981 | LOCKING_ANDX_RANGE *buf, *cur; |
954 | int types[] = {LOCKING_ANDX_LARGE_FILES, | 982 | int types[] = {LOCKING_ANDX_LARGE_FILES, |
@@ -958,21 +986,12 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile) | |||
958 | xid = get_xid(); | 986 | xid = get_xid(); |
959 | tcon = tlink_tcon(cfile->tlink); | 987 | tcon = tlink_tcon(cfile->tlink); |
960 | 988 | ||
961 | /* we are going to update can_cache_brlcks here - need a write access */ | ||
962 | down_write(&cinode->lock_sem); | ||
963 | if (!cinode->can_cache_brlcks) { | ||
964 | up_write(&cinode->lock_sem); | ||
965 | free_xid(xid); | ||
966 | return rc; | ||
967 | } | ||
968 | |||
969 | /* | 989 | /* |
970 | * Accessing maxBuf is racy with cifs_reconnect - need to store value | 990 | * Accessing maxBuf is racy with cifs_reconnect - need to store value |
971 | * and check it for zero before using. | 991 | * and check it for zero before using. |
972 | */ | 992 | */ |
973 | max_buf = tcon->ses->server->maxBuf; | 993 | max_buf = tcon->ses->server->maxBuf; |
974 | if (!max_buf) { | 994 | if (!max_buf) { |
975 | up_write(&cinode->lock_sem); | ||
976 | free_xid(xid); | 995 | free_xid(xid); |
977 | return -EINVAL; | 996 | return -EINVAL; |
978 | } | 997 | } |
@@ -981,7 +1000,6 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile) | |||
981 | sizeof(LOCKING_ANDX_RANGE); | 1000 | sizeof(LOCKING_ANDX_RANGE); |
982 | buf = kzalloc(max_num * sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL); | 1001 | buf = kzalloc(max_num * sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL); |
983 | if (!buf) { | 1002 | if (!buf) { |
984 | up_write(&cinode->lock_sem); | ||
985 | free_xid(xid); | 1003 | free_xid(xid); |
986 | return -ENOMEM; | 1004 | return -ENOMEM; |
987 | } | 1005 | } |
@@ -1018,9 +1036,6 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile) | |||
1018 | } | 1036 | } |
1019 | } | 1037 | } |
1020 | 1038 | ||
1021 | cinode->can_cache_brlcks = false; | ||
1022 | up_write(&cinode->lock_sem); | ||
1023 | |||
1024 | kfree(buf); | 1039 | kfree(buf); |
1025 | free_xid(xid); | 1040 | free_xid(xid); |
1026 | return rc; | 1041 | return rc; |
@@ -1043,7 +1058,6 @@ struct lock_to_push { | |||
1043 | static int | 1058 | static int |
1044 | cifs_push_posix_locks(struct cifsFileInfo *cfile) | 1059 | cifs_push_posix_locks(struct cifsFileInfo *cfile) |
1045 | { | 1060 | { |
1046 | struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); | ||
1047 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | 1061 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); |
1048 | struct file_lock *flock, **before; | 1062 | struct file_lock *flock, **before; |
1049 | unsigned int count = 0, i = 0; | 1063 | unsigned int count = 0, i = 0; |
@@ -1054,14 +1068,6 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile) | |||
1054 | 1068 | ||
1055 | xid = get_xid(); | 1069 | xid = get_xid(); |
1056 | 1070 | ||
1057 | /* we are going to update can_cache_brlcks here - need a write access */ | ||
1058 | down_write(&cinode->lock_sem); | ||
1059 | if (!cinode->can_cache_brlcks) { | ||
1060 | up_write(&cinode->lock_sem); | ||
1061 | free_xid(xid); | ||
1062 | return rc; | ||
1063 | } | ||
1064 | |||
1065 | lock_flocks(); | 1071 | lock_flocks(); |
1066 | cifs_for_each_lock(cfile->dentry->d_inode, before) { | 1072 | cifs_for_each_lock(cfile->dentry->d_inode, before) { |
1067 | if ((*before)->fl_flags & FL_POSIX) | 1073 | if ((*before)->fl_flags & FL_POSIX) |
@@ -1127,9 +1133,6 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile) | |||
1127 | } | 1133 | } |
1128 | 1134 | ||
1129 | out: | 1135 | out: |
1130 | cinode->can_cache_brlcks = false; | ||
1131 | up_write(&cinode->lock_sem); | ||
1132 | |||
1133 | free_xid(xid); | 1136 | free_xid(xid); |
1134 | return rc; | 1137 | return rc; |
1135 | err_out: | 1138 | err_out: |
@@ -1144,14 +1147,27 @@ static int | |||
1144 | cifs_push_locks(struct cifsFileInfo *cfile) | 1147 | cifs_push_locks(struct cifsFileInfo *cfile) |
1145 | { | 1148 | { |
1146 | struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb); | 1149 | struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb); |
1150 | struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); | ||
1147 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | 1151 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); |
1152 | int rc = 0; | ||
1153 | |||
1154 | /* we are going to update can_cache_brlcks here - need a write access */ | ||
1155 | down_write(&cinode->lock_sem); | ||
1156 | if (!cinode->can_cache_brlcks) { | ||
1157 | up_write(&cinode->lock_sem); | ||
1158 | return rc; | ||
1159 | } | ||
1148 | 1160 | ||
1149 | if (cap_unix(tcon->ses) && | 1161 | if (cap_unix(tcon->ses) && |
1150 | (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && | 1162 | (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && |
1151 | ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) | 1163 | ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) |
1152 | return cifs_push_posix_locks(cfile); | 1164 | rc = cifs_push_posix_locks(cfile); |
1165 | else | ||
1166 | rc = tcon->ses->server->ops->push_mand_locks(cfile); | ||
1153 | 1167 | ||
1154 | return tcon->ses->server->ops->push_mand_locks(cfile); | 1168 | cinode->can_cache_brlcks = false; |
1169 | up_write(&cinode->lock_sem); | ||
1170 | return rc; | ||
1155 | } | 1171 | } |
1156 | 1172 | ||
1157 | static void | 1173 | static void |
@@ -1436,16 +1452,18 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type, | |||
1436 | return -ENOMEM; | 1452 | return -ENOMEM; |
1437 | 1453 | ||
1438 | rc = cifs_lock_add_if(cfile, lock, wait_flag); | 1454 | rc = cifs_lock_add_if(cfile, lock, wait_flag); |
1439 | if (rc < 0) | 1455 | if (rc < 0) { |
1440 | kfree(lock); | 1456 | kfree(lock); |
1441 | if (rc <= 0) | 1457 | return rc; |
1458 | } | ||
1459 | if (!rc) | ||
1442 | goto out; | 1460 | goto out; |
1443 | 1461 | ||
1444 | rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length, | 1462 | rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length, |
1445 | type, 1, 0, wait_flag); | 1463 | type, 1, 0, wait_flag); |
1446 | if (rc) { | 1464 | if (rc) { |
1447 | kfree(lock); | 1465 | kfree(lock); |
1448 | goto out; | 1466 | return rc; |
1449 | } | 1467 | } |
1450 | 1468 | ||
1451 | cifs_lock_add(cfile, lock); | 1469 | cifs_lock_add(cfile, lock); |
@@ -2085,7 +2103,15 @@ static int cifs_write_end(struct file *file, struct address_space *mapping, | |||
2085 | } else { | 2103 | } else { |
2086 | rc = copied; | 2104 | rc = copied; |
2087 | pos += copied; | 2105 | pos += copied; |
2088 | set_page_dirty(page); | 2106 | /* |
2107 | * When we use strict cache mode and cifs_strict_writev was run | ||
2108 | * with level II oplock (indicated by leave_pages_clean field of | ||
2109 | * CIFS_I(inode)), we can leave pages clean - cifs_strict_writev | ||
2110 | * sent the data to the server itself. | ||
2111 | */ | ||
2112 | if (!CIFS_I(inode)->leave_pages_clean || | ||
2113 | !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO)) | ||
2114 | set_page_dirty(page); | ||
2089 | } | 2115 | } |
2090 | 2116 | ||
2091 | if (rc > 0) { | 2117 | if (rc > 0) { |
@@ -2436,8 +2462,8 @@ ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov, | |||
2436 | } | 2462 | } |
2437 | 2463 | ||
2438 | static ssize_t | 2464 | static ssize_t |
2439 | cifs_writev(struct kiocb *iocb, const struct iovec *iov, | 2465 | cifs_pagecache_writev(struct kiocb *iocb, const struct iovec *iov, |
2440 | unsigned long nr_segs, loff_t pos) | 2466 | unsigned long nr_segs, loff_t pos, bool cache_ex) |
2441 | { | 2467 | { |
2442 | struct file *file = iocb->ki_filp; | 2468 | struct file *file = iocb->ki_filp; |
2443 | struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data; | 2469 | struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data; |
@@ -2457,10 +2483,14 @@ cifs_writev(struct kiocb *iocb, const struct iovec *iov, | |||
2457 | down_read(&cinode->lock_sem); | 2483 | down_read(&cinode->lock_sem); |
2458 | if (!cifs_find_lock_conflict(cfile, pos, iov_length(iov, nr_segs), | 2484 | if (!cifs_find_lock_conflict(cfile, pos, iov_length(iov, nr_segs), |
2459 | server->vals->exclusive_lock_type, NULL, | 2485 | server->vals->exclusive_lock_type, NULL, |
2460 | true)) { | 2486 | CIFS_WRITE_OP)) { |
2461 | mutex_lock(&inode->i_mutex); | 2487 | mutex_lock(&inode->i_mutex); |
2488 | if (!cache_ex) | ||
2489 | cinode->leave_pages_clean = true; | ||
2462 | rc = __generic_file_aio_write(iocb, iov, nr_segs, | 2490 | rc = __generic_file_aio_write(iocb, iov, nr_segs, |
2463 | &iocb->ki_pos); | 2491 | &iocb->ki_pos); |
2492 | if (!cache_ex) | ||
2493 | cinode->leave_pages_clean = false; | ||
2464 | mutex_unlock(&inode->i_mutex); | 2494 | mutex_unlock(&inode->i_mutex); |
2465 | } | 2495 | } |
2466 | 2496 | ||
@@ -2487,42 +2517,62 @@ cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov, | |||
2487 | struct cifsFileInfo *cfile = (struct cifsFileInfo *) | 2517 | struct cifsFileInfo *cfile = (struct cifsFileInfo *) |
2488 | iocb->ki_filp->private_data; | 2518 | iocb->ki_filp->private_data; |
2489 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | 2519 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); |
2490 | 2520 | ssize_t written, written2; | |
2491 | #ifdef CONFIG_CIFS_SMB2 | ||
2492 | /* | 2521 | /* |
2493 | * If we have an oplock for read and want to write a data to the file | 2522 | * We need to store clientCanCacheAll here to prevent race |
2494 | * we need to store it in the page cache and then push it to the server | 2523 | * conditions - this value can be changed during an execution |
2495 | * to be sure the next read will get a valid data. | 2524 | * of generic_file_aio_write. For CIFS it can be changed from |
2525 | * true to false only, but for SMB2 it can be changed both from | ||
2526 | * true to false and vice versa. So, we can end up with a data | ||
2527 | * stored in the cache, not marked dirty and not sent to the | ||
2528 | * server if this value changes its state from false to true | ||
2529 | * after cifs_write_end. | ||
2496 | */ | 2530 | */ |
2497 | if (!cinode->clientCanCacheAll && cinode->clientCanCacheRead) { | 2531 | bool cache_ex = cinode->clientCanCacheAll; |
2498 | ssize_t written; | 2532 | bool cache_read = cinode->clientCanCacheRead; |
2499 | int rc; | 2533 | int rc; |
2500 | 2534 | loff_t saved_pos; | |
2501 | written = generic_file_aio_write(iocb, iov, nr_segs, pos); | ||
2502 | rc = filemap_fdatawrite(inode->i_mapping); | ||
2503 | if (rc) | ||
2504 | return (ssize_t)rc; | ||
2505 | 2535 | ||
2506 | return written; | 2536 | if (cache_ex) { |
2537 | if (cap_unix(tcon->ses) && | ||
2538 | ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0) && | ||
2539 | (CIFS_UNIX_FCNTL_CAP & le64_to_cpu( | ||
2540 | tcon->fsUnixInfo.Capability))) | ||
2541 | return generic_file_aio_write(iocb, iov, nr_segs, pos); | ||
2542 | return cifs_pagecache_writev(iocb, iov, nr_segs, pos, cache_ex); | ||
2507 | } | 2543 | } |
2508 | #endif | ||
2509 | 2544 | ||
2510 | /* | 2545 | /* |
2511 | * For non-oplocked files in strict cache mode we need to write the data | 2546 | * For files without exclusive oplock in strict cache mode we need to |
2512 | * to the server exactly from the pos to pos+len-1 rather than flush all | 2547 | * write the data to the server exactly from the pos to pos+len-1 rather |
2513 | * affected pages because it may cause a error with mandatory locks on | 2548 | * than flush all affected pages because it may cause a error with |
2514 | * these pages but not on the region from pos to ppos+len-1. | 2549 | * mandatory locks on these pages but not on the region from pos to |
2550 | * ppos+len-1. | ||
2515 | */ | 2551 | */ |
2552 | written = cifs_user_writev(iocb, iov, nr_segs, pos); | ||
2553 | if (!cache_read || written <= 0) | ||
2554 | return written; | ||
2516 | 2555 | ||
2517 | if (!cinode->clientCanCacheAll) | 2556 | saved_pos = iocb->ki_pos; |
2518 | return cifs_user_writev(iocb, iov, nr_segs, pos); | 2557 | iocb->ki_pos = pos; |
2519 | 2558 | /* we have a read oplock - need to store a data in the page cache */ | |
2520 | if (cap_unix(tcon->ses) && | 2559 | if (cap_unix(tcon->ses) && |
2521 | (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && | 2560 | ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0) && |
2522 | ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) | 2561 | (CIFS_UNIX_FCNTL_CAP & le64_to_cpu( |
2523 | return generic_file_aio_write(iocb, iov, nr_segs, pos); | 2562 | tcon->fsUnixInfo.Capability))) |
2524 | 2563 | written2 = generic_file_aio_write(iocb, iov, nr_segs, pos); | |
2525 | return cifs_writev(iocb, iov, nr_segs, pos); | 2564 | else |
2565 | written2 = cifs_pagecache_writev(iocb, iov, nr_segs, pos, | ||
2566 | cache_ex); | ||
2567 | /* errors occured during writing - invalidate the page cache */ | ||
2568 | if (written2 < 0) { | ||
2569 | rc = cifs_invalidate_mapping(inode); | ||
2570 | if (rc) | ||
2571 | written = (ssize_t)rc; | ||
2572 | else | ||
2573 | iocb->ki_pos = saved_pos; | ||
2574 | } | ||
2575 | return written; | ||
2526 | } | 2576 | } |
2527 | 2577 | ||
2528 | static struct cifs_readdata * | 2578 | static struct cifs_readdata * |
@@ -2892,7 +2942,7 @@ cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov, | |||
2892 | down_read(&cinode->lock_sem); | 2942 | down_read(&cinode->lock_sem); |
2893 | if (!cifs_find_lock_conflict(cfile, pos, iov_length(iov, nr_segs), | 2943 | if (!cifs_find_lock_conflict(cfile, pos, iov_length(iov, nr_segs), |
2894 | tcon->ses->server->vals->shared_lock_type, | 2944 | tcon->ses->server->vals->shared_lock_type, |
2895 | NULL, true)) | 2945 | NULL, CIFS_READ_OP)) |
2896 | rc = generic_file_aio_read(iocb, iov, nr_segs, pos); | 2946 | rc = generic_file_aio_read(iocb, iov, nr_segs, pos); |
2897 | up_read(&cinode->lock_sem); | 2947 | up_read(&cinode->lock_sem); |
2898 | return rc; | 2948 | return rc; |
@@ -3536,7 +3586,7 @@ void cifs_oplock_break(struct work_struct *work) | |||
3536 | if (cinode->clientCanCacheRead == 0) { | 3586 | if (cinode->clientCanCacheRead == 0) { |
3537 | rc = filemap_fdatawait(inode->i_mapping); | 3587 | rc = filemap_fdatawait(inode->i_mapping); |
3538 | mapping_set_error(inode->i_mapping, rc); | 3588 | mapping_set_error(inode->i_mapping, rc); |
3539 | invalidate_remote_inode(inode); | 3589 | cifs_invalidate_mapping(inode); |
3540 | } | 3590 | } |
3541 | cFYI(1, "Oplock flush inode %p rc %d", inode, rc); | 3591 | cFYI(1, "Oplock flush inode %p rc %d", inode, rc); |
3542 | } | 3592 | } |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index afdff79651f1..ed6208ff85a7 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -1791,11 +1791,12 @@ int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, | |||
1791 | stat->ino = CIFS_I(inode)->uniqueid; | 1791 | stat->ino = CIFS_I(inode)->uniqueid; |
1792 | 1792 | ||
1793 | /* | 1793 | /* |
1794 | * If on a multiuser mount without unix extensions, and the admin hasn't | 1794 | * If on a multiuser mount without unix extensions or cifsacl being |
1795 | * overridden them, set the ownership to the fsuid/fsgid of the current | 1795 | * enabled, and the admin hasn't overridden them, set the ownership |
1796 | * process. | 1796 | * to the fsuid/fsgid of the current process. |
1797 | */ | 1797 | */ |
1798 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) && | 1798 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) && |
1799 | !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && | ||
1799 | !tcon->unix_ext) { | 1800 | !tcon->unix_ext) { |
1800 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)) | 1801 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)) |
1801 | stat->uid = current_fsuid(); | 1802 | stat->uid = current_fsuid(); |
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index d5ce9e26696c..a82bc51fdc82 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c | |||
@@ -204,7 +204,7 @@ cifs_convert_address(struct sockaddr *dst, const char *src, int len) | |||
204 | return rc; | 204 | return rc; |
205 | } | 205 | } |
206 | 206 | ||
207 | int | 207 | void |
208 | cifs_set_port(struct sockaddr *addr, const unsigned short int port) | 208 | cifs_set_port(struct sockaddr *addr, const unsigned short int port) |
209 | { | 209 | { |
210 | switch (addr->sa_family) { | 210 | switch (addr->sa_family) { |
@@ -214,19 +214,7 @@ cifs_set_port(struct sockaddr *addr, const unsigned short int port) | |||
214 | case AF_INET6: | 214 | case AF_INET6: |
215 | ((struct sockaddr_in6 *)addr)->sin6_port = htons(port); | 215 | ((struct sockaddr_in6 *)addr)->sin6_port = htons(port); |
216 | break; | 216 | break; |
217 | default: | ||
218 | return 0; | ||
219 | } | 217 | } |
220 | return 1; | ||
221 | } | ||
222 | |||
223 | int | ||
224 | cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len, | ||
225 | const unsigned short int port) | ||
226 | { | ||
227 | if (!cifs_convert_address(dst, src, len)) | ||
228 | return 0; | ||
229 | return cifs_set_port(dst, port); | ||
230 | } | 218 | } |
231 | 219 | ||
232 | /***************************************************************************** | 220 | /***************************************************************************** |
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 1c576e871366..6002fdc920ae 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
@@ -66,18 +66,20 @@ static inline void dump_cifs_file_struct(struct file *file, char *label) | |||
66 | #endif /* DEBUG2 */ | 66 | #endif /* DEBUG2 */ |
67 | 67 | ||
68 | /* | 68 | /* |
69 | * Attempt to preload the dcache with the results from the FIND_FIRST/NEXT | ||
70 | * | ||
69 | * Find the dentry that matches "name". If there isn't one, create one. If it's | 71 | * Find the dentry that matches "name". If there isn't one, create one. If it's |
70 | * a negative dentry or the uniqueid changed, then drop it and recreate it. | 72 | * a negative dentry or the uniqueid changed, then drop it and recreate it. |
71 | */ | 73 | */ |
72 | static struct dentry * | 74 | static void |
73 | cifs_readdir_lookup(struct dentry *parent, struct qstr *name, | 75 | cifs_prime_dcache(struct dentry *parent, struct qstr *name, |
74 | struct cifs_fattr *fattr) | 76 | struct cifs_fattr *fattr) |
75 | { | 77 | { |
76 | struct dentry *dentry, *alias; | 78 | struct dentry *dentry, *alias; |
77 | struct inode *inode; | 79 | struct inode *inode; |
78 | struct super_block *sb = parent->d_inode->i_sb; | 80 | struct super_block *sb = parent->d_inode->i_sb; |
79 | 81 | ||
80 | cFYI(1, "For %s", name->name); | 82 | cFYI(1, "%s: for %s", __func__, name->name); |
81 | 83 | ||
82 | if (parent->d_op && parent->d_op->d_hash) | 84 | if (parent->d_op && parent->d_op->d_hash) |
83 | parent->d_op->d_hash(parent, parent->d_inode, name); | 85 | parent->d_op->d_hash(parent, parent->d_inode, name); |
@@ -87,37 +89,32 @@ cifs_readdir_lookup(struct dentry *parent, struct qstr *name, | |||
87 | dentry = d_lookup(parent, name); | 89 | dentry = d_lookup(parent, name); |
88 | if (dentry) { | 90 | if (dentry) { |
89 | int err; | 91 | int err; |
92 | |||
90 | inode = dentry->d_inode; | 93 | inode = dentry->d_inode; |
91 | /* update inode in place if i_ino didn't change */ | 94 | /* update inode in place if i_ino didn't change */ |
92 | if (inode && CIFS_I(inode)->uniqueid == fattr->cf_uniqueid) { | 95 | if (inode && CIFS_I(inode)->uniqueid == fattr->cf_uniqueid) { |
93 | cifs_fattr_to_inode(inode, fattr); | 96 | cifs_fattr_to_inode(inode, fattr); |
94 | return dentry; | 97 | goto out; |
95 | } | 98 | } |
96 | err = d_invalidate(dentry); | 99 | err = d_invalidate(dentry); |
97 | dput(dentry); | 100 | dput(dentry); |
98 | if (err) | 101 | if (err) |
99 | return NULL; | 102 | return; |
100 | } | 103 | } |
101 | 104 | ||
102 | dentry = d_alloc(parent, name); | 105 | dentry = d_alloc(parent, name); |
103 | if (dentry == NULL) | 106 | if (!dentry) |
104 | return NULL; | 107 | return; |
105 | 108 | ||
106 | inode = cifs_iget(sb, fattr); | 109 | inode = cifs_iget(sb, fattr); |
107 | if (!inode) { | 110 | if (!inode) |
108 | dput(dentry); | 111 | goto out; |
109 | return NULL; | ||
110 | } | ||
111 | 112 | ||
112 | alias = d_materialise_unique(dentry, inode); | 113 | alias = d_materialise_unique(dentry, inode); |
113 | if (alias != NULL) { | 114 | if (alias && !IS_ERR(alias)) |
114 | dput(dentry); | 115 | dput(alias); |
115 | if (IS_ERR(alias)) | 116 | out: |
116 | return NULL; | 117 | dput(dentry); |
117 | dentry = alias; | ||
118 | } | ||
119 | |||
120 | return dentry; | ||
121 | } | 118 | } |
122 | 119 | ||
123 | static void | 120 | static void |
@@ -137,6 +134,16 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb) | |||
137 | if (fattr->cf_cifsattrs & ATTR_READONLY) | 134 | if (fattr->cf_cifsattrs & ATTR_READONLY) |
138 | fattr->cf_mode &= ~S_IWUGO; | 135 | fattr->cf_mode &= ~S_IWUGO; |
139 | 136 | ||
137 | /* | ||
138 | * We of course don't get ACL info in FIND_FIRST/NEXT results, so | ||
139 | * mark it for revalidation so that "ls -l" will look right. It might | ||
140 | * be super-slow, but if we don't do this then the ownership of files | ||
141 | * may look wrong since the inodes may not have timed out by the time | ||
142 | * "ls" does a stat() call on them. | ||
143 | */ | ||
144 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) | ||
145 | fattr->cf_flags |= CIFS_FATTR_NEED_REVAL; | ||
146 | |||
140 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL && | 147 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL && |
141 | fattr->cf_cifsattrs & ATTR_SYSTEM) { | 148 | fattr->cf_cifsattrs & ATTR_SYSTEM) { |
142 | if (fattr->cf_eof == 0) { | 149 | if (fattr->cf_eof == 0) { |
@@ -652,7 +659,6 @@ static int cifs_filldir(char *find_entry, struct file *file, filldir_t filldir, | |||
652 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 659 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
653 | struct cifs_dirent de = { NULL, }; | 660 | struct cifs_dirent de = { NULL, }; |
654 | struct cifs_fattr fattr; | 661 | struct cifs_fattr fattr; |
655 | struct dentry *dentry; | ||
656 | struct qstr name; | 662 | struct qstr name; |
657 | int rc = 0; | 663 | int rc = 0; |
658 | ino_t ino; | 664 | ino_t ino; |
@@ -723,13 +729,11 @@ static int cifs_filldir(char *find_entry, struct file *file, filldir_t filldir, | |||
723 | */ | 729 | */ |
724 | fattr.cf_flags |= CIFS_FATTR_NEED_REVAL; | 730 | fattr.cf_flags |= CIFS_FATTR_NEED_REVAL; |
725 | 731 | ||
726 | ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid); | 732 | cifs_prime_dcache(file->f_dentry, &name, &fattr); |
727 | dentry = cifs_readdir_lookup(file->f_dentry, &name, &fattr); | ||
728 | 733 | ||
734 | ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid); | ||
729 | rc = filldir(dirent, name.name, name.len, file->f_pos, ino, | 735 | rc = filldir(dirent, name.name, name.len, file->f_pos, ino, |
730 | fattr.cf_dtype); | 736 | fattr.cf_dtype); |
731 | |||
732 | dput(dentry); | ||
733 | return rc; | 737 | return rc; |
734 | } | 738 | } |
735 | 739 | ||
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index 34cea2798333..a5d234c8d5d9 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c | |||
@@ -575,37 +575,6 @@ cifs_query_file_info(const unsigned int xid, struct cifs_tcon *tcon, | |||
575 | return CIFSSMBQFileInfo(xid, tcon, fid->netfid, data); | 575 | return CIFSSMBQFileInfo(xid, tcon, fid->netfid, data); |
576 | } | 576 | } |
577 | 577 | ||
578 | static char * | ||
579 | cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb, | ||
580 | struct cifs_tcon *tcon) | ||
581 | { | ||
582 | int pplen = vol->prepath ? strlen(vol->prepath) : 0; | ||
583 | int dfsplen; | ||
584 | char *full_path = NULL; | ||
585 | |||
586 | /* if no prefix path, simply set path to the root of share to "" */ | ||
587 | if (pplen == 0) { | ||
588 | full_path = kzalloc(1, GFP_KERNEL); | ||
589 | return full_path; | ||
590 | } | ||
591 | |||
592 | if (tcon->Flags & SMB_SHARE_IS_IN_DFS) | ||
593 | dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1); | ||
594 | else | ||
595 | dfsplen = 0; | ||
596 | |||
597 | full_path = kmalloc(dfsplen + pplen + 1, GFP_KERNEL); | ||
598 | if (full_path == NULL) | ||
599 | return full_path; | ||
600 | |||
601 | if (dfsplen) | ||
602 | strncpy(full_path, tcon->treeName, dfsplen); | ||
603 | strncpy(full_path + dfsplen, vol->prepath, pplen); | ||
604 | convert_delimiter(full_path, CIFS_DIR_SEP(cifs_sb)); | ||
605 | full_path[dfsplen + pplen] = 0; /* add trailing null */ | ||
606 | return full_path; | ||
607 | } | ||
608 | |||
609 | static void | 578 | static void |
610 | cifs_clear_stats(struct cifs_tcon *tcon) | 579 | cifs_clear_stats(struct cifs_tcon *tcon) |
611 | { | 580 | { |
@@ -943,7 +912,6 @@ struct smb_version_operations smb1_operations = { | |||
943 | .set_path_size = CIFSSMBSetEOF, | 912 | .set_path_size = CIFSSMBSetEOF, |
944 | .set_file_size = CIFSSMBSetFileSize, | 913 | .set_file_size = CIFSSMBSetFileSize, |
945 | .set_file_info = smb_set_file_info, | 914 | .set_file_info = smb_set_file_info, |
946 | .build_path_to_root = cifs_build_path_to_root, | ||
947 | .echo = CIFSSMBEcho, | 915 | .echo = CIFSSMBEcho, |
948 | .mkdir = CIFSSMBMkDir, | 916 | .mkdir = CIFSSMBMkDir, |
949 | .mkdir_setinfo = cifs_mkdir_setinfo, | 917 | .mkdir_setinfo = cifs_mkdir_setinfo, |
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c index a93eec30a50d..71e6aed4b382 100644 --- a/fs/cifs/smb2file.c +++ b/fs/cifs/smb2file.c | |||
@@ -260,13 +260,6 @@ smb2_push_mandatory_locks(struct cifsFileInfo *cfile) | |||
260 | struct cifs_fid_locks *fdlocks; | 260 | struct cifs_fid_locks *fdlocks; |
261 | 261 | ||
262 | xid = get_xid(); | 262 | xid = get_xid(); |
263 | /* we are going to update can_cache_brlcks here - need a write access */ | ||
264 | down_write(&cinode->lock_sem); | ||
265 | if (!cinode->can_cache_brlcks) { | ||
266 | up_write(&cinode->lock_sem); | ||
267 | free_xid(xid); | ||
268 | return rc; | ||
269 | } | ||
270 | 263 | ||
271 | /* | 264 | /* |
272 | * Accessing maxBuf is racy with cifs_reconnect - need to store value | 265 | * Accessing maxBuf is racy with cifs_reconnect - need to store value |
@@ -274,7 +267,6 @@ smb2_push_mandatory_locks(struct cifsFileInfo *cfile) | |||
274 | */ | 267 | */ |
275 | max_buf = tlink_tcon(cfile->tlink)->ses->server->maxBuf; | 268 | max_buf = tlink_tcon(cfile->tlink)->ses->server->maxBuf; |
276 | if (!max_buf) { | 269 | if (!max_buf) { |
277 | up_write(&cinode->lock_sem); | ||
278 | free_xid(xid); | 270 | free_xid(xid); |
279 | return -EINVAL; | 271 | return -EINVAL; |
280 | } | 272 | } |
@@ -282,7 +274,6 @@ smb2_push_mandatory_locks(struct cifsFileInfo *cfile) | |||
282 | max_num = max_buf / sizeof(struct smb2_lock_element); | 274 | max_num = max_buf / sizeof(struct smb2_lock_element); |
283 | buf = kzalloc(max_num * sizeof(struct smb2_lock_element), GFP_KERNEL); | 275 | buf = kzalloc(max_num * sizeof(struct smb2_lock_element), GFP_KERNEL); |
284 | if (!buf) { | 276 | if (!buf) { |
285 | up_write(&cinode->lock_sem); | ||
286 | free_xid(xid); | 277 | free_xid(xid); |
287 | return -ENOMEM; | 278 | return -ENOMEM; |
288 | } | 279 | } |
@@ -293,10 +284,7 @@ smb2_push_mandatory_locks(struct cifsFileInfo *cfile) | |||
293 | rc = stored_rc; | 284 | rc = stored_rc; |
294 | } | 285 | } |
295 | 286 | ||
296 | cinode->can_cache_brlcks = false; | ||
297 | kfree(buf); | 287 | kfree(buf); |
298 | |||
299 | up_write(&cinode->lock_sem); | ||
300 | free_xid(xid); | 288 | free_xid(xid); |
301 | return rc; | 289 | return rc; |
302 | } | 290 | } |
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 4d9dbe0b7385..d79de7bc4435 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c | |||
@@ -262,23 +262,6 @@ smb2_query_file_info(const unsigned int xid, struct cifs_tcon *tcon, | |||
262 | return rc; | 262 | return rc; |
263 | } | 263 | } |
264 | 264 | ||
265 | static char * | ||
266 | smb2_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb, | ||
267 | struct cifs_tcon *tcon) | ||
268 | { | ||
269 | int pplen = vol->prepath ? strlen(vol->prepath) : 0; | ||
270 | char *full_path = NULL; | ||
271 | |||
272 | /* if no prefix path, simply set path to the root of share to "" */ | ||
273 | if (pplen == 0) { | ||
274 | full_path = kzalloc(2, GFP_KERNEL); | ||
275 | return full_path; | ||
276 | } | ||
277 | |||
278 | cERROR(1, "prefixpath is not supported for SMB2 now"); | ||
279 | return NULL; | ||
280 | } | ||
281 | |||
282 | static bool | 265 | static bool |
283 | smb2_can_echo(struct TCP_Server_Info *server) | 266 | smb2_can_echo(struct TCP_Server_Info *server) |
284 | { | 267 | { |
@@ -613,7 +596,6 @@ struct smb_version_operations smb21_operations = { | |||
613 | .set_path_size = smb2_set_path_size, | 596 | .set_path_size = smb2_set_path_size, |
614 | .set_file_size = smb2_set_file_size, | 597 | .set_file_size = smb2_set_file_size, |
615 | .set_file_info = smb2_set_file_info, | 598 | .set_file_info = smb2_set_file_info, |
616 | .build_path_to_root = smb2_build_path_to_root, | ||
617 | .mkdir = smb2_mkdir, | 599 | .mkdir = smb2_mkdir, |
618 | .mkdir_setinfo = smb2_mkdir_setinfo, | 600 | .mkdir_setinfo = smb2_mkdir_setinfo, |
619 | .rmdir = smb2_rmdir, | 601 | .rmdir = smb2_rmdir, |
@@ -641,6 +623,91 @@ struct smb_version_operations smb21_operations = { | |||
641 | .get_lease_key = smb2_get_lease_key, | 623 | .get_lease_key = smb2_get_lease_key, |
642 | .set_lease_key = smb2_set_lease_key, | 624 | .set_lease_key = smb2_set_lease_key, |
643 | .new_lease_key = smb2_new_lease_key, | 625 | .new_lease_key = smb2_new_lease_key, |
626 | .calc_signature = smb2_calc_signature, | ||
627 | }; | ||
628 | |||
629 | |||
630 | struct smb_version_operations smb30_operations = { | ||
631 | .compare_fids = smb2_compare_fids, | ||
632 | .setup_request = smb2_setup_request, | ||
633 | .setup_async_request = smb2_setup_async_request, | ||
634 | .check_receive = smb2_check_receive, | ||
635 | .add_credits = smb2_add_credits, | ||
636 | .set_credits = smb2_set_credits, | ||
637 | .get_credits_field = smb2_get_credits_field, | ||
638 | .get_credits = smb2_get_credits, | ||
639 | .get_next_mid = smb2_get_next_mid, | ||
640 | .read_data_offset = smb2_read_data_offset, | ||
641 | .read_data_length = smb2_read_data_length, | ||
642 | .map_error = map_smb2_to_linux_error, | ||
643 | .find_mid = smb2_find_mid, | ||
644 | .check_message = smb2_check_message, | ||
645 | .dump_detail = smb2_dump_detail, | ||
646 | .clear_stats = smb2_clear_stats, | ||
647 | .print_stats = smb2_print_stats, | ||
648 | .is_oplock_break = smb2_is_valid_oplock_break, | ||
649 | .need_neg = smb2_need_neg, | ||
650 | .negotiate = smb2_negotiate, | ||
651 | .negotiate_wsize = smb2_negotiate_wsize, | ||
652 | .negotiate_rsize = smb2_negotiate_rsize, | ||
653 | .sess_setup = SMB2_sess_setup, | ||
654 | .logoff = SMB2_logoff, | ||
655 | .tree_connect = SMB2_tcon, | ||
656 | .tree_disconnect = SMB2_tdis, | ||
657 | .is_path_accessible = smb2_is_path_accessible, | ||
658 | .can_echo = smb2_can_echo, | ||
659 | .echo = SMB2_echo, | ||
660 | .query_path_info = smb2_query_path_info, | ||
661 | .get_srv_inum = smb2_get_srv_inum, | ||
662 | .query_file_info = smb2_query_file_info, | ||
663 | .set_path_size = smb2_set_path_size, | ||
664 | .set_file_size = smb2_set_file_size, | ||
665 | .set_file_info = smb2_set_file_info, | ||
666 | .mkdir = smb2_mkdir, | ||
667 | .mkdir_setinfo = smb2_mkdir_setinfo, | ||
668 | .rmdir = smb2_rmdir, | ||
669 | .unlink = smb2_unlink, | ||
670 | .rename = smb2_rename_path, | ||
671 | .create_hardlink = smb2_create_hardlink, | ||
672 | .open = smb2_open_file, | ||
673 | .set_fid = smb2_set_fid, | ||
674 | .close = smb2_close_file, | ||
675 | .flush = smb2_flush_file, | ||
676 | .async_readv = smb2_async_readv, | ||
677 | .async_writev = smb2_async_writev, | ||
678 | .sync_read = smb2_sync_read, | ||
679 | .sync_write = smb2_sync_write, | ||
680 | .query_dir_first = smb2_query_dir_first, | ||
681 | .query_dir_next = smb2_query_dir_next, | ||
682 | .close_dir = smb2_close_dir, | ||
683 | .calc_smb_size = smb2_calc_size, | ||
684 | .is_status_pending = smb2_is_status_pending, | ||
685 | .oplock_response = smb2_oplock_response, | ||
686 | .queryfs = smb2_queryfs, | ||
687 | .mand_lock = smb2_mand_lock, | ||
688 | .mand_unlock_range = smb2_unlock_range, | ||
689 | .push_mand_locks = smb2_push_mandatory_locks, | ||
690 | .get_lease_key = smb2_get_lease_key, | ||
691 | .set_lease_key = smb2_set_lease_key, | ||
692 | .new_lease_key = smb2_new_lease_key, | ||
693 | .calc_signature = smb3_calc_signature, | ||
694 | }; | ||
695 | |||
696 | struct smb_version_values smb20_values = { | ||
697 | .version_string = SMB20_VERSION_STRING, | ||
698 | .protocol_id = SMB20_PROT_ID, | ||
699 | .req_capabilities = 0, /* MBZ */ | ||
700 | .large_lock_type = 0, | ||
701 | .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK, | ||
702 | .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK, | ||
703 | .unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, | ||
704 | .header_size = sizeof(struct smb2_hdr), | ||
705 | .max_header_size = MAX_SMB2_HDR_SIZE, | ||
706 | .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, | ||
707 | .lock_cmd = SMB2_LOCK, | ||
708 | .cap_unix = 0, | ||
709 | .cap_nt_find = SMB2_NT_FIND, | ||
710 | .cap_large_files = SMB2_LARGE_FILES, | ||
644 | }; | 711 | }; |
645 | 712 | ||
646 | struct smb_version_values smb21_values = { | 713 | struct smb_version_values smb21_values = { |
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index cf33622cdac8..41d9d0725f0f 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c | |||
@@ -425,7 +425,7 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) | |||
425 | } | 425 | } |
426 | 426 | ||
427 | cFYI(1, "sec_flags 0x%x", sec_flags); | 427 | cFYI(1, "sec_flags 0x%x", sec_flags); |
428 | if (sec_flags & CIFSSEC_MUST_SIGN) { | 428 | if ((sec_flags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) { |
429 | cFYI(1, "Signing required"); | 429 | cFYI(1, "Signing required"); |
430 | if (!(server->sec_mode & (SMB2_NEGOTIATE_SIGNING_REQUIRED | | 430 | if (!(server->sec_mode & (SMB2_NEGOTIATE_SIGNING_REQUIRED | |
431 | SMB2_NEGOTIATE_SIGNING_ENABLED))) { | 431 | SMB2_NEGOTIATE_SIGNING_ENABLED))) { |
@@ -612,7 +612,8 @@ ssetup_ntlmssp_authenticate: | |||
612 | 612 | ||
613 | /* BB add code to build os and lm fields */ | 613 | /* BB add code to build os and lm fields */ |
614 | 614 | ||
615 | rc = SendReceive2(xid, ses, iov, 2, &resp_buftype, CIFS_LOG_ERROR); | 615 | rc = SendReceive2(xid, ses, iov, 2, &resp_buftype, |
616 | CIFS_LOG_ERROR | CIFS_NEG_OP); | ||
616 | 617 | ||
617 | kfree(security_blob); | 618 | kfree(security_blob); |
618 | rsp = (struct smb2_sess_setup_rsp *)iov[0].iov_base; | 619 | rsp = (struct smb2_sess_setup_rsp *)iov[0].iov_base; |
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 7d25f8b14f93..2aa3535e38ce 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h | |||
@@ -47,6 +47,10 @@ extern struct mid_q_entry *smb2_setup_request(struct cifs_ses *ses, | |||
47 | struct smb_rqst *rqst); | 47 | struct smb_rqst *rqst); |
48 | extern struct mid_q_entry *smb2_setup_async_request( | 48 | extern struct mid_q_entry *smb2_setup_async_request( |
49 | struct TCP_Server_Info *server, struct smb_rqst *rqst); | 49 | struct TCP_Server_Info *server, struct smb_rqst *rqst); |
50 | extern int smb2_calc_signature(struct smb_rqst *rqst, | ||
51 | struct TCP_Server_Info *server); | ||
52 | extern int smb3_calc_signature(struct smb_rqst *rqst, | ||
53 | struct TCP_Server_Info *server); | ||
50 | extern void smb2_echo_request(struct work_struct *work); | 54 | extern void smb2_echo_request(struct work_struct *work); |
51 | extern __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode); | 55 | extern __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode); |
52 | extern __u8 smb2_map_lease_to_oplock(__le32 lease_state); | 56 | extern __u8 smb2_map_lease_to_oplock(__le32 lease_state); |
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c index 2a5fdf26f79f..8dd73e61d762 100644 --- a/fs/cifs/smb2transport.c +++ b/fs/cifs/smb2transport.c | |||
@@ -39,7 +39,7 @@ | |||
39 | #include "smb2status.h" | 39 | #include "smb2status.h" |
40 | #include "smb2glob.h" | 40 | #include "smb2glob.h" |
41 | 41 | ||
42 | static int | 42 | int |
43 | smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) | 43 | smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) |
44 | { | 44 | { |
45 | int i, rc; | 45 | int i, rc; |
@@ -116,6 +116,13 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) | |||
116 | return rc; | 116 | return rc; |
117 | } | 117 | } |
118 | 118 | ||
119 | int | ||
120 | smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) | ||
121 | { | ||
122 | cFYI(1, "smb3 signatures not supported yet"); | ||
123 | return -EOPNOTSUPP; | ||
124 | } | ||
125 | |||
119 | /* must be called with server->srv_mutex held */ | 126 | /* must be called with server->srv_mutex held */ |
120 | static int | 127 | static int |
121 | smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server) | 128 | smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server) |
@@ -132,7 +139,7 @@ smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server) | |||
132 | return rc; | 139 | return rc; |
133 | } | 140 | } |
134 | 141 | ||
135 | rc = smb2_calc_signature(rqst, server); | 142 | rc = server->ops->calc_signature(rqst, server); |
136 | 143 | ||
137 | return rc; | 144 | return rc; |
138 | } | 145 | } |
@@ -168,7 +175,7 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) | |||
168 | memset(smb2_pdu->Signature, 0, SMB2_SIGNATURE_SIZE); | 175 | memset(smb2_pdu->Signature, 0, SMB2_SIGNATURE_SIZE); |
169 | 176 | ||
170 | mutex_lock(&server->srv_mutex); | 177 | mutex_lock(&server->srv_mutex); |
171 | rc = smb2_calc_signature(rqst, server); | 178 | rc = server->ops->calc_signature(rqst, server); |
172 | mutex_unlock(&server->srv_mutex); | 179 | mutex_unlock(&server->srv_mutex); |
173 | 180 | ||
174 | if (rc) | 181 | if (rc) |