diff options
author | Jiri Kosina <jkosina@suse.cz> | 2013-01-29 04:48:30 -0500 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2013-01-29 04:48:30 -0500 |
commit | 617677295b53a40d0e54aac4cbbc216ffbc755dd (patch) | |
tree | 51b9e87213243ed5efff252c8e8d8fec4eebc588 /fs/cifs | |
parent | 5c8d1b68e01a144813e38795fe6dbe7ebb506131 (diff) | |
parent | 6abb7c25775b7fb2225ad0508236d63ca710e65f (diff) |
Merge branch 'master' into for-next
Conflicts:
drivers/devfreq/exynos4_bus.c
Sync with Linus' tree to be able to apply patches that are
against newer code (mvneta).
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/Kconfig | 10 | ||||
-rw-r--r-- | fs/cifs/cifs_debug.h | 72 | ||||
-rw-r--r-- | fs/cifs/cifs_dfs_ref.c | 2 | ||||
-rw-r--r-- | fs/cifs/cifsacl.c | 777 | ||||
-rw-r--r-- | fs/cifs/cifsacl.h | 66 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 25 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 36 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 10 | ||||
-rw-r--r-- | fs/cifs/connect.c | 313 | ||||
-rw-r--r-- | fs/cifs/dir.c | 43 | ||||
-rw-r--r-- | fs/cifs/file.c | 215 | ||||
-rw-r--r-- | fs/cifs/inode.c | 7 | ||||
-rw-r--r-- | fs/cifs/netmisc.c | 14 | ||||
-rw-r--r-- | fs/cifs/readdir.c | 72 | ||||
-rw-r--r-- | fs/cifs/smb1ops.c | 43 | ||||
-rw-r--r-- | fs/cifs/smb2file.c | 12 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 105 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 5 | ||||
-rw-r--r-- | fs/cifs/smb2proto.h | 4 | ||||
-rw-r--r-- | fs/cifs/smb2transport.c | 13 | ||||
-rw-r--r-- | fs/cifs/transport.c | 6 |
21 files changed, 852 insertions, 998 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..69ae3d3c3b31 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,39 @@ 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 | |||
40 | /* | 41 | /* |
41 | * debug ON | 42 | * debug ON |
42 | * -------- | 43 | * -------- |
43 | */ | 44 | */ |
44 | #ifdef CIFS_DEBUG | 45 | #ifdef CONFIG_CIFS_DEBUG |
45 | 46 | ||
46 | /* information message: e.g., configuration, major event */ | 47 | /* information message: e.g., configuration, major event */ |
47 | extern int cifsFYI; | 48 | #define cifsfyi(fmt, ...) \ |
48 | #define cifsfyi(fmt, arg...) \ | ||
49 | do { \ | 49 | do { \ |
50 | if (cifsFYI & CIFS_INFO) \ | 50 | if (cifsFYI & CIFS_INFO) \ |
51 | printk(KERN_DEBUG "%s: " fmt "\n", __FILE__, ##arg); \ | 51 | printk(KERN_DEBUG "%s: " fmt "\n", \ |
52 | } while (0) | 52 | __FILE__, ##__VA_ARGS__); \ |
53 | |||
54 | #define cFYI(set, fmt, arg...) \ | ||
55 | do { \ | ||
56 | if (set) \ | ||
57 | cifsfyi(fmt, ##arg); \ | ||
58 | } while (0) | 53 | } while (0) |
59 | 54 | ||
60 | #define cifswarn(fmt, arg...) \ | 55 | #define cFYI(set, fmt, ...) \ |
61 | printk(KERN_WARNING fmt "\n", ##arg) | ||
62 | |||
63 | /* debug event message: */ | ||
64 | extern int cifsERROR; | ||
65 | |||
66 | #define cEVENT(fmt, arg...) \ | ||
67 | do { \ | 56 | do { \ |
68 | if (cifsERROR) \ | 57 | if (set) \ |
69 | printk(KERN_EVENT "%s: " fmt "\n", __FILE__, ##arg); \ | 58 | cifsfyi(fmt, ##__VA_ARGS__); \ |
70 | } while (0) | 59 | } while (0) |
71 | 60 | ||
61 | #define cifswarn(fmt, ...) \ | ||
62 | printk(KERN_WARNING fmt "\n", ##__VA_ARGS__) | ||
63 | |||
72 | /* error event message: e.g., i/o error */ | 64 | /* error event message: e.g., i/o error */ |
73 | #define cifserror(fmt, arg...) \ | 65 | #define cifserror(fmt, ...) \ |
74 | do { \ | 66 | printk(KERN_ERR "CIFS VFS: " fmt "\n", ##__VA_ARGS__); \ |
75 | if (cifsERROR) \ | ||
76 | printk(KERN_ERR "CIFS VFS: " fmt "\n", ##arg); \ | ||
77 | } while (0) | ||
78 | 67 | ||
79 | #define cERROR(set, fmt, arg...) \ | 68 | #define cERROR(set, fmt, ...) \ |
80 | do { \ | 69 | do { \ |
81 | if (set) \ | 70 | if (set) \ |
82 | cifserror(fmt, ##arg); \ | 71 | cifserror(fmt, ##__VA_ARGS__); \ |
83 | } while (0) | 72 | } while (0) |
84 | 73 | ||
85 | /* | 74 | /* |
@@ -87,10 +76,27 @@ do { \ | |||
87 | * --------- | 76 | * --------- |
88 | */ | 77 | */ |
89 | #else /* _CIFS_DEBUG */ | 78 | #else /* _CIFS_DEBUG */ |
90 | #define cERROR(set, fmt, arg...) | 79 | #define cifsfyi(fmt, ...) \ |
91 | #define cEVENT(fmt, arg...) | 80 | do { \ |
92 | #define cFYI(set, fmt, arg...) | 81 | if (0) \ |
93 | #define cifserror(fmt, arg...) | 82 | printk(KERN_DEBUG "%s: " fmt "\n", \ |
83 | __FILE__, ##__VA_ARGS__); \ | ||
84 | } while (0) | ||
85 | #define cFYI(set, fmt, ...) \ | ||
86 | do { \ | ||
87 | if (0 && set) \ | ||
88 | cifsfyi(fmt, ##__VA_ARGS__); \ | ||
89 | } while (0) | ||
90 | #define cifserror(fmt, ...) \ | ||
91 | do { \ | ||
92 | if (0) \ | ||
93 | printk(KERN_ERR "CIFS VFS: " fmt "\n", ##__VA_ARGS__); \ | ||
94 | } while (0) | ||
95 | #define cERROR(set, fmt, ...) \ | ||
96 | do { \ | ||
97 | if (0 && set) \ | ||
98 | cifserror(fmt, ##__VA_ARGS__); \ | ||
99 | } while (0) | ||
94 | #endif /* _CIFS_DEBUG */ | 100 | #endif /* _CIFS_DEBUG */ |
95 | 101 | ||
96 | #endif /* _H_CIFS_DEBUG */ | 102 | #endif /* _H_CIFS_DEBUG */ |
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index ce5cbd717bfc..210fce2df308 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c | |||
@@ -226,6 +226,8 @@ compose_mount_options_out: | |||
226 | compose_mount_options_err: | 226 | compose_mount_options_err: |
227 | kfree(mountdata); | 227 | kfree(mountdata); |
228 | mountdata = ERR_PTR(rc); | 228 | mountdata = ERR_PTR(rc); |
229 | kfree(*devname); | ||
230 | *devname = NULL; | ||
229 | goto compose_mount_options_out; | 231 | goto compose_mount_options_out; |
230 | } | 232 | } |
231 | 233 | ||
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index fc783e264420..5cbd00e74067 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,214 +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 | } |
135 | |||
136 | return sidstr; | ||
225 | } | 137 | } |
226 | 138 | ||
227 | static void | 139 | /* |
228 | 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 |
229 | 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) | ||
230 | { | 145 | { |
231 | int rc; | 146 | int i; |
232 | char *strptr; | 147 | int num_subauth, num_sat, num_saw; |
233 | struct rb_node *node = root->rb_node; | ||
234 | struct rb_node *parent = NULL; | ||
235 | struct rb_node **linkto = &(root->rb_node); | ||
236 | struct cifs_sid_id *lsidid; | ||
237 | |||
238 | while (node) { | ||
239 | lsidid = rb_entry(node, struct cifs_sid_id, rbnode); | ||
240 | parent = node; | ||
241 | rc = compare_sids(sidptr, &((lsidid)->sid)); | ||
242 | if (rc > 0) { | ||
243 | linkto = &(node->rb_left); | ||
244 | node = node->rb_left; | ||
245 | } else if (rc < 0) { | ||
246 | linkto = &(node->rb_right); | ||
247 | node = node->rb_right; | ||
248 | } | ||
249 | } | ||
250 | |||
251 | memcpy(&(*psidid)->sid, sidptr, sizeof(struct cifs_sid)); | ||
252 | (*psidid)->time = jiffies - (SID_MAP_RETRY + 1); | ||
253 | (*psidid)->refcount = 0; | ||
254 | 148 | ||
255 | sprintf((*psidid)->sidstr, "%s", typestr); | 149 | if ((!ctsid) || (!cwsid)) |
256 | strptr = (*psidid)->sidstr + strlen((*psidid)->sidstr); | 150 | return 1; |
257 | sid_to_str(&(*psidid)->sid, strptr); | ||
258 | 151 | ||
259 | clear_bit(SID_ID_PENDING, &(*psidid)->state); | 152 | /* compare the revision */ |
260 | 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 | } | ||
261 | 159 | ||
262 | rb_link_node(&(*psidid)->rbnode, parent, linkto); | 160 | /* compare all of the six auth values */ |
263 | rb_insert_color(&(*psidid)->rbnode, root); | 161 | for (i = 0; i < NUM_AUTHS; ++i) { |
264 | } | 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 | } | ||
265 | 169 | ||
266 | static struct cifs_sid_id * | 170 | /* compare all of the subauth values if any */ |
267 | id_rb_search(struct rb_root *root, struct cifs_sid *sidptr) | 171 | num_sat = ctsid->num_subauth; |
268 | { | 172 | num_saw = cwsid->num_subauth; |
269 | int rc; | 173 | num_subauth = num_sat < num_saw ? num_sat : num_saw; |
270 | struct rb_node *node = root->rb_node; | 174 | if (num_subauth) { |
271 | struct cifs_sid_id *lsidid; | 175 | for (i = 0; i < num_subauth; ++i) { |
272 | 176 | if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) { | |
273 | while (node) { | 177 | if (le32_to_cpu(ctsid->sub_auth[i]) > |
274 | lsidid = rb_entry(node, struct cifs_sid_id, rbnode); | 178 | le32_to_cpu(cwsid->sub_auth[i])) |
275 | rc = compare_sids(sidptr, &((lsidid)->sid)); | 179 | return 1; |
276 | if (rc > 0) { | 180 | else |
277 | node = node->rb_left; | 181 | return -1; |
278 | } else if (rc < 0) { | 182 | } |
279 | node = node->rb_right; | 183 | } |
280 | } else /* node found */ | ||
281 | return lsidid; | ||
282 | } | 184 | } |
283 | 185 | ||
284 | return NULL; | 186 | return 0; /* sids compare/match */ |
285 | } | 187 | } |
286 | 188 | ||
287 | static int | 189 | static void |
288 | sidid_pending_wait(void *unused) | 190 | cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src) |
289 | { | 191 | { |
290 | schedule(); | 192 | int i; |
291 | 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]; | ||
292 | } | 200 | } |
293 | 201 | ||
294 | static int | 202 | static int |
295 | 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) |
296 | { | 204 | { |
297 | int rc = 0; | 205 | int rc; |
298 | 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 */ | ||
299 | const struct cred *saved_cred; | 210 | const struct cred *saved_cred; |
300 | struct cifs_sid *lsid; | ||
301 | struct cifs_sid_id *psidid, *npsidid; | ||
302 | struct rb_root *cidtree; | ||
303 | spinlock_t *cidlock; | ||
304 | |||
305 | if (sidtype == SIDOWNER) { | ||
306 | cidlock = &siduidlock; | ||
307 | cidtree = &uidtree; | ||
308 | } else if (sidtype == SIDGROUP) { | ||
309 | cidlock = &sidgidlock; | ||
310 | cidtree = &gidtree; | ||
311 | } else | ||
312 | return -EINVAL; | ||
313 | |||
314 | spin_lock(cidlock); | ||
315 | psidid = sid_rb_search(cidtree, cid); | ||
316 | |||
317 | if (!psidid) { /* node does not exist, allocate one & attempt adding */ | ||
318 | spin_unlock(cidlock); | ||
319 | npsidid = kzalloc(sizeof(struct cifs_sid_id), GFP_KERNEL); | ||
320 | if (!npsidid) | ||
321 | return -ENOMEM; | ||
322 | 211 | ||
323 | npsidid->sidstr = kmalloc(SIDLEN, GFP_KERNEL); | 212 | rc = snprintf(desc, sizeof(desc), "%ci:%u", |
324 | if (!npsidid->sidstr) { | 213 | sidtype == SIDOWNER ? 'o' : 'g', cid); |
325 | kfree(npsidid); | 214 | if (rc >= sizeof(desc)) |
326 | return -ENOMEM; | 215 | return -EINVAL; |
327 | } | ||
328 | 216 | ||
329 | spin_lock(cidlock); | 217 | rc = 0; |
330 | psidid = sid_rb_search(cidtree, cid); | 218 | saved_cred = override_creds(root_cred); |
331 | if (psidid) { /* node happened to get inserted meanwhile */ | 219 | sidkey = request_key(&cifs_idmap_key_type, desc, ""); |
332 | ++psidid->refcount; | 220 | if (IS_ERR(sidkey)) { |
333 | spin_unlock(cidlock); | 221 | rc = -EINVAL; |
334 | kfree(npsidid->sidstr); | 222 | cFYI(1, "%s: Can't map %cid %u to a SID", __func__, |
335 | kfree(npsidid); | 223 | sidtype == SIDOWNER ? 'u' : 'g', cid); |
336 | } else { | 224 | goto out_revert_creds; |
337 | psidid = npsidid; | 225 | } else if (sidkey->datalen < CIFS_SID_BASE_SIZE) { |
338 | sid_rb_insert(cidtree, cid, &psidid, | 226 | rc = -EIO; |
339 | sidtype == SIDOWNER ? "oi:" : "gi:"); | 227 | cFYI(1, "%s: Downcall contained malformed key " |
340 | ++psidid->refcount; | 228 | "(datalen=%hu)", __func__, sidkey->datalen); |
341 | spin_unlock(cidlock); | 229 | goto invalidate_key; |
342 | } | ||
343 | } else { | ||
344 | ++psidid->refcount; | ||
345 | spin_unlock(cidlock); | ||
346 | } | 230 | } |
347 | 231 | ||
348 | /* | 232 | /* |
349 | * 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 |
350 | * since a reference was taken earlier while holding the spinlock. | 234 | * there are no subauthorities and the host has 8-byte pointers, then |
351 | * A reference on the node is put without holding the spinlock | 235 | * it could be. |
352 | * and it is OK to do so in this case, shrinker will not erase | ||
353 | * this node until all references are put and we do not access | ||
354 | * any fields of the node after a reference is put . | ||
355 | */ | 236 | */ |
356 | if (test_bit(SID_ID_MAPPED, &psidid->state)) { | 237 | ksid = sidkey->datalen <= sizeof(sidkey->payload) ? |
357 | memcpy(ssid, &psidid->sid, sizeof(struct cifs_sid)); | 238 | (struct cifs_sid *)&sidkey->payload.value : |
358 | psidid->time = jiffies; /* update ts for accessing */ | 239 | (struct cifs_sid *)sidkey->payload.data; |
359 | goto id_sid_out; | 240 | |
360 | } | 241 | ksid_size = CIFS_SID_BASE_SIZE + (ksid->num_subauth * sizeof(__le32)); |
361 | 242 | if (ksid_size > sidkey->datalen) { | |
362 | if (time_after(psidid->time + SID_MAP_RETRY, jiffies)) { | 243 | rc = -EIO; |
363 | rc = -EINVAL; | 244 | cFYI(1, "%s: Downcall contained malformed key (datalen=%hu, " |
364 | goto id_sid_out; | 245 | "ksid_size=%u)", __func__, sidkey->datalen, ksid_size); |
246 | goto invalidate_key; | ||
365 | } | 247 | } |
366 | 248 | ||
367 | if (!test_and_set_bit(SID_ID_PENDING, &psidid->state)) { | 249 | cifs_copy_sid(ssid, ksid); |
368 | saved_cred = override_creds(root_cred); | 250 | out_key_put: |
369 | sidkey = request_key(&cifs_idmap_key_type, psidid->sidstr, ""); | 251 | key_put(sidkey); |
370 | if (IS_ERR(sidkey)) { | 252 | out_revert_creds: |
371 | rc = -EINVAL; | 253 | revert_creds(saved_cred); |
372 | cFYI(1, "%s: Can't map and id to a SID", __func__); | ||
373 | } else { | ||
374 | lsid = (struct cifs_sid *)sidkey->payload.data; | ||
375 | memcpy(&psidid->sid, lsid, | ||
376 | sidkey->datalen < sizeof(struct cifs_sid) ? | ||
377 | sidkey->datalen : sizeof(struct cifs_sid)); | ||
378 | memcpy(ssid, &psidid->sid, | ||
379 | sidkey->datalen < sizeof(struct cifs_sid) ? | ||
380 | sidkey->datalen : sizeof(struct cifs_sid)); | ||
381 | set_bit(SID_ID_MAPPED, &psidid->state); | ||
382 | key_put(sidkey); | ||
383 | kfree(psidid->sidstr); | ||
384 | } | ||
385 | psidid->time = jiffies; /* update ts for accessing */ | ||
386 | revert_creds(saved_cred); | ||
387 | clear_bit(SID_ID_PENDING, &psidid->state); | ||
388 | wake_up_bit(&psidid->state, SID_ID_PENDING); | ||
389 | } else { | ||
390 | rc = wait_on_bit(&psidid->state, SID_ID_PENDING, | ||
391 | sidid_pending_wait, TASK_INTERRUPTIBLE); | ||
392 | if (rc) { | ||
393 | cFYI(1, "%s: sidid_pending_wait interrupted %d", | ||
394 | __func__, rc); | ||
395 | --psidid->refcount; | ||
396 | return rc; | ||
397 | } | ||
398 | if (test_bit(SID_ID_MAPPED, &psidid->state)) | ||
399 | memcpy(ssid, &psidid->sid, sizeof(struct cifs_sid)); | ||
400 | else | ||
401 | rc = -EINVAL; | ||
402 | } | ||
403 | id_sid_out: | ||
404 | --psidid->refcount; | ||
405 | return rc; | 254 | return rc; |
255 | |||
256 | invalidate_key: | ||
257 | key_invalidate(sidkey); | ||
258 | goto out_key_put; | ||
406 | } | 259 | } |
407 | 260 | ||
408 | static int | 261 | static int |
@@ -410,111 +263,67 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid, | |||
410 | struct cifs_fattr *fattr, uint sidtype) | 263 | struct cifs_fattr *fattr, uint sidtype) |
411 | { | 264 | { |
412 | int rc; | 265 | int rc; |
413 | unsigned long cid; | 266 | struct key *sidkey; |
414 | struct key *idkey; | 267 | char *sidstr; |
415 | const struct cred *saved_cred; | 268 | const struct cred *saved_cred; |
416 | struct cifs_sid_id *psidid, *npsidid; | 269 | uid_t fuid = cifs_sb->mnt_uid; |
417 | struct rb_root *cidtree; | 270 | gid_t fgid = cifs_sb->mnt_gid; |
418 | spinlock_t *cidlock; | ||
419 | |||
420 | if (sidtype == SIDOWNER) { | ||
421 | cid = cifs_sb->mnt_uid; /* default uid, in case upcall fails */ | ||
422 | cidlock = &siduidlock; | ||
423 | cidtree = &uidtree; | ||
424 | } else if (sidtype == SIDGROUP) { | ||
425 | cid = cifs_sb->mnt_gid; /* default gid, in case upcall fails */ | ||
426 | cidlock = &sidgidlock; | ||
427 | cidtree = &gidtree; | ||
428 | } else | ||
429 | return -ENOENT; | ||
430 | |||
431 | spin_lock(cidlock); | ||
432 | psidid = id_rb_search(cidtree, psid); | ||
433 | |||
434 | if (!psidid) { /* node does not exist, allocate one & attempt adding */ | ||
435 | spin_unlock(cidlock); | ||
436 | npsidid = kzalloc(sizeof(struct cifs_sid_id), GFP_KERNEL); | ||
437 | if (!npsidid) | ||
438 | return -ENOMEM; | ||
439 | |||
440 | npsidid->sidstr = kmalloc(SIDLEN, GFP_KERNEL); | ||
441 | if (!npsidid->sidstr) { | ||
442 | kfree(npsidid); | ||
443 | return -ENOMEM; | ||
444 | } | ||
445 | |||
446 | spin_lock(cidlock); | ||
447 | psidid = id_rb_search(cidtree, psid); | ||
448 | if (psidid) { /* node happened to get inserted meanwhile */ | ||
449 | ++psidid->refcount; | ||
450 | spin_unlock(cidlock); | ||
451 | kfree(npsidid->sidstr); | ||
452 | kfree(npsidid); | ||
453 | } else { | ||
454 | psidid = npsidid; | ||
455 | id_rb_insert(cidtree, psid, &psidid, | ||
456 | sidtype == SIDOWNER ? "os:" : "gs:"); | ||
457 | ++psidid->refcount; | ||
458 | spin_unlock(cidlock); | ||
459 | } | ||
460 | } else { | ||
461 | ++psidid->refcount; | ||
462 | spin_unlock(cidlock); | ||
463 | } | ||
464 | 271 | ||
465 | /* | 272 | /* |
466 | * 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. |
467 | * since a reference was taken earlier while holding the spinlock. | 274 | * Just return an error. |
468 | * A reference on the node is put without holding the spinlock | ||
469 | * and it is OK to do so in this case, shrinker will not erase | ||
470 | * this node until all references are put and we do not access | ||
471 | * any fields of the node after a reference is put . | ||
472 | */ | 275 | */ |
473 | if (test_bit(SID_ID_MAPPED, &psidid->state)) { | 276 | if (unlikely(psid->num_subauth > SID_MAX_SUB_AUTHORITIES)) { |
474 | cid = psidid->id; | 277 | cFYI(1, "%s: %u subauthorities is too many!", __func__, |
475 | psidid->time = jiffies; /* update ts for accessing */ | 278 | psid->num_subauth); |
476 | goto sid_to_id_out; | 279 | return -EIO; |
477 | } | 280 | } |
478 | 281 | ||
479 | if (time_after(psidid->time + SID_MAP_RETRY, jiffies)) | 282 | sidstr = sid_to_key_str(psid, sidtype); |
480 | goto sid_to_id_out; | 283 | if (!sidstr) |
481 | 284 | return -ENOMEM; | |
482 | if (!test_and_set_bit(SID_ID_PENDING, &psidid->state)) { | 285 | |
483 | saved_cred = override_creds(root_cred); | 286 | saved_cred = override_creds(root_cred); |
484 | idkey = request_key(&cifs_idmap_key_type, psidid->sidstr, ""); | 287 | sidkey = request_key(&cifs_idmap_key_type, sidstr, ""); |
485 | if (IS_ERR(idkey)) | 288 | if (IS_ERR(sidkey)) { |
486 | cFYI(1, "%s: Can't map SID to an id", __func__); | 289 | rc = -EINVAL; |
487 | else { | 290 | cFYI(1, "%s: Can't map SID %s to a %cid", __func__, sidstr, |
488 | cid = *(unsigned long *)idkey->payload.value; | 291 | sidtype == SIDOWNER ? 'u' : 'g'); |
489 | psidid->id = cid; | 292 | goto out_revert_creds; |
490 | set_bit(SID_ID_MAPPED, &psidid->state); | 293 | } |
491 | key_put(idkey); | 294 | |
492 | kfree(psidid->sidstr); | 295 | /* |
493 | } | 296 | * FIXME: Here we assume that uid_t and gid_t are same size. It's |
494 | revert_creds(saved_cred); | 297 | * probably a safe assumption but might be better to check based on |
495 | psidid->time = jiffies; /* update ts for accessing */ | 298 | * sidtype. |
496 | clear_bit(SID_ID_PENDING, &psidid->state); | 299 | */ |
497 | wake_up_bit(&psidid->state, SID_ID_PENDING); | 300 | if (sidkey->datalen != sizeof(uid_t)) { |
498 | } else { | 301 | rc = -EIO; |
499 | rc = wait_on_bit(&psidid->state, SID_ID_PENDING, | 302 | cFYI(1, "%s: Downcall contained malformed key " |
500 | sidid_pending_wait, TASK_INTERRUPTIBLE); | 303 | "(datalen=%hu)", __func__, sidkey->datalen); |
501 | if (rc) { | 304 | key_invalidate(sidkey); |
502 | cFYI(1, "%s: sidid_pending_wait interrupted %d", | 305 | goto out_key_put; |
503 | __func__, rc); | ||
504 | --psidid->refcount; /* decremented without spinlock */ | ||
505 | return rc; | ||
506 | } | ||
507 | if (test_bit(SID_ID_MAPPED, &psidid->state)) | ||
508 | cid = psidid->id; | ||
509 | } | 306 | } |
510 | 307 | ||
511 | sid_to_id_out: | ||
512 | --psidid->refcount; /* decremented without spinlock */ | ||
513 | if (sidtype == SIDOWNER) | 308 | if (sidtype == SIDOWNER) |
514 | fattr->cf_uid = cid; | 309 | memcpy(&fuid, &sidkey->payload.value, sizeof(uid_t)); |
515 | else | 310 | else |
516 | 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); | ||
517 | 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; | ||
518 | return 0; | 327 | return 0; |
519 | } | 328 | } |
520 | 329 | ||
@@ -537,19 +346,15 @@ init_cifs_idmap(void) | |||
537 | if (!cred) | 346 | if (!cred) |
538 | return -ENOMEM; | 347 | return -ENOMEM; |
539 | 348 | ||
540 | keyring = key_alloc(&key_type_keyring, ".cifs_idmap", 0, 0, cred, | 349 | keyring = keyring_alloc(".cifs_idmap", 0, 0, cred, |
541 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | | 350 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | |
542 | KEY_USR_VIEW | KEY_USR_READ, | 351 | KEY_USR_VIEW | KEY_USR_READ, |
543 | KEY_ALLOC_NOT_IN_QUOTA); | 352 | KEY_ALLOC_NOT_IN_QUOTA, NULL); |
544 | if (IS_ERR(keyring)) { | 353 | if (IS_ERR(keyring)) { |
545 | ret = PTR_ERR(keyring); | 354 | ret = PTR_ERR(keyring); |
546 | goto failed_put_cred; | 355 | goto failed_put_cred; |
547 | } | 356 | } |
548 | 357 | ||
549 | ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL); | ||
550 | if (ret < 0) | ||
551 | goto failed_put_key; | ||
552 | |||
553 | ret = register_key_type(&cifs_idmap_key_type); | 358 | ret = register_key_type(&cifs_idmap_key_type); |
554 | if (ret < 0) | 359 | if (ret < 0) |
555 | goto failed_put_key; | 360 | goto failed_put_key; |
@@ -561,17 +366,6 @@ init_cifs_idmap(void) | |||
561 | cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; | 366 | cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; |
562 | root_cred = cred; | 367 | root_cred = cred; |
563 | 368 | ||
564 | spin_lock_init(&siduidlock); | ||
565 | uidtree = RB_ROOT; | ||
566 | spin_lock_init(&sidgidlock); | ||
567 | gidtree = RB_ROOT; | ||
568 | |||
569 | spin_lock_init(&uidsidlock); | ||
570 | siduidtree = RB_ROOT; | ||
571 | spin_lock_init(&gidsidlock); | ||
572 | sidgidtree = RB_ROOT; | ||
573 | register_shrinker(&cifs_shrinker); | ||
574 | |||
575 | cFYI(1, "cifs idmap keyring: %d", key_serial(keyring)); | 369 | cFYI(1, "cifs idmap keyring: %d", key_serial(keyring)); |
576 | return 0; | 370 | return 0; |
577 | 371 | ||
@@ -588,95 +382,13 @@ exit_cifs_idmap(void) | |||
588 | key_revoke(root_cred->thread_keyring); | 382 | key_revoke(root_cred->thread_keyring); |
589 | unregister_key_type(&cifs_idmap_key_type); | 383 | unregister_key_type(&cifs_idmap_key_type); |
590 | put_cred(root_cred); | 384 | put_cred(root_cred); |
591 | unregister_shrinker(&cifs_shrinker); | ||
592 | cFYI(1, "Unregistered %s key type", cifs_idmap_key_type.name); | 385 | cFYI(1, "Unregistered %s key type", cifs_idmap_key_type.name); |
593 | } | 386 | } |
594 | 387 | ||
595 | void | ||
596 | cifs_destroy_idmaptrees(void) | ||
597 | { | ||
598 | struct rb_root *root; | ||
599 | struct rb_node *node; | ||
600 | |||
601 | root = &uidtree; | ||
602 | spin_lock(&siduidlock); | ||
603 | while ((node = rb_first(root))) | ||
604 | rb_erase(node, root); | ||
605 | spin_unlock(&siduidlock); | ||
606 | |||
607 | root = &gidtree; | ||
608 | spin_lock(&sidgidlock); | ||
609 | while ((node = rb_first(root))) | ||
610 | rb_erase(node, root); | ||
611 | spin_unlock(&sidgidlock); | ||
612 | |||
613 | root = &siduidtree; | ||
614 | spin_lock(&uidsidlock); | ||
615 | while ((node = rb_first(root))) | ||
616 | rb_erase(node, root); | ||
617 | spin_unlock(&uidsidlock); | ||
618 | |||
619 | root = &sidgidtree; | ||
620 | spin_lock(&gidsidlock); | ||
621 | while ((node = rb_first(root))) | ||
622 | rb_erase(node, root); | ||
623 | spin_unlock(&gidsidlock); | ||
624 | } | ||
625 | |||
626 | /* if the two SIDs (roughly equivalent to a UUID for a user or group) are | ||
627 | the same returns 1, if they do not match returns 0 */ | ||
628 | int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid) | ||
629 | { | ||
630 | int i; | ||
631 | int num_subauth, num_sat, num_saw; | ||
632 | |||
633 | if ((!ctsid) || (!cwsid)) | ||
634 | return 1; | ||
635 | |||
636 | /* compare the revision */ | ||
637 | if (ctsid->revision != cwsid->revision) { | ||
638 | if (ctsid->revision > cwsid->revision) | ||
639 | return 1; | ||
640 | else | ||
641 | return -1; | ||
642 | } | ||
643 | |||
644 | /* compare all of the six auth values */ | ||
645 | for (i = 0; i < 6; ++i) { | ||
646 | if (ctsid->authority[i] != cwsid->authority[i]) { | ||
647 | if (ctsid->authority[i] > cwsid->authority[i]) | ||
648 | return 1; | ||
649 | else | ||
650 | return -1; | ||
651 | } | ||
652 | } | ||
653 | |||
654 | /* compare all of the subauth values if any */ | ||
655 | num_sat = ctsid->num_subauth; | ||
656 | num_saw = cwsid->num_subauth; | ||
657 | num_subauth = num_sat < num_saw ? num_sat : num_saw; | ||
658 | if (num_subauth) { | ||
659 | for (i = 0; i < num_subauth; ++i) { | ||
660 | if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) { | ||
661 | if (le32_to_cpu(ctsid->sub_auth[i]) > | ||
662 | le32_to_cpu(cwsid->sub_auth[i])) | ||
663 | return 1; | ||
664 | else | ||
665 | return -1; | ||
666 | } | ||
667 | } | ||
668 | } | ||
669 | |||
670 | return 0; /* sids compare/match */ | ||
671 | } | ||
672 | |||
673 | |||
674 | /* copy ntsd, owner sid, and group sid from a security descriptor to another */ | 388 | /* copy ntsd, owner sid, and group sid from a security descriptor to another */ |
675 | static void copy_sec_desc(const struct cifs_ntsd *pntsd, | 389 | static void copy_sec_desc(const struct cifs_ntsd *pntsd, |
676 | struct cifs_ntsd *pnntsd, __u32 sidsoffset) | 390 | struct cifs_ntsd *pnntsd, __u32 sidsoffset) |
677 | { | 391 | { |
678 | int i; | ||
679 | |||
680 | struct cifs_sid *owner_sid_ptr, *group_sid_ptr; | 392 | struct cifs_sid *owner_sid_ptr, *group_sid_ptr; |
681 | struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr; | 393 | struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr; |
682 | 394 | ||
@@ -692,26 +404,14 @@ static void copy_sec_desc(const struct cifs_ntsd *pntsd, | |||
692 | owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + | 404 | owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + |
693 | le32_to_cpu(pntsd->osidoffset)); | 405 | le32_to_cpu(pntsd->osidoffset)); |
694 | nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset); | 406 | nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset); |
695 | 407 | cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr); | |
696 | nowner_sid_ptr->revision = owner_sid_ptr->revision; | ||
697 | nowner_sid_ptr->num_subauth = owner_sid_ptr->num_subauth; | ||
698 | for (i = 0; i < 6; i++) | ||
699 | nowner_sid_ptr->authority[i] = owner_sid_ptr->authority[i]; | ||
700 | for (i = 0; i < 5; i++) | ||
701 | nowner_sid_ptr->sub_auth[i] = owner_sid_ptr->sub_auth[i]; | ||
702 | 408 | ||
703 | /* copy group sid */ | 409 | /* copy group sid */ |
704 | group_sid_ptr = (struct cifs_sid *)((char *)pntsd + | 410 | group_sid_ptr = (struct cifs_sid *)((char *)pntsd + |
705 | le32_to_cpu(pntsd->gsidoffset)); | 411 | le32_to_cpu(pntsd->gsidoffset)); |
706 | ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset + | 412 | ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset + |
707 | sizeof(struct cifs_sid)); | 413 | sizeof(struct cifs_sid)); |
708 | 414 | cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr); | |
709 | ngroup_sid_ptr->revision = group_sid_ptr->revision; | ||
710 | ngroup_sid_ptr->num_subauth = group_sid_ptr->num_subauth; | ||
711 | for (i = 0; i < 6; i++) | ||
712 | ngroup_sid_ptr->authority[i] = group_sid_ptr->authority[i]; | ||
713 | for (i = 0; i < 5; i++) | ||
714 | ngroup_sid_ptr->sub_auth[i] = group_sid_ptr->sub_auth[i]; | ||
715 | 415 | ||
716 | return; | 416 | return; |
717 | } | 417 | } |
@@ -818,7 +518,7 @@ static __u16 fill_ace_for_sid(struct cifs_ace *pntace, | |||
818 | 518 | ||
819 | pntace->sid.revision = psid->revision; | 519 | pntace->sid.revision = psid->revision; |
820 | pntace->sid.num_subauth = psid->num_subauth; | 520 | pntace->sid.num_subauth = psid->num_subauth; |
821 | for (i = 0; i < 6; i++) | 521 | for (i = 0; i < NUM_AUTHS; i++) |
822 | pntace->sid.authority[i] = psid->authority[i]; | 522 | pntace->sid.authority[i] = psid->authority[i]; |
823 | for (i = 0; i < psid->num_subauth; i++) | 523 | for (i = 0; i < psid->num_subauth; i++) |
824 | pntace->sid.sub_auth[i] = psid->sub_auth[i]; | 524 | pntace->sid.sub_auth[i] = psid->sub_auth[i]; |
@@ -994,8 +694,8 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl) | |||
994 | return -EINVAL; | 694 | return -EINVAL; |
995 | } | 695 | } |
996 | 696 | ||
997 | if (psid->num_subauth) { | ||
998 | #ifdef CONFIG_CIFS_DEBUG2 | 697 | #ifdef CONFIG_CIFS_DEBUG2 |
698 | if (psid->num_subauth) { | ||
999 | int i; | 699 | int i; |
1000 | cFYI(1, "SID revision %d num_auth %d", | 700 | cFYI(1, "SID revision %d num_auth %d", |
1001 | psid->revision, psid->num_subauth); | 701 | psid->revision, psid->num_subauth); |
@@ -1009,8 +709,8 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl) | |||
1009 | num auths and therefore go off the end */ | 709 | num auths and therefore go off the end */ |
1010 | cFYI(1, "RID 0x%x", | 710 | cFYI(1, "RID 0x%x", |
1011 | le32_to_cpu(psid->sub_auth[psid->num_subauth-1])); | 711 | le32_to_cpu(psid->sub_auth[psid->num_subauth-1])); |
1012 | #endif | ||
1013 | } | 712 | } |
713 | #endif | ||
1014 | 714 | ||
1015 | return 0; | 715 | return 0; |
1016 | } | 716 | } |
@@ -1120,8 +820,7 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, | |||
1120 | kfree(nowner_sid_ptr); | 820 | kfree(nowner_sid_ptr); |
1121 | return rc; | 821 | return rc; |
1122 | } | 822 | } |
1123 | memcpy(owner_sid_ptr, nowner_sid_ptr, | 823 | cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr); |
1124 | sizeof(struct cifs_sid)); | ||
1125 | kfree(nowner_sid_ptr); | 824 | kfree(nowner_sid_ptr); |
1126 | *aclflag = CIFS_ACL_OWNER; | 825 | *aclflag = CIFS_ACL_OWNER; |
1127 | } | 826 | } |
@@ -1139,8 +838,7 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, | |||
1139 | kfree(ngroup_sid_ptr); | 838 | kfree(ngroup_sid_ptr); |
1140 | return rc; | 839 | return rc; |
1141 | } | 840 | } |
1142 | memcpy(group_sid_ptr, ngroup_sid_ptr, | 841 | cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr); |
1143 | sizeof(struct cifs_sid)); | ||
1144 | kfree(ngroup_sid_ptr); | 842 | kfree(ngroup_sid_ptr); |
1145 | *aclflag = CIFS_ACL_GROUP; | 843 | *aclflag = CIFS_ACL_GROUP; |
1146 | } | 844 | } |
@@ -1316,42 +1014,39 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode, | |||
1316 | 1014 | ||
1317 | /* Get the security descriptor */ | 1015 | /* Get the security descriptor */ |
1318 | pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen); | 1016 | pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen); |
1319 | |||
1320 | /* Add three ACEs for owner, group, everyone getting rid of | ||
1321 | other ACEs as chmod disables ACEs and set the security descriptor */ | ||
1322 | |||
1323 | if (IS_ERR(pntsd)) { | 1017 | if (IS_ERR(pntsd)) { |
1324 | rc = PTR_ERR(pntsd); | 1018 | rc = PTR_ERR(pntsd); |
1325 | cERROR(1, "%s: error %d getting sec desc", __func__, rc); | 1019 | cERROR(1, "%s: error %d getting sec desc", __func__, rc); |
1326 | } else { | 1020 | goto out; |
1327 | /* allocate memory for the smb header, | 1021 | } |
1328 | set security descriptor request security descriptor | ||
1329 | parameters, and secuirty descriptor itself */ | ||
1330 | |||
1331 | secdesclen = secdesclen < DEFSECDESCLEN ? | ||
1332 | DEFSECDESCLEN : secdesclen; | ||
1333 | pnntsd = kmalloc(secdesclen, GFP_KERNEL); | ||
1334 | if (!pnntsd) { | ||
1335 | cERROR(1, "Unable to allocate security descriptor"); | ||
1336 | kfree(pntsd); | ||
1337 | return -ENOMEM; | ||
1338 | } | ||
1339 | 1022 | ||
1340 | rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid, | 1023 | /* |
1341 | &aclflag); | 1024 | * Add three ACEs for owner, group, everyone getting rid of other ACEs |
1025 | * as chmod disables ACEs and set the security descriptor. Allocate | ||
1026 | * memory for the smb header, set security descriptor request security | ||
1027 | * descriptor parameters, and secuirty descriptor itself | ||
1028 | */ | ||
1029 | secdesclen = max_t(u32, secdesclen, DEFAULT_SEC_DESC_LEN); | ||
1030 | pnntsd = kmalloc(secdesclen, GFP_KERNEL); | ||
1031 | if (!pnntsd) { | ||
1032 | cERROR(1, "Unable to allocate security descriptor"); | ||
1033 | kfree(pntsd); | ||
1034 | return -ENOMEM; | ||
1035 | } | ||
1342 | 1036 | ||
1343 | cFYI(DBG2, "build_sec_desc rc: %d", rc); | 1037 | rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid, |
1038 | &aclflag); | ||
1344 | 1039 | ||
1345 | if (!rc) { | 1040 | cFYI(DBG2, "build_sec_desc rc: %d", rc); |
1346 | /* Set the security descriptor */ | ||
1347 | rc = set_cifs_acl(pnntsd, secdesclen, inode, | ||
1348 | path, aclflag); | ||
1349 | cFYI(DBG2, "set_cifs_acl rc: %d", rc); | ||
1350 | } | ||
1351 | 1041 | ||
1352 | kfree(pnntsd); | 1042 | if (!rc) { |
1353 | kfree(pntsd); | 1043 | /* Set the security descriptor */ |
1044 | rc = set_cifs_acl(pnntsd, secdesclen, inode, path, aclflag); | ||
1045 | cFYI(DBG2, "set_cifs_acl rc: %d", rc); | ||
1354 | } | 1046 | } |
1355 | 1047 | ||
1048 | kfree(pnntsd); | ||
1049 | kfree(pntsd); | ||
1050 | out: | ||
1356 | return rc; | 1051 | return rc; |
1357 | } | 1052 | } |
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..de7f9168a118 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -54,7 +54,6 @@ | |||
54 | #endif | 54 | #endif |
55 | 55 | ||
56 | int cifsFYI = 0; | 56 | int cifsFYI = 0; |
57 | int cifsERROR = 1; | ||
58 | int traceSMB = 0; | 57 | int traceSMB = 0; |
59 | bool enable_oplocks = true; | 58 | bool enable_oplocks = true; |
60 | unsigned int linuxExtEnabled = 1; | 59 | unsigned int linuxExtEnabled = 1; |
@@ -64,24 +63,23 @@ unsigned int global_secflags = CIFSSEC_DEF; | |||
64 | unsigned int sign_CIFS_PDUs = 1; | 63 | unsigned int sign_CIFS_PDUs = 1; |
65 | static const struct super_operations cifs_super_ops; | 64 | static const struct super_operations cifs_super_ops; |
66 | unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; | 65 | unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; |
67 | module_param(CIFSMaxBufSize, int, 0); | 66 | module_param(CIFSMaxBufSize, uint, 0); |
68 | MODULE_PARM_DESC(CIFSMaxBufSize, "Network buffer size (not including header). " | 67 | MODULE_PARM_DESC(CIFSMaxBufSize, "Network buffer size (not including header). " |
69 | "Default: 16384 Range: 8192 to 130048"); | 68 | "Default: 16384 Range: 8192 to 130048"); |
70 | unsigned int cifs_min_rcv = CIFS_MIN_RCV_POOL; | 69 | unsigned int cifs_min_rcv = CIFS_MIN_RCV_POOL; |
71 | module_param(cifs_min_rcv, int, 0); | 70 | module_param(cifs_min_rcv, uint, 0); |
72 | MODULE_PARM_DESC(cifs_min_rcv, "Network buffers in pool. Default: 4 Range: " | 71 | MODULE_PARM_DESC(cifs_min_rcv, "Network buffers in pool. Default: 4 Range: " |
73 | "1 to 64"); | 72 | "1 to 64"); |
74 | unsigned int cifs_min_small = 30; | 73 | unsigned int cifs_min_small = 30; |
75 | module_param(cifs_min_small, int, 0); | 74 | module_param(cifs_min_small, uint, 0); |
76 | MODULE_PARM_DESC(cifs_min_small, "Small network buffers in pool. Default: 30 " | 75 | MODULE_PARM_DESC(cifs_min_small, "Small network buffers in pool. Default: 30 " |
77 | "Range: 2 to 256"); | 76 | "Range: 2 to 256"); |
78 | unsigned int cifs_max_pending = CIFS_MAX_REQ; | 77 | unsigned int cifs_max_pending = CIFS_MAX_REQ; |
79 | module_param(cifs_max_pending, int, 0444); | 78 | module_param(cifs_max_pending, uint, 0444); |
80 | MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. " | 79 | MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. " |
81 | "Default: 32767 Range: 2 to 32767."); | 80 | "Default: 32767 Range: 2 to 32767."); |
82 | module_param(enable_oplocks, bool, 0644); | 81 | module_param(enable_oplocks, bool, 0644); |
83 | MODULE_PARM_DESC(enable_oplocks, "Enable or disable oplocks (bool). Default:" | 82 | MODULE_PARM_DESC(enable_oplocks, "Enable or disable oplocks. Default: y/Y/1"); |
84 | "y/Y/1"); | ||
85 | 83 | ||
86 | extern mempool_t *cifs_sm_req_poolp; | 84 | extern mempool_t *cifs_sm_req_poolp; |
87 | extern mempool_t *cifs_req_poolp; | 85 | extern mempool_t *cifs_req_poolp; |
@@ -540,8 +538,8 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb) | |||
540 | char *s, *p; | 538 | char *s, *p; |
541 | char sep; | 539 | char sep; |
542 | 540 | ||
543 | full_path = build_path_to_root(vol, cifs_sb, | 541 | full_path = cifs_build_path_to_root(vol, cifs_sb, |
544 | cifs_sb_master_tcon(cifs_sb)); | 542 | cifs_sb_master_tcon(cifs_sb)); |
545 | if (full_path == NULL) | 543 | if (full_path == NULL) |
546 | return ERR_PTR(-ENOMEM); | 544 | return ERR_PTR(-ENOMEM); |
547 | 545 | ||
@@ -695,13 +693,13 @@ static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
695 | return written; | 693 | return written; |
696 | } | 694 | } |
697 | 695 | ||
698 | static loff_t cifs_llseek(struct file *file, loff_t offset, int origin) | 696 | static loff_t cifs_llseek(struct file *file, loff_t offset, int whence) |
699 | { | 697 | { |
700 | /* | 698 | /* |
701 | * origin == SEEK_END || SEEK_DATA || SEEK_HOLE => we must revalidate | 699 | * whence == SEEK_END || SEEK_DATA || SEEK_HOLE => we must revalidate |
702 | * the cached file length | 700 | * the cached file length |
703 | */ | 701 | */ |
704 | if (origin != SEEK_SET && origin != SEEK_CUR) { | 702 | if (whence != SEEK_SET && whence != SEEK_CUR) { |
705 | int rc; | 703 | int rc; |
706 | struct inode *inode = file->f_path.dentry->d_inode; | 704 | struct inode *inode = file->f_path.dentry->d_inode; |
707 | 705 | ||
@@ -728,7 +726,7 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int origin) | |||
728 | if (rc < 0) | 726 | if (rc < 0) |
729 | return (loff_t)rc; | 727 | return (loff_t)rc; |
730 | } | 728 | } |
731 | return generic_file_llseek(file, offset, origin); | 729 | return generic_file_llseek(file, offset, whence); |
732 | } | 730 | } |
733 | 731 | ||
734 | static int cifs_setlease(struct file *file, long arg, struct file_lock **lease) | 732 | static int cifs_setlease(struct file *file, long arg, struct file_lock **lease) |
@@ -1205,7 +1203,6 @@ exit_cifs(void) | |||
1205 | unregister_filesystem(&cifs_fs_type); | 1203 | unregister_filesystem(&cifs_fs_type); |
1206 | cifs_dfs_release_automount_timer(); | 1204 | cifs_dfs_release_automount_timer(); |
1207 | #ifdef CONFIG_CIFS_ACL | 1205 | #ifdef CONFIG_CIFS_ACL |
1208 | cifs_destroy_idmaptrees(); | ||
1209 | exit_cifs_idmap(); | 1206 | exit_cifs_idmap(); |
1210 | #endif | 1207 | #endif |
1211 | #ifdef CONFIG_CIFS_UPCALL | 1208 | #ifdef CONFIG_CIFS_UPCALL |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index f5af2527fc69..e6899cea1c35 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 { |
@@ -386,6 +386,7 @@ struct smb_version_values { | |||
386 | unsigned int cap_unix; | 386 | unsigned int cap_unix; |
387 | unsigned int cap_nt_find; | 387 | unsigned int cap_nt_find; |
388 | unsigned int cap_large_files; | 388 | unsigned int cap_large_files; |
389 | unsigned int oplock_read; | ||
389 | }; | 390 | }; |
390 | 391 | ||
391 | #define HEADER_SIZE(server) (server->vals->header_size) | 392 | #define HEADER_SIZE(server) (server->vals->header_size) |
@@ -396,7 +397,6 @@ struct smb_vol { | |||
396 | char *password; | 397 | char *password; |
397 | char *domainname; | 398 | char *domainname; |
398 | char *UNC; | 399 | char *UNC; |
399 | char *UNCip; | ||
400 | char *iocharset; /* local code page for mapping to and from Unicode */ | 400 | char *iocharset; /* local code page for mapping to and from Unicode */ |
401 | char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */ | 401 | 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 */ | 402 | char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */ |
@@ -444,11 +444,11 @@ struct smb_vol { | |||
444 | unsigned int rsize; | 444 | unsigned int rsize; |
445 | unsigned int wsize; | 445 | unsigned int wsize; |
446 | bool sockopt_tcp_nodelay:1; | 446 | bool sockopt_tcp_nodelay:1; |
447 | unsigned short int port; | ||
448 | unsigned long actimeo; /* attribute cache timeout (jiffies) */ | 447 | unsigned long actimeo; /* attribute cache timeout (jiffies) */ |
449 | struct smb_version_operations *ops; | 448 | struct smb_version_operations *ops; |
450 | struct smb_version_values *vals; | 449 | struct smb_version_values *vals; |
451 | char *prepath; | 450 | char *prepath; |
451 | struct sockaddr_storage dstaddr; /* destination address */ | ||
452 | struct sockaddr_storage srcaddr; /* allow binding to a local IP */ | 452 | struct sockaddr_storage srcaddr; /* allow binding to a local IP */ |
453 | struct nls_table *local_nls; | 453 | struct nls_table *local_nls; |
454 | }; | 454 | }; |
@@ -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..12b3da39733b 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,45 @@ 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) | ||
1563 | goto out_nomem; | 1628 | goto out_nomem; |
1564 | 1629 | ||
1565 | temp_len = strnlen(string, 300); | 1630 | convert_delimiter(vol->UNC, '\\'); |
1566 | if (temp_len == 300) { | 1631 | if (vol->UNC[0] != '\\' || vol->UNC[1] != '\\') { |
1567 | printk(KERN_WARNING "CIFS: UNC name too long\n"); | 1632 | printk(KERN_ERR "CIFS: UNC Path does not " |
1568 | goto cifs_parse_mount_err; | 1633 | "begin with // or \\\\\n"); |
1569 | } | ||
1570 | |||
1571 | vol->UNC = kmalloc(temp_len+1, GFP_KERNEL); | ||
1572 | if (vol->UNC == NULL) { | ||
1573 | printk(KERN_WARNING "CIFS: no memory for UNC\n"); | ||
1574 | goto cifs_parse_mount_err; | ||
1575 | } | ||
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; | 1634 | goto cifs_parse_mount_err; |
1585 | } | 1635 | } |
1586 | 1636 | ||
1637 | /* Compare old unc= option to new one */ | ||
1638 | if (!string || strcmp(string, vol->UNC)) | ||
1639 | printk(KERN_WARNING "CIFS: the value of the " | ||
1640 | "unc= mount option does not match the " | ||
1641 | "device string. Using the unc= option " | ||
1642 | "for now. In 3.10, that option will " | ||
1643 | "be ignored and the contents of the " | ||
1644 | "device string will be used " | ||
1645 | "instead. (%s != %s)\n", string, | ||
1646 | vol->UNC); | ||
1587 | break; | 1647 | break; |
1588 | case Opt_domain: | 1648 | case Opt_domain: |
1589 | string = match_strdup(args); | 1649 | string = match_strdup(args); |
@@ -1618,31 +1678,24 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1618 | } | 1678 | } |
1619 | break; | 1679 | break; |
1620 | case Opt_prefixpath: | 1680 | case Opt_prefixpath: |
1621 | string = match_strdup(args); | 1681 | /* skip over any leading delimiter */ |
1622 | if (string == NULL) | 1682 | if (*args[0].from == '/' || *args[0].from == '\\') |
1623 | goto out_nomem; | 1683 | 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 | |||
1633 | vol->prepath = kmalloc(temp_len+1, GFP_KERNEL); | ||
1634 | if (vol->prepath == NULL) { | ||
1635 | printk(KERN_WARNING "CIFS: no memory " | ||
1636 | "for path prefix\n"); | ||
1637 | goto cifs_parse_mount_err; | ||
1638 | } | ||
1639 | |||
1640 | if (string[0] != '/') { | ||
1641 | vol->prepath[0] = '/'; | ||
1642 | strcpy(vol->prepath+1, string); | ||
1643 | } else | ||
1644 | strcpy(vol->prepath, string); | ||
1645 | 1684 | ||
1685 | string = vol->prepath; | ||
1686 | vol->prepath = match_strdup(args); | ||
1687 | if (vol->prepath == NULL) | ||
1688 | goto out_nomem; | ||
1689 | /* Compare old prefixpath= option to new one */ | ||
1690 | if (!string || strcmp(string, vol->prepath)) | ||
1691 | printk(KERN_WARNING "CIFS: the value of the " | ||
1692 | "prefixpath= mount option does not " | ||
1693 | "match the device string. Using the " | ||
1694 | "prefixpath= option for now. In 3.10, " | ||
1695 | "that option will be ignored and the " | ||
1696 | "contents of the device string will be " | ||
1697 | "used instead.(%s != %s)\n", string, | ||
1698 | vol->prepath); | ||
1646 | break; | 1699 | break; |
1647 | case Opt_iocharset: | 1700 | case Opt_iocharset: |
1648 | string = match_strdup(args); | 1701 | string = match_strdup(args); |
@@ -1799,9 +1852,30 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1799 | goto cifs_parse_mount_err; | 1852 | goto cifs_parse_mount_err; |
1800 | } | 1853 | } |
1801 | #endif | 1854 | #endif |
1855 | if (!vol->UNC) { | ||
1856 | cERROR(1, "CIFS mount error: No usable UNC path provided in " | ||
1857 | "device string or in unc= option!"); | ||
1858 | goto cifs_parse_mount_err; | ||
1859 | } | ||
1802 | 1860 | ||
1803 | if (vol->UNCip == NULL) | 1861 | /* make sure UNC has a share name */ |
1804 | vol->UNCip = &vol->UNC[2]; | 1862 | if (!strchr(vol->UNC + 3, '\\')) { |
1863 | cERROR(1, "Malformed UNC. Unable to find share name."); | ||
1864 | goto cifs_parse_mount_err; | ||
1865 | } | ||
1866 | |||
1867 | if (!got_ip) { | ||
1868 | /* No ip= option specified? Try to get it from UNC */ | ||
1869 | if (!cifs_convert_address(dstaddr, &vol->UNC[2], | ||
1870 | strlen(&vol->UNC[2]))) { | ||
1871 | printk(KERN_ERR "Unable to determine destination " | ||
1872 | "address.\n"); | ||
1873 | goto cifs_parse_mount_err; | ||
1874 | } | ||
1875 | } | ||
1876 | |||
1877 | /* set the port that we got earlier */ | ||
1878 | cifs_set_port(dstaddr, port); | ||
1805 | 1879 | ||
1806 | if (uid_specified) | 1880 | if (uid_specified) |
1807 | vol->override_uid = override_uid; | 1881 | vol->override_uid = override_uid; |
@@ -1843,7 +1917,7 @@ srcip_matches(struct sockaddr *srcaddr, struct sockaddr *rhs) | |||
1843 | } | 1917 | } |
1844 | case AF_INET6: { | 1918 | case AF_INET6: { |
1845 | struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)srcaddr; | 1919 | struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)srcaddr; |
1846 | struct sockaddr_in6 *vaddr6 = (struct sockaddr_in6 *)&rhs; | 1920 | struct sockaddr_in6 *vaddr6 = (struct sockaddr_in6 *)rhs; |
1847 | return ipv6_addr_equal(&saddr6->sin6_addr, &vaddr6->sin6_addr); | 1921 | return ipv6_addr_equal(&saddr6->sin6_addr, &vaddr6->sin6_addr); |
1848 | } | 1922 | } |
1849 | default: | 1923 | default: |
@@ -1972,9 +2046,10 @@ match_security(struct TCP_Server_Info *server, struct smb_vol *vol) | |||
1972 | return true; | 2046 | return true; |
1973 | } | 2047 | } |
1974 | 2048 | ||
1975 | static int match_server(struct TCP_Server_Info *server, struct sockaddr *addr, | 2049 | static int match_server(struct TCP_Server_Info *server, struct smb_vol *vol) |
1976 | struct smb_vol *vol) | ||
1977 | { | 2050 | { |
2051 | struct sockaddr *addr = (struct sockaddr *)&vol->dstaddr; | ||
2052 | |||
1978 | if ((server->vals != vol->vals) || (server->ops != vol->ops)) | 2053 | if ((server->vals != vol->vals) || (server->ops != vol->ops)) |
1979 | return 0; | 2054 | return 0; |
1980 | 2055 | ||
@@ -1995,13 +2070,13 @@ static int match_server(struct TCP_Server_Info *server, struct sockaddr *addr, | |||
1995 | } | 2070 | } |
1996 | 2071 | ||
1997 | static struct TCP_Server_Info * | 2072 | static struct TCP_Server_Info * |
1998 | cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol) | 2073 | cifs_find_tcp_session(struct smb_vol *vol) |
1999 | { | 2074 | { |
2000 | struct TCP_Server_Info *server; | 2075 | struct TCP_Server_Info *server; |
2001 | 2076 | ||
2002 | spin_lock(&cifs_tcp_ses_lock); | 2077 | spin_lock(&cifs_tcp_ses_lock); |
2003 | list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { | 2078 | list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { |
2004 | if (!match_server(server, addr, vol)) | 2079 | if (!match_server(server, vol)) |
2005 | continue; | 2080 | continue; |
2006 | 2081 | ||
2007 | ++server->srv_count; | 2082 | ++server->srv_count; |
@@ -2051,40 +2126,12 @@ static struct TCP_Server_Info * | |||
2051 | cifs_get_tcp_session(struct smb_vol *volume_info) | 2126 | cifs_get_tcp_session(struct smb_vol *volume_info) |
2052 | { | 2127 | { |
2053 | struct TCP_Server_Info *tcp_ses = NULL; | 2128 | 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; | 2129 | int rc; |
2058 | 2130 | ||
2059 | memset(&addr, 0, sizeof(struct sockaddr_storage)); | 2131 | 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 | 2132 | ||
2086 | /* see if we already have a matching tcp_ses */ | 2133 | /* see if we already have a matching tcp_ses */ |
2087 | tcp_ses = cifs_find_tcp_session((struct sockaddr *)&addr, volume_info); | 2134 | tcp_ses = cifs_find_tcp_session(volume_info); |
2088 | if (tcp_ses) | 2135 | if (tcp_ses) |
2089 | return tcp_ses; | 2136 | return tcp_ses; |
2090 | 2137 | ||
@@ -2129,27 +2176,18 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
2129 | INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); | 2176 | INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); |
2130 | INIT_LIST_HEAD(&tcp_ses->smb_ses_list); | 2177 | INIT_LIST_HEAD(&tcp_ses->smb_ses_list); |
2131 | INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request); | 2178 | INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request); |
2132 | 2179 | memcpy(&tcp_ses->srcaddr, &volume_info->srcaddr, | |
2180 | sizeof(tcp_ses->srcaddr)); | ||
2181 | memcpy(&tcp_ses->dstaddr, &volume_info->dstaddr, | ||
2182 | sizeof(tcp_ses->dstaddr)); | ||
2133 | /* | 2183 | /* |
2134 | * at this point we are the only ones with the pointer | 2184 | * at this point we are the only ones with the pointer |
2135 | * to the struct since the kernel thread not created yet | 2185 | * to the struct since the kernel thread not created yet |
2136 | * no need to spinlock this init of tcpStatus or srv_count | 2186 | * no need to spinlock this init of tcpStatus or srv_count |
2137 | */ | 2187 | */ |
2138 | tcp_ses->tcpStatus = CifsNew; | 2188 | tcp_ses->tcpStatus = CifsNew; |
2139 | memcpy(&tcp_ses->srcaddr, &volume_info->srcaddr, | ||
2140 | sizeof(tcp_ses->srcaddr)); | ||
2141 | ++tcp_ses->srv_count; | 2189 | ++tcp_ses->srv_count; |
2142 | 2190 | ||
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); | 2191 | rc = ip_connect(tcp_ses); |
2154 | if (rc < 0) { | 2192 | if (rc < 0) { |
2155 | cERROR(1, "Error connecting to socket. Aborting operation"); | 2193 | cERROR(1, "Error connecting to socket. Aborting operation"); |
@@ -2397,8 +2435,6 @@ cifs_set_cifscreds(struct smb_vol *vol __attribute__((unused)), | |||
2397 | } | 2435 | } |
2398 | #endif /* CONFIG_KEYS */ | 2436 | #endif /* CONFIG_KEYS */ |
2399 | 2437 | ||
2400 | static bool warned_on_ntlm; /* globals init to false automatically */ | ||
2401 | |||
2402 | static struct cifs_ses * | 2438 | static struct cifs_ses * |
2403 | cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | 2439 | cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) |
2404 | { | 2440 | { |
@@ -2475,14 +2511,6 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | |||
2475 | ses->cred_uid = volume_info->cred_uid; | 2511 | ses->cred_uid = volume_info->cred_uid; |
2476 | ses->linux_uid = volume_info->linux_uid; | 2512 | ses->linux_uid = volume_info->linux_uid; |
2477 | 2513 | ||
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; | 2514 | ses->overrideSecFlg = volume_info->secFlg; |
2487 | 2515 | ||
2488 | mutex_lock(&ses->session_mutex); | 2516 | mutex_lock(&ses->session_mutex); |
@@ -2598,13 +2626,6 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) | |||
2598 | } | 2626 | } |
2599 | } | 2627 | } |
2600 | 2628 | ||
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 | /* | 2629 | /* |
2609 | * BB Do we need to wrap session_mutex around this TCon call and Unix | 2630 | * BB Do we need to wrap session_mutex around this TCon call and Unix |
2610 | * SetFS as we do on SessSetup and reconnect? | 2631 | * SetFS as we do on SessSetup and reconnect? |
@@ -2718,11 +2739,8 @@ cifs_match_super(struct super_block *sb, void *data) | |||
2718 | struct cifs_ses *ses; | 2739 | struct cifs_ses *ses; |
2719 | struct cifs_tcon *tcon; | 2740 | struct cifs_tcon *tcon; |
2720 | struct tcon_link *tlink; | 2741 | struct tcon_link *tlink; |
2721 | struct sockaddr_storage addr; | ||
2722 | int rc = 0; | 2742 | int rc = 0; |
2723 | 2743 | ||
2724 | memset(&addr, 0, sizeof(struct sockaddr_storage)); | ||
2725 | |||
2726 | spin_lock(&cifs_tcp_ses_lock); | 2744 | spin_lock(&cifs_tcp_ses_lock); |
2727 | cifs_sb = CIFS_SB(sb); | 2745 | cifs_sb = CIFS_SB(sb); |
2728 | tlink = cifs_get_tlink(cifs_sb_master_tlink(cifs_sb)); | 2746 | tlink = cifs_get_tlink(cifs_sb_master_tlink(cifs_sb)); |
@@ -2736,17 +2754,7 @@ cifs_match_super(struct super_block *sb, void *data) | |||
2736 | 2754 | ||
2737 | volume_info = mnt_data->vol; | 2755 | volume_info = mnt_data->vol; |
2738 | 2756 | ||
2739 | if (!volume_info->UNCip || !volume_info->UNC) | 2757 | 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) || | 2758 | !match_session(ses, volume_info) || |
2751 | !match_tcon(tcon, volume_info->UNC)) { | 2759 | !match_tcon(tcon, volume_info->UNC)) { |
2752 | rc = 0; | 2760 | rc = 0; |
@@ -3261,8 +3269,6 @@ cleanup_volume_info_contents(struct smb_vol *volume_info) | |||
3261 | { | 3269 | { |
3262 | kfree(volume_info->username); | 3270 | kfree(volume_info->username); |
3263 | kzfree(volume_info->password); | 3271 | kzfree(volume_info->password); |
3264 | if (volume_info->UNCip != volume_info->UNC + 2) | ||
3265 | kfree(volume_info->UNCip); | ||
3266 | kfree(volume_info->UNC); | 3272 | kfree(volume_info->UNC); |
3267 | kfree(volume_info->domainname); | 3273 | kfree(volume_info->domainname); |
3268 | kfree(volume_info->iocharset); | 3274 | kfree(volume_info->iocharset); |
@@ -3280,14 +3286,16 @@ cifs_cleanup_volume_info(struct smb_vol *volume_info) | |||
3280 | 3286 | ||
3281 | 3287 | ||
3282 | #ifdef CONFIG_CIFS_DFS_UPCALL | 3288 | #ifdef CONFIG_CIFS_DFS_UPCALL |
3283 | /* build_path_to_root returns full path to root when | 3289 | /* |
3284 | * we do not have an exiting connection (tcon) */ | 3290 | * cifs_build_path_to_root returns full path to root when we do not have an |
3291 | * exiting connection (tcon) | ||
3292 | */ | ||
3285 | static char * | 3293 | static char * |
3286 | build_unc_path_to_root(const struct smb_vol *vol, | 3294 | build_unc_path_to_root(const struct smb_vol *vol, |
3287 | const struct cifs_sb_info *cifs_sb) | 3295 | const struct cifs_sb_info *cifs_sb) |
3288 | { | 3296 | { |
3289 | char *full_path, *pos; | 3297 | char *full_path, *pos; |
3290 | unsigned int pplen = vol->prepath ? strlen(vol->prepath) : 0; | 3298 | unsigned int pplen = vol->prepath ? strlen(vol->prepath) + 1 : 0; |
3291 | unsigned int unc_len = strnlen(vol->UNC, MAX_TREE_SIZE + 1); | 3299 | unsigned int unc_len = strnlen(vol->UNC, MAX_TREE_SIZE + 1); |
3292 | 3300 | ||
3293 | full_path = kmalloc(unc_len + pplen + 1, GFP_KERNEL); | 3301 | full_path = kmalloc(unc_len + pplen + 1, GFP_KERNEL); |
@@ -3298,6 +3306,7 @@ build_unc_path_to_root(const struct smb_vol *vol, | |||
3298 | pos = full_path + unc_len; | 3306 | pos = full_path + unc_len; |
3299 | 3307 | ||
3300 | if (pplen) { | 3308 | if (pplen) { |
3309 | *pos++ = CIFS_DIR_SEP(cifs_sb); | ||
3301 | strncpy(pos, vol->prepath, pplen); | 3310 | strncpy(pos, vol->prepath, pplen); |
3302 | pos += pplen; | 3311 | pos += pplen; |
3303 | } | 3312 | } |
@@ -3353,7 +3362,6 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses, | |||
3353 | mdata = NULL; | 3362 | mdata = NULL; |
3354 | } else { | 3363 | } else { |
3355 | cleanup_volume_info_contents(volume_info); | 3364 | cleanup_volume_info_contents(volume_info); |
3356 | memset(volume_info, '\0', sizeof(*volume_info)); | ||
3357 | rc = cifs_setup_volume_info(volume_info, mdata, | 3365 | rc = cifs_setup_volume_info(volume_info, mdata, |
3358 | fake_devname); | 3366 | fake_devname); |
3359 | } | 3367 | } |
@@ -3375,7 +3383,6 @@ cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data, | |||
3375 | if (cifs_parse_mount_options(mount_data, devname, volume_info)) | 3383 | if (cifs_parse_mount_options(mount_data, devname, volume_info)) |
3376 | return -EINVAL; | 3384 | return -EINVAL; |
3377 | 3385 | ||
3378 | |||
3379 | if (volume_info->nullauth) { | 3386 | if (volume_info->nullauth) { |
3380 | cFYI(1, "Anonymous login"); | 3387 | cFYI(1, "Anonymous login"); |
3381 | kfree(volume_info->username); | 3388 | kfree(volume_info->username); |
@@ -3412,7 +3419,7 @@ cifs_get_volume_info(char *mount_data, const char *devname) | |||
3412 | int rc; | 3419 | int rc; |
3413 | struct smb_vol *volume_info; | 3420 | struct smb_vol *volume_info; |
3414 | 3421 | ||
3415 | volume_info = kzalloc(sizeof(struct smb_vol), GFP_KERNEL); | 3422 | volume_info = kmalloc(sizeof(struct smb_vol), GFP_KERNEL); |
3416 | if (!volume_info) | 3423 | if (!volume_info) |
3417 | return ERR_PTR(-ENOMEM); | 3424 | return ERR_PTR(-ENOMEM); |
3418 | 3425 | ||
@@ -3537,8 +3544,10 @@ remote_path_check: | |||
3537 | rc = -ENOSYS; | 3544 | rc = -ENOSYS; |
3538 | goto mount_fail_check; | 3545 | goto mount_fail_check; |
3539 | } | 3546 | } |
3540 | /* build_path_to_root works only when we have a valid tcon */ | 3547 | /* |
3541 | full_path = build_path_to_root(volume_info, cifs_sb, tcon); | 3548 | * cifs_build_path_to_root works only when we have a valid tcon |
3549 | */ | ||
3550 | full_path = cifs_build_path_to_root(volume_info, cifs_sb, tcon); | ||
3542 | if (full_path == NULL) { | 3551 | if (full_path == NULL) { |
3543 | rc = -ENOMEM; | 3552 | rc = -ENOMEM; |
3544 | goto mount_fail_check; | 3553 | goto mount_fail_check; |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 7c0a81283645..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) |
@@ -398,7 +430,16 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry, | |||
398 | * in network traffic in the other paths. | 430 | * in network traffic in the other paths. |
399 | */ | 431 | */ |
400 | if (!(oflags & O_CREAT)) { | 432 | if (!(oflags & O_CREAT)) { |
401 | struct dentry *res = cifs_lookup(inode, direntry, 0); | 433 | struct dentry *res; |
434 | |||
435 | /* | ||
436 | * Check for hashed negative dentry. We have already revalidated | ||
437 | * the dentry and it is fine. No need to perform another lookup. | ||
438 | */ | ||
439 | if (!d_unhashed(direntry)) | ||
440 | return -ENOENT; | ||
441 | |||
442 | res = cifs_lookup(inode, direntry, 0); | ||
402 | if (IS_ERR(res)) | 443 | if (IS_ERR(res)) |
403 | return PTR_ERR(res); | 444 | return PTR_ERR(res); |
404 | 445 | ||
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index edb25b4bbb95..8ea6ca50a665 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -238,6 +238,23 @@ out: | |||
238 | return rc; | 238 | return rc; |
239 | } | 239 | } |
240 | 240 | ||
241 | static bool | ||
242 | cifs_has_mand_locks(struct cifsInodeInfo *cinode) | ||
243 | { | ||
244 | struct cifs_fid_locks *cur; | ||
245 | bool has_locks = false; | ||
246 | |||
247 | down_read(&cinode->lock_sem); | ||
248 | list_for_each_entry(cur, &cinode->llist, llist) { | ||
249 | if (!list_empty(&cur->locks)) { | ||
250 | has_locks = true; | ||
251 | break; | ||
252 | } | ||
253 | } | ||
254 | up_read(&cinode->lock_sem); | ||
255 | return has_locks; | ||
256 | } | ||
257 | |||
241 | struct cifsFileInfo * | 258 | struct cifsFileInfo * |
242 | cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, | 259 | cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, |
243 | struct tcon_link *tlink, __u32 oplock) | 260 | struct tcon_link *tlink, __u32 oplock) |
@@ -248,6 +265,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, | |||
248 | struct cifsFileInfo *cfile; | 265 | struct cifsFileInfo *cfile; |
249 | struct cifs_fid_locks *fdlocks; | 266 | struct cifs_fid_locks *fdlocks; |
250 | struct cifs_tcon *tcon = tlink_tcon(tlink); | 267 | struct cifs_tcon *tcon = tlink_tcon(tlink); |
268 | struct TCP_Server_Info *server = tcon->ses->server; | ||
251 | 269 | ||
252 | cfile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); | 270 | cfile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); |
253 | if (cfile == NULL) | 271 | if (cfile == NULL) |
@@ -276,12 +294,22 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, | |||
276 | INIT_WORK(&cfile->oplock_break, cifs_oplock_break); | 294 | INIT_WORK(&cfile->oplock_break, cifs_oplock_break); |
277 | mutex_init(&cfile->fh_mutex); | 295 | mutex_init(&cfile->fh_mutex); |
278 | 296 | ||
297 | /* | ||
298 | * If the server returned a read oplock and we have mandatory brlocks, | ||
299 | * set oplock level to None. | ||
300 | */ | ||
301 | if (oplock == server->vals->oplock_read && | ||
302 | cifs_has_mand_locks(cinode)) { | ||
303 | cFYI(1, "Reset oplock val from read to None due to mand locks"); | ||
304 | oplock = 0; | ||
305 | } | ||
306 | |||
279 | spin_lock(&cifs_file_list_lock); | 307 | spin_lock(&cifs_file_list_lock); |
280 | if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE) | 308 | if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE && oplock) |
281 | oplock = fid->pending_open->oplock; | 309 | oplock = fid->pending_open->oplock; |
282 | list_del(&fid->pending_open->olist); | 310 | list_del(&fid->pending_open->olist); |
283 | 311 | ||
284 | tlink_tcon(tlink)->ses->server->ops->set_fid(cfile, fid, oplock); | 312 | server->ops->set_fid(cfile, fid, oplock); |
285 | 313 | ||
286 | list_add(&cfile->tlist, &tcon->openFileList); | 314 | list_add(&cfile->tlist, &tcon->openFileList); |
287 | /* if readable file instance put first in list*/ | 315 | /* if readable file instance put first in list*/ |
@@ -505,16 +533,36 @@ out: | |||
505 | return rc; | 533 | return rc; |
506 | } | 534 | } |
507 | 535 | ||
536 | static int cifs_push_posix_locks(struct cifsFileInfo *cfile); | ||
537 | |||
508 | /* | 538 | /* |
509 | * Try to reacquire byte range locks that were released when session | 539 | * Try to reacquire byte range locks that were released when session |
510 | * to server was lost | 540 | * to server was lost. |
511 | */ | 541 | */ |
512 | static int cifs_relock_file(struct cifsFileInfo *cifsFile) | 542 | static int |
543 | cifs_relock_file(struct cifsFileInfo *cfile) | ||
513 | { | 544 | { |
545 | struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb); | ||
546 | struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); | ||
547 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | ||
514 | int rc = 0; | 548 | int rc = 0; |
515 | 549 | ||
516 | /* BB list all locks open on this file and relock */ | 550 | /* we are going to update can_cache_brlcks here - need a write access */ |
551 | down_write(&cinode->lock_sem); | ||
552 | if (cinode->can_cache_brlcks) { | ||
553 | /* can cache locks - no need to push them */ | ||
554 | up_write(&cinode->lock_sem); | ||
555 | return rc; | ||
556 | } | ||
557 | |||
558 | if (cap_unix(tcon->ses) && | ||
559 | (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && | ||
560 | ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) | ||
561 | rc = cifs_push_posix_locks(cfile); | ||
562 | else | ||
563 | rc = tcon->ses->server->ops->push_mand_locks(cfile); | ||
517 | 564 | ||
565 | up_write(&cinode->lock_sem); | ||
518 | return rc; | 566 | return rc; |
519 | } | 567 | } |
520 | 568 | ||
@@ -739,10 +787,15 @@ cifs_del_lock_waiters(struct cifsLockInfo *lock) | |||
739 | } | 787 | } |
740 | } | 788 | } |
741 | 789 | ||
790 | #define CIFS_LOCK_OP 0 | ||
791 | #define CIFS_READ_OP 1 | ||
792 | #define CIFS_WRITE_OP 2 | ||
793 | |||
794 | /* @rw_check : 0 - no op, 1 - read, 2 - write */ | ||
742 | static bool | 795 | static bool |
743 | cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset, | 796 | cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset, |
744 | __u64 length, __u8 type, struct cifsFileInfo *cfile, | 797 | __u64 length, __u8 type, struct cifsFileInfo *cfile, |
745 | struct cifsLockInfo **conf_lock, bool rw_check) | 798 | struct cifsLockInfo **conf_lock, int rw_check) |
746 | { | 799 | { |
747 | struct cifsLockInfo *li; | 800 | struct cifsLockInfo *li; |
748 | struct cifsFileInfo *cur_cfile = fdlocks->cfile; | 801 | struct cifsFileInfo *cur_cfile = fdlocks->cfile; |
@@ -752,9 +805,13 @@ cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset, | |||
752 | if (offset + length <= li->offset || | 805 | if (offset + length <= li->offset || |
753 | offset >= li->offset + li->length) | 806 | offset >= li->offset + li->length) |
754 | continue; | 807 | continue; |
755 | if (rw_check && server->ops->compare_fids(cfile, cur_cfile) && | 808 | if (rw_check != CIFS_LOCK_OP && current->tgid == li->pid && |
756 | current->tgid == li->pid) | 809 | server->ops->compare_fids(cfile, cur_cfile)) { |
757 | continue; | 810 | /* shared lock prevents write op through the same fid */ |
811 | if (!(li->type & server->vals->shared_lock_type) || | ||
812 | rw_check != CIFS_WRITE_OP) | ||
813 | continue; | ||
814 | } | ||
758 | if ((type & server->vals->shared_lock_type) && | 815 | if ((type & server->vals->shared_lock_type) && |
759 | ((server->ops->compare_fids(cfile, cur_cfile) && | 816 | ((server->ops->compare_fids(cfile, cur_cfile) && |
760 | current->tgid == li->pid) || type == li->type)) | 817 | current->tgid == li->pid) || type == li->type)) |
@@ -769,7 +826,7 @@ cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset, | |||
769 | bool | 826 | bool |
770 | cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, __u64 length, | 827 | cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, __u64 length, |
771 | __u8 type, struct cifsLockInfo **conf_lock, | 828 | __u8 type, struct cifsLockInfo **conf_lock, |
772 | bool rw_check) | 829 | int rw_check) |
773 | { | 830 | { |
774 | bool rc = false; | 831 | bool rc = false; |
775 | struct cifs_fid_locks *cur; | 832 | struct cifs_fid_locks *cur; |
@@ -805,7 +862,7 @@ cifs_lock_test(struct cifsFileInfo *cfile, __u64 offset, __u64 length, | |||
805 | down_read(&cinode->lock_sem); | 862 | down_read(&cinode->lock_sem); |
806 | 863 | ||
807 | exist = cifs_find_lock_conflict(cfile, offset, length, type, | 864 | exist = cifs_find_lock_conflict(cfile, offset, length, type, |
808 | &conf_lock, false); | 865 | &conf_lock, CIFS_LOCK_OP); |
809 | if (exist) { | 866 | if (exist) { |
810 | flock->fl_start = conf_lock->offset; | 867 | flock->fl_start = conf_lock->offset; |
811 | flock->fl_end = conf_lock->offset + conf_lock->length - 1; | 868 | flock->fl_end = conf_lock->offset + conf_lock->length - 1; |
@@ -852,7 +909,7 @@ try_again: | |||
852 | down_write(&cinode->lock_sem); | 909 | down_write(&cinode->lock_sem); |
853 | 910 | ||
854 | exist = cifs_find_lock_conflict(cfile, lock->offset, lock->length, | 911 | exist = cifs_find_lock_conflict(cfile, lock->offset, lock->length, |
855 | lock->type, &conf_lock, false); | 912 | lock->type, &conf_lock, CIFS_LOCK_OP); |
856 | if (!exist && cinode->can_cache_brlcks) { | 913 | if (!exist && cinode->can_cache_brlcks) { |
857 | list_add_tail(&lock->llist, &cfile->llist->locks); | 914 | list_add_tail(&lock->llist, &cfile->llist->locks); |
858 | up_write(&cinode->lock_sem); | 915 | up_write(&cinode->lock_sem); |
@@ -948,7 +1005,6 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile) | |||
948 | int rc = 0, stored_rc; | 1005 | int rc = 0, stored_rc; |
949 | struct cifsLockInfo *li, *tmp; | 1006 | struct cifsLockInfo *li, *tmp; |
950 | struct cifs_tcon *tcon; | 1007 | struct cifs_tcon *tcon; |
951 | struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); | ||
952 | unsigned int num, max_num, max_buf; | 1008 | unsigned int num, max_num, max_buf; |
953 | LOCKING_ANDX_RANGE *buf, *cur; | 1009 | LOCKING_ANDX_RANGE *buf, *cur; |
954 | int types[] = {LOCKING_ANDX_LARGE_FILES, | 1010 | int types[] = {LOCKING_ANDX_LARGE_FILES, |
@@ -958,21 +1014,12 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile) | |||
958 | xid = get_xid(); | 1014 | xid = get_xid(); |
959 | tcon = tlink_tcon(cfile->tlink); | 1015 | tcon = tlink_tcon(cfile->tlink); |
960 | 1016 | ||
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 | /* | 1017 | /* |
970 | * Accessing maxBuf is racy with cifs_reconnect - need to store value | 1018 | * Accessing maxBuf is racy with cifs_reconnect - need to store value |
971 | * and check it for zero before using. | 1019 | * and check it for zero before using. |
972 | */ | 1020 | */ |
973 | max_buf = tcon->ses->server->maxBuf; | 1021 | max_buf = tcon->ses->server->maxBuf; |
974 | if (!max_buf) { | 1022 | if (!max_buf) { |
975 | up_write(&cinode->lock_sem); | ||
976 | free_xid(xid); | 1023 | free_xid(xid); |
977 | return -EINVAL; | 1024 | return -EINVAL; |
978 | } | 1025 | } |
@@ -981,7 +1028,6 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile) | |||
981 | sizeof(LOCKING_ANDX_RANGE); | 1028 | sizeof(LOCKING_ANDX_RANGE); |
982 | buf = kzalloc(max_num * sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL); | 1029 | buf = kzalloc(max_num * sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL); |
983 | if (!buf) { | 1030 | if (!buf) { |
984 | up_write(&cinode->lock_sem); | ||
985 | free_xid(xid); | 1031 | free_xid(xid); |
986 | return -ENOMEM; | 1032 | return -ENOMEM; |
987 | } | 1033 | } |
@@ -1018,9 +1064,6 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile) | |||
1018 | } | 1064 | } |
1019 | } | 1065 | } |
1020 | 1066 | ||
1021 | cinode->can_cache_brlcks = false; | ||
1022 | up_write(&cinode->lock_sem); | ||
1023 | |||
1024 | kfree(buf); | 1067 | kfree(buf); |
1025 | free_xid(xid); | 1068 | free_xid(xid); |
1026 | return rc; | 1069 | return rc; |
@@ -1043,7 +1086,6 @@ struct lock_to_push { | |||
1043 | static int | 1086 | static int |
1044 | cifs_push_posix_locks(struct cifsFileInfo *cfile) | 1087 | cifs_push_posix_locks(struct cifsFileInfo *cfile) |
1045 | { | 1088 | { |
1046 | struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); | ||
1047 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | 1089 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); |
1048 | struct file_lock *flock, **before; | 1090 | struct file_lock *flock, **before; |
1049 | unsigned int count = 0, i = 0; | 1091 | unsigned int count = 0, i = 0; |
@@ -1054,14 +1096,6 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile) | |||
1054 | 1096 | ||
1055 | xid = get_xid(); | 1097 | xid = get_xid(); |
1056 | 1098 | ||
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(); | 1099 | lock_flocks(); |
1066 | cifs_for_each_lock(cfile->dentry->d_inode, before) { | 1100 | cifs_for_each_lock(cfile->dentry->d_inode, before) { |
1067 | if ((*before)->fl_flags & FL_POSIX) | 1101 | if ((*before)->fl_flags & FL_POSIX) |
@@ -1127,9 +1161,6 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile) | |||
1127 | } | 1161 | } |
1128 | 1162 | ||
1129 | out: | 1163 | out: |
1130 | cinode->can_cache_brlcks = false; | ||
1131 | up_write(&cinode->lock_sem); | ||
1132 | |||
1133 | free_xid(xid); | 1164 | free_xid(xid); |
1134 | return rc; | 1165 | return rc; |
1135 | err_out: | 1166 | err_out: |
@@ -1144,14 +1175,27 @@ static int | |||
1144 | cifs_push_locks(struct cifsFileInfo *cfile) | 1175 | cifs_push_locks(struct cifsFileInfo *cfile) |
1145 | { | 1176 | { |
1146 | struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb); | 1177 | struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb); |
1178 | struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); | ||
1147 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | 1179 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); |
1180 | int rc = 0; | ||
1181 | |||
1182 | /* we are going to update can_cache_brlcks here - need a write access */ | ||
1183 | down_write(&cinode->lock_sem); | ||
1184 | if (!cinode->can_cache_brlcks) { | ||
1185 | up_write(&cinode->lock_sem); | ||
1186 | return rc; | ||
1187 | } | ||
1148 | 1188 | ||
1149 | if (cap_unix(tcon->ses) && | 1189 | if (cap_unix(tcon->ses) && |
1150 | (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && | 1190 | (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && |
1151 | ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) | 1191 | ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) |
1152 | return cifs_push_posix_locks(cfile); | 1192 | rc = cifs_push_posix_locks(cfile); |
1193 | else | ||
1194 | rc = tcon->ses->server->ops->push_mand_locks(cfile); | ||
1153 | 1195 | ||
1154 | return tcon->ses->server->ops->push_mand_locks(cfile); | 1196 | cinode->can_cache_brlcks = false; |
1197 | up_write(&cinode->lock_sem); | ||
1198 | return rc; | ||
1155 | } | 1199 | } |
1156 | 1200 | ||
1157 | static void | 1201 | static void |
@@ -1406,6 +1450,7 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type, | |||
1406 | struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data; | 1450 | struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data; |
1407 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | 1451 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); |
1408 | struct TCP_Server_Info *server = tcon->ses->server; | 1452 | struct TCP_Server_Info *server = tcon->ses->server; |
1453 | struct inode *inode = cfile->dentry->d_inode; | ||
1409 | 1454 | ||
1410 | if (posix_lck) { | 1455 | if (posix_lck) { |
1411 | int posix_lock_type; | 1456 | int posix_lock_type; |
@@ -1436,16 +1481,33 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type, | |||
1436 | return -ENOMEM; | 1481 | return -ENOMEM; |
1437 | 1482 | ||
1438 | rc = cifs_lock_add_if(cfile, lock, wait_flag); | 1483 | rc = cifs_lock_add_if(cfile, lock, wait_flag); |
1439 | if (rc < 0) | 1484 | if (rc < 0) { |
1440 | kfree(lock); | 1485 | kfree(lock); |
1441 | if (rc <= 0) | 1486 | return rc; |
1487 | } | ||
1488 | if (!rc) | ||
1442 | goto out; | 1489 | goto out; |
1443 | 1490 | ||
1491 | /* | ||
1492 | * Windows 7 server can delay breaking lease from read to None | ||
1493 | * if we set a byte-range lock on a file - break it explicitly | ||
1494 | * before sending the lock to the server to be sure the next | ||
1495 | * read won't conflict with non-overlapted locks due to | ||
1496 | * pagereading. | ||
1497 | */ | ||
1498 | if (!CIFS_I(inode)->clientCanCacheAll && | ||
1499 | CIFS_I(inode)->clientCanCacheRead) { | ||
1500 | cifs_invalidate_mapping(inode); | ||
1501 | cFYI(1, "Set no oplock for inode=%p due to mand locks", | ||
1502 | inode); | ||
1503 | CIFS_I(inode)->clientCanCacheRead = false; | ||
1504 | } | ||
1505 | |||
1444 | rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length, | 1506 | rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length, |
1445 | type, 1, 0, wait_flag); | 1507 | type, 1, 0, wait_flag); |
1446 | if (rc) { | 1508 | if (rc) { |
1447 | kfree(lock); | 1509 | kfree(lock); |
1448 | goto out; | 1510 | return rc; |
1449 | } | 1511 | } |
1450 | 1512 | ||
1451 | cifs_lock_add(cfile, lock); | 1513 | cifs_lock_add(cfile, lock); |
@@ -1794,7 +1856,6 @@ static int cifs_writepages(struct address_space *mapping, | |||
1794 | struct TCP_Server_Info *server; | 1856 | struct TCP_Server_Info *server; |
1795 | struct page *page; | 1857 | struct page *page; |
1796 | int rc = 0; | 1858 | int rc = 0; |
1797 | loff_t isize = i_size_read(mapping->host); | ||
1798 | 1859 | ||
1799 | /* | 1860 | /* |
1800 | * If wsize is smaller than the page cache size, default to writing | 1861 | * If wsize is smaller than the page cache size, default to writing |
@@ -1899,7 +1960,7 @@ retry: | |||
1899 | */ | 1960 | */ |
1900 | set_page_writeback(page); | 1961 | set_page_writeback(page); |
1901 | 1962 | ||
1902 | if (page_offset(page) >= isize) { | 1963 | if (page_offset(page) >= i_size_read(mapping->host)) { |
1903 | done = true; | 1964 | done = true; |
1904 | unlock_page(page); | 1965 | unlock_page(page); |
1905 | end_page_writeback(page); | 1966 | end_page_writeback(page); |
@@ -1932,7 +1993,8 @@ retry: | |||
1932 | wdata->offset = page_offset(wdata->pages[0]); | 1993 | wdata->offset = page_offset(wdata->pages[0]); |
1933 | wdata->pagesz = PAGE_CACHE_SIZE; | 1994 | wdata->pagesz = PAGE_CACHE_SIZE; |
1934 | wdata->tailsz = | 1995 | wdata->tailsz = |
1935 | min(isize - page_offset(wdata->pages[nr_pages - 1]), | 1996 | min(i_size_read(mapping->host) - |
1997 | page_offset(wdata->pages[nr_pages - 1]), | ||
1936 | (loff_t)PAGE_CACHE_SIZE); | 1998 | (loff_t)PAGE_CACHE_SIZE); |
1937 | wdata->bytes = ((nr_pages - 1) * PAGE_CACHE_SIZE) + | 1999 | wdata->bytes = ((nr_pages - 1) * PAGE_CACHE_SIZE) + |
1938 | wdata->tailsz; | 2000 | wdata->tailsz; |
@@ -2457,7 +2519,7 @@ cifs_writev(struct kiocb *iocb, const struct iovec *iov, | |||
2457 | down_read(&cinode->lock_sem); | 2519 | down_read(&cinode->lock_sem); |
2458 | if (!cifs_find_lock_conflict(cfile, pos, iov_length(iov, nr_segs), | 2520 | if (!cifs_find_lock_conflict(cfile, pos, iov_length(iov, nr_segs), |
2459 | server->vals->exclusive_lock_type, NULL, | 2521 | server->vals->exclusive_lock_type, NULL, |
2460 | true)) { | 2522 | CIFS_WRITE_OP)) { |
2461 | mutex_lock(&inode->i_mutex); | 2523 | mutex_lock(&inode->i_mutex); |
2462 | rc = __generic_file_aio_write(iocb, iov, nr_segs, | 2524 | rc = __generic_file_aio_write(iocb, iov, nr_segs, |
2463 | &iocb->ki_pos); | 2525 | &iocb->ki_pos); |
@@ -2487,42 +2549,34 @@ cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov, | |||
2487 | struct cifsFileInfo *cfile = (struct cifsFileInfo *) | 2549 | struct cifsFileInfo *cfile = (struct cifsFileInfo *) |
2488 | iocb->ki_filp->private_data; | 2550 | iocb->ki_filp->private_data; |
2489 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | 2551 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); |
2552 | ssize_t written; | ||
2490 | 2553 | ||
2491 | #ifdef CONFIG_CIFS_SMB2 | 2554 | if (cinode->clientCanCacheAll) { |
2492 | /* | 2555 | if (cap_unix(tcon->ses) && |
2493 | * If we have an oplock for read and want to write a data to the file | 2556 | (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) |
2494 | * we need to store it in the page cache and then push it to the server | 2557 | && ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) |
2495 | * to be sure the next read will get a valid data. | 2558 | return generic_file_aio_write(iocb, iov, nr_segs, pos); |
2496 | */ | 2559 | return cifs_writev(iocb, iov, nr_segs, pos); |
2497 | if (!cinode->clientCanCacheAll && cinode->clientCanCacheRead) { | ||
2498 | ssize_t written; | ||
2499 | int rc; | ||
2500 | |||
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 | |||
2506 | return written; | ||
2507 | } | 2560 | } |
2508 | #endif | ||
2509 | |||
2510 | /* | 2561 | /* |
2511 | * For non-oplocked files in strict cache mode we need to write the data | 2562 | * For non-oplocked files in strict cache mode we need to write the data |
2512 | * to the server exactly from the pos to pos+len-1 rather than flush all | 2563 | * to the server exactly from the pos to pos+len-1 rather than flush all |
2513 | * affected pages because it may cause a error with mandatory locks on | 2564 | * affected pages because it may cause a error with mandatory locks on |
2514 | * these pages but not on the region from pos to ppos+len-1. | 2565 | * these pages but not on the region from pos to ppos+len-1. |
2515 | */ | 2566 | */ |
2516 | 2567 | written = cifs_user_writev(iocb, iov, nr_segs, pos); | |
2517 | if (!cinode->clientCanCacheAll) | 2568 | if (written > 0 && cinode->clientCanCacheRead) { |
2518 | return cifs_user_writev(iocb, iov, nr_segs, pos); | 2569 | /* |
2519 | 2570 | * Windows 7 server can delay breaking level2 oplock if a write | |
2520 | if (cap_unix(tcon->ses) && | 2571 | * request comes - break it on the client to prevent reading |
2521 | (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && | 2572 | * an old data. |
2522 | ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) | 2573 | */ |
2523 | return generic_file_aio_write(iocb, iov, nr_segs, pos); | 2574 | cifs_invalidate_mapping(inode); |
2524 | 2575 | cFYI(1, "Set no oplock for inode=%p after a write operation", | |
2525 | return cifs_writev(iocb, iov, nr_segs, pos); | 2576 | inode); |
2577 | cinode->clientCanCacheRead = false; | ||
2578 | } | ||
2579 | return written; | ||
2526 | } | 2580 | } |
2527 | 2581 | ||
2528 | static struct cifs_readdata * | 2582 | static struct cifs_readdata * |
@@ -2892,7 +2946,7 @@ cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov, | |||
2892 | down_read(&cinode->lock_sem); | 2946 | down_read(&cinode->lock_sem); |
2893 | if (!cifs_find_lock_conflict(cfile, pos, iov_length(iov, nr_segs), | 2947 | if (!cifs_find_lock_conflict(cfile, pos, iov_length(iov, nr_segs), |
2894 | tcon->ses->server->vals->shared_lock_type, | 2948 | tcon->ses->server->vals->shared_lock_type, |
2895 | NULL, true)) | 2949 | NULL, CIFS_READ_OP)) |
2896 | rc = generic_file_aio_read(iocb, iov, nr_segs, pos); | 2950 | rc = generic_file_aio_read(iocb, iov, nr_segs, pos); |
2897 | up_read(&cinode->lock_sem); | 2951 | up_read(&cinode->lock_sem); |
2898 | return rc; | 2952 | return rc; |
@@ -3527,6 +3581,13 @@ void cifs_oplock_break(struct work_struct *work) | |||
3527 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | 3581 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); |
3528 | int rc = 0; | 3582 | int rc = 0; |
3529 | 3583 | ||
3584 | if (!cinode->clientCanCacheAll && cinode->clientCanCacheRead && | ||
3585 | cifs_has_mand_locks(cinode)) { | ||
3586 | cFYI(1, "Reset oplock to None for inode=%p due to mand locks", | ||
3587 | inode); | ||
3588 | cinode->clientCanCacheRead = false; | ||
3589 | } | ||
3590 | |||
3530 | if (inode && S_ISREG(inode->i_mode)) { | 3591 | if (inode && S_ISREG(inode->i_mode)) { |
3531 | if (cinode->clientCanCacheRead) | 3592 | if (cinode->clientCanCacheRead) |
3532 | break_lease(inode, O_RDONLY); | 3593 | break_lease(inode, O_RDONLY); |
@@ -3536,7 +3597,7 @@ void cifs_oplock_break(struct work_struct *work) | |||
3536 | if (cinode->clientCanCacheRead == 0) { | 3597 | if (cinode->clientCanCacheRead == 0) { |
3537 | rc = filemap_fdatawait(inode->i_mapping); | 3598 | rc = filemap_fdatawait(inode->i_mapping); |
3538 | mapping_set_error(inode->i_mapping, rc); | 3599 | mapping_set_error(inode->i_mapping, rc); |
3539 | invalidate_remote_inode(inode); | 3600 | cifs_invalidate_mapping(inode); |
3540 | } | 3601 | } |
3541 | cFYI(1, "Oplock flush inode %p rc %d", inode, rc); | 3602 | cFYI(1, "Oplock flush inode %p rc %d", inode, rc); |
3542 | } | 3603 | } |
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 f9b5d3d6cf33..cdd6ff48246b 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
@@ -66,18 +66,21 @@ 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; |
81 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | ||
79 | 82 | ||
80 | cFYI(1, "For %s", name->name); | 83 | cFYI(1, "%s: for %s", __func__, name->name); |
81 | 84 | ||
82 | if (parent->d_op && parent->d_op->d_hash) | 85 | if (parent->d_op && parent->d_op->d_hash) |
83 | parent->d_op->d_hash(parent, parent->d_inode, name); | 86 | parent->d_op->d_hash(parent, parent->d_inode, name); |
@@ -86,35 +89,43 @@ cifs_readdir_lookup(struct dentry *parent, struct qstr *name, | |||
86 | 89 | ||
87 | dentry = d_lookup(parent, name); | 90 | dentry = d_lookup(parent, name); |
88 | if (dentry) { | 91 | if (dentry) { |
92 | int err; | ||
93 | |||
89 | inode = dentry->d_inode; | 94 | inode = dentry->d_inode; |
90 | /* update inode in place if i_ino didn't change */ | 95 | if (inode) { |
91 | if (inode && CIFS_I(inode)->uniqueid == fattr->cf_uniqueid) { | 96 | /* |
92 | cifs_fattr_to_inode(inode, fattr); | 97 | * If we're generating inode numbers, then we don't |
93 | return dentry; | 98 | * want to clobber the existing one with the one that |
99 | * the readdir code created. | ||
100 | */ | ||
101 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) | ||
102 | fattr->cf_uniqueid = CIFS_I(inode)->uniqueid; | ||
103 | |||
104 | /* update inode in place if i_ino didn't change */ | ||
105 | if (CIFS_I(inode)->uniqueid == fattr->cf_uniqueid) { | ||
106 | cifs_fattr_to_inode(inode, fattr); | ||
107 | goto out; | ||
108 | } | ||
94 | } | 109 | } |
95 | d_drop(dentry); | 110 | err = d_invalidate(dentry); |
96 | dput(dentry); | 111 | dput(dentry); |
112 | if (err) | ||
113 | return; | ||
97 | } | 114 | } |
98 | 115 | ||
99 | dentry = d_alloc(parent, name); | 116 | dentry = d_alloc(parent, name); |
100 | if (dentry == NULL) | 117 | if (!dentry) |
101 | return NULL; | 118 | return; |
102 | 119 | ||
103 | inode = cifs_iget(sb, fattr); | 120 | inode = cifs_iget(sb, fattr); |
104 | if (!inode) { | 121 | if (!inode) |
105 | dput(dentry); | 122 | goto out; |
106 | return NULL; | ||
107 | } | ||
108 | 123 | ||
109 | alias = d_materialise_unique(dentry, inode); | 124 | alias = d_materialise_unique(dentry, inode); |
110 | if (alias != NULL) { | 125 | if (alias && !IS_ERR(alias)) |
111 | dput(dentry); | 126 | dput(alias); |
112 | if (IS_ERR(alias)) | 127 | out: |
113 | return NULL; | 128 | dput(dentry); |
114 | dentry = alias; | ||
115 | } | ||
116 | |||
117 | return dentry; | ||
118 | } | 129 | } |
119 | 130 | ||
120 | static void | 131 | static void |
@@ -134,6 +145,16 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb) | |||
134 | if (fattr->cf_cifsattrs & ATTR_READONLY) | 145 | if (fattr->cf_cifsattrs & ATTR_READONLY) |
135 | fattr->cf_mode &= ~S_IWUGO; | 146 | fattr->cf_mode &= ~S_IWUGO; |
136 | 147 | ||
148 | /* | ||
149 | * We of course don't get ACL info in FIND_FIRST/NEXT results, so | ||
150 | * mark it for revalidation so that "ls -l" will look right. It might | ||
151 | * be super-slow, but if we don't do this then the ownership of files | ||
152 | * may look wrong since the inodes may not have timed out by the time | ||
153 | * "ls" does a stat() call on them. | ||
154 | */ | ||
155 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) | ||
156 | fattr->cf_flags |= CIFS_FATTR_NEED_REVAL; | ||
157 | |||
137 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL && | 158 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL && |
138 | fattr->cf_cifsattrs & ATTR_SYSTEM) { | 159 | fattr->cf_cifsattrs & ATTR_SYSTEM) { |
139 | if (fattr->cf_eof == 0) { | 160 | if (fattr->cf_eof == 0) { |
@@ -649,7 +670,6 @@ static int cifs_filldir(char *find_entry, struct file *file, filldir_t filldir, | |||
649 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 670 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
650 | struct cifs_dirent de = { NULL, }; | 671 | struct cifs_dirent de = { NULL, }; |
651 | struct cifs_fattr fattr; | 672 | struct cifs_fattr fattr; |
652 | struct dentry *dentry; | ||
653 | struct qstr name; | 673 | struct qstr name; |
654 | int rc = 0; | 674 | int rc = 0; |
655 | ino_t ino; | 675 | ino_t ino; |
@@ -720,13 +740,11 @@ static int cifs_filldir(char *find_entry, struct file *file, filldir_t filldir, | |||
720 | */ | 740 | */ |
721 | fattr.cf_flags |= CIFS_FATTR_NEED_REVAL; | 741 | fattr.cf_flags |= CIFS_FATTR_NEED_REVAL; |
722 | 742 | ||
723 | ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid); | 743 | cifs_prime_dcache(file->f_dentry, &name, &fattr); |
724 | dentry = cifs_readdir_lookup(file->f_dentry, &name, &fattr); | ||
725 | 744 | ||
745 | ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid); | ||
726 | rc = filldir(dirent, name.name, name.len, file->f_pos, ino, | 746 | rc = filldir(dirent, name.name, name.len, file->f_pos, ino, |
727 | fattr.cf_dtype); | 747 | fattr.cf_dtype); |
728 | |||
729 | dput(dentry); | ||
730 | return rc; | 748 | return rc; |
731 | } | 749 | } |
732 | 750 | ||
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index 56cc4be87807..47bc5a87f94e 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c | |||
@@ -53,6 +53,13 @@ send_nt_cancel(struct TCP_Server_Info *server, void *buf, | |||
53 | mutex_unlock(&server->srv_mutex); | 53 | mutex_unlock(&server->srv_mutex); |
54 | return rc; | 54 | return rc; |
55 | } | 55 | } |
56 | |||
57 | /* | ||
58 | * The response to this call was already factored into the sequence | ||
59 | * number when the call went out, so we must adjust it back downward | ||
60 | * after signing here. | ||
61 | */ | ||
62 | --server->sequence_number; | ||
56 | rc = smb_send(server, in_buf, be32_to_cpu(in_buf->smb_buf_length)); | 63 | rc = smb_send(server, in_buf, be32_to_cpu(in_buf->smb_buf_length)); |
57 | mutex_unlock(&server->srv_mutex); | 64 | mutex_unlock(&server->srv_mutex); |
58 | 65 | ||
@@ -575,37 +582,6 @@ cifs_query_file_info(const unsigned int xid, struct cifs_tcon *tcon, | |||
575 | return CIFSSMBQFileInfo(xid, tcon, fid->netfid, data); | 582 | return CIFSSMBQFileInfo(xid, tcon, fid->netfid, data); |
576 | } | 583 | } |
577 | 584 | ||
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 | 585 | static void |
610 | cifs_clear_stats(struct cifs_tcon *tcon) | 586 | cifs_clear_stats(struct cifs_tcon *tcon) |
611 | { | 587 | { |
@@ -766,7 +742,6 @@ smb_set_file_info(struct inode *inode, const char *full_path, | |||
766 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 742 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
767 | struct tcon_link *tlink = NULL; | 743 | struct tcon_link *tlink = NULL; |
768 | struct cifs_tcon *tcon; | 744 | struct cifs_tcon *tcon; |
769 | FILE_BASIC_INFO info_buf; | ||
770 | 745 | ||
771 | /* if the file is already open for write, just use that fileid */ | 746 | /* if the file is already open for write, just use that fileid */ |
772 | open_file = find_writable_file(cinode, true); | 747 | open_file = find_writable_file(cinode, true); |
@@ -817,7 +792,7 @@ smb_set_file_info(struct inode *inode, const char *full_path, | |||
817 | netpid = current->tgid; | 792 | netpid = current->tgid; |
818 | 793 | ||
819 | set_via_filehandle: | 794 | set_via_filehandle: |
820 | rc = CIFSSMBSetFileInfo(xid, tcon, &info_buf, netfid, netpid); | 795 | rc = CIFSSMBSetFileInfo(xid, tcon, buf, netfid, netpid); |
821 | if (!rc) | 796 | if (!rc) |
822 | cinode->cifsAttrs = le32_to_cpu(buf->Attributes); | 797 | cinode->cifsAttrs = le32_to_cpu(buf->Attributes); |
823 | 798 | ||
@@ -944,7 +919,6 @@ struct smb_version_operations smb1_operations = { | |||
944 | .set_path_size = CIFSSMBSetEOF, | 919 | .set_path_size = CIFSSMBSetEOF, |
945 | .set_file_size = CIFSSMBSetFileSize, | 920 | .set_file_size = CIFSSMBSetFileSize, |
946 | .set_file_info = smb_set_file_info, | 921 | .set_file_info = smb_set_file_info, |
947 | .build_path_to_root = cifs_build_path_to_root, | ||
948 | .echo = CIFSSMBEcho, | 922 | .echo = CIFSSMBEcho, |
949 | .mkdir = CIFSSMBMkDir, | 923 | .mkdir = CIFSSMBMkDir, |
950 | .mkdir_setinfo = cifs_mkdir_setinfo, | 924 | .mkdir_setinfo = cifs_mkdir_setinfo, |
@@ -985,4 +959,5 @@ struct smb_version_values smb1_values = { | |||
985 | .cap_unix = CAP_UNIX, | 959 | .cap_unix = CAP_UNIX, |
986 | .cap_nt_find = CAP_NT_SMBS | CAP_NT_FIND, | 960 | .cap_nt_find = CAP_NT_SMBS | CAP_NT_FIND, |
987 | .cap_large_files = CAP_LARGE_FILES, | 961 | .cap_large_files = CAP_LARGE_FILES, |
962 | .oplock_read = OPLOCK_READ, | ||
988 | }; | 963 | }; |
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..c9c7aa7ed966 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,92 @@ 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, | ||
711 | .oplock_read = SMB2_OPLOCK_LEVEL_II, | ||
644 | }; | 712 | }; |
645 | 713 | ||
646 | struct smb_version_values smb21_values = { | 714 | struct smb_version_values smb21_values = { |
@@ -658,6 +726,7 @@ struct smb_version_values smb21_values = { | |||
658 | .cap_unix = 0, | 726 | .cap_unix = 0, |
659 | .cap_nt_find = SMB2_NT_FIND, | 727 | .cap_nt_find = SMB2_NT_FIND, |
660 | .cap_large_files = SMB2_LARGE_FILES, | 728 | .cap_large_files = SMB2_LARGE_FILES, |
729 | .oplock_read = SMB2_OPLOCK_LEVEL_II, | ||
661 | }; | 730 | }; |
662 | 731 | ||
663 | struct smb_version_values smb30_values = { | 732 | struct smb_version_values smb30_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) |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 76d974c952fe..1a528680ec5a 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -144,9 +144,6 @@ smb_send_kvec(struct TCP_Server_Info *server, struct kvec *iov, size_t n_vec, | |||
144 | 144 | ||
145 | *sent = 0; | 145 | *sent = 0; |
146 | 146 | ||
147 | if (ssocket == NULL) | ||
148 | return -ENOTSOCK; /* BB eventually add reconnect code here */ | ||
149 | |||
150 | smb_msg.msg_name = (struct sockaddr *) &server->dstaddr; | 147 | smb_msg.msg_name = (struct sockaddr *) &server->dstaddr; |
151 | smb_msg.msg_namelen = sizeof(struct sockaddr); | 148 | smb_msg.msg_namelen = sizeof(struct sockaddr); |
152 | smb_msg.msg_control = NULL; | 149 | smb_msg.msg_control = NULL; |
@@ -291,6 +288,9 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) | |||
291 | struct socket *ssocket = server->ssocket; | 288 | struct socket *ssocket = server->ssocket; |
292 | int val = 1; | 289 | int val = 1; |
293 | 290 | ||
291 | if (ssocket == NULL) | ||
292 | return -ENOTSOCK; | ||
293 | |||
294 | cFYI(1, "Sending smb: smb_len=%u", smb_buf_length); | 294 | cFYI(1, "Sending smb: smb_len=%u", smb_buf_length); |
295 | dump_smb(iov[0].iov_base, iov[0].iov_len); | 295 | dump_smb(iov[0].iov_base, iov[0].iov_len); |
296 | 296 | ||