diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-12 12:24:13 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-12 12:24:13 -0500 |
commit | 6facac1ab68fbf9cbad31a9d521f3a0d6aa9470e (patch) | |
tree | 1b00b4d9aab6c5567036157044da98857a84237a | |
parent | 3f1c64f410e4394ecefadd7a597a7c20368a65fc (diff) | |
parent | c299dd0e2d3dd61d0048a9d9b021aa01f023ed0c (diff) |
Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6
Pull CIFS fixes from Steve French:
"This includes a set of misc. cifs fixes (most importantly some byte
range lock related write fixes from Pavel, and some ACL and idmap
related fixes from Jeff) but also includes the SMB2.02 dialect
enablement, and a key fix for SMB3 mounts.
Default authentication upgraded to ntlmv2 for cifs (it was already
ntlmv2 for smb2)"
* 'for-next' of git://git.samba.org/sfrench/cifs-2.6: (43 commits)
CIFS: Fix write after setting a read lock for read oplock files
cifs: parse the device name into UNC and prepath
cifs: fix up handling of prefixpath= option
cifs: clean up handling of unc= option
cifs: fix SID binary to string conversion
fix "disabling echoes and oplocks" on SMB2 mounts
Do not send SMB2 signatures for SMB3 frames
cifs: deal with id_to_sid embedded sid reply corner case
cifs: fix hardcoded default security descriptor length
cifs: extra sanity checking for cifs.idmap keys
cifs: avoid extra allocation for small cifs.idmap keys
cifs: simplify id_to_sid and sid_to_id mapping code
CIFS: Fix possible data coherency problem after oplock break to None
CIFS: Do not permit write to a range mandatory locked with a read lock
cifs: rename cifs_readdir_lookup to cifs_prime_dcache and make it void return
cifs: Add CONFIG_CIFS_DEBUG and rename use of CIFS_DEBUG
cifs: Make CIFS_DEBUG possible to undefine
SMB3 mounts fail with access denied to some servers
cifs: Remove unused cEVENT macro
cifs: always zero out smb_vol before parsing 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) |