diff options
author | Miklos Szeredi <mszeredi@suse.cz> | 2012-06-05 09:10:23 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-07-14 08:33:15 -0400 |
commit | d2c127197dfc0b2bae62a52e1e0d3e3ff493919e (patch) | |
tree | 75a30530499790ace8af09f9442f111f59564647 /fs/cifs/dir.c | |
parent | c8ccbe032feb127a977c66865cb63d72d9a6e08b (diff) |
cifs: implement i_op->atomic_open()
Add an ->atomic_open implementation which replaces the atomic lookup+open+create
operation implemented via ->lookup and ->create operations.
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
CC: Steve French <sfrench@samba.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/cifs/dir.c')
-rw-r--r-- | fs/cifs/dir.c | 441 |
1 files changed, 243 insertions, 198 deletions
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index ec4e9a2a12f8..7a3dcd15d681 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -133,108 +133,141 @@ cifs_bp_rename_retry: | |||
133 | return full_path; | 133 | return full_path; |
134 | } | 134 | } |
135 | 135 | ||
136 | /* | ||
137 | * Don't allow the separator character in a path component. | ||
138 | * The VFS will not allow "/", but "\" is allowed by posix. | ||
139 | */ | ||
140 | static int | ||
141 | check_name(struct dentry *direntry) | ||
142 | { | ||
143 | struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); | ||
144 | int i; | ||
145 | |||
146 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) { | ||
147 | for (i = 0; i < direntry->d_name.len; i++) { | ||
148 | if (direntry->d_name.name[i] == '\\') { | ||
149 | cFYI(1, "Invalid file name"); | ||
150 | return -EINVAL; | ||
151 | } | ||
152 | } | ||
153 | } | ||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | |||
136 | /* Inode operations in similar order to how they appear in Linux file fs.h */ | 158 | /* Inode operations in similar order to how they appear in Linux file fs.h */ |
137 | 159 | ||
138 | int | 160 | static int cifs_do_create(struct inode *inode, struct dentry *direntry, |
139 | cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, | 161 | int xid, struct tcon_link *tlink, unsigned oflags, |
140 | struct nameidata *nd) | 162 | umode_t mode, __u32 *oplock, __u16 *fileHandle, |
163 | bool *created) | ||
141 | { | 164 | { |
142 | int rc = -ENOENT; | 165 | int rc = -ENOENT; |
143 | int xid; | ||
144 | int create_options = CREATE_NOT_DIR; | 166 | int create_options = CREATE_NOT_DIR; |
145 | __u32 oplock = 0; | 167 | int desiredAccess; |
146 | int oflags; | 168 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
147 | /* | 169 | struct cifs_tcon *tcon = tlink_tcon(tlink); |
148 | * BB below access is probably too much for mknod to request | ||
149 | * but we have to do query and setpathinfo so requesting | ||
150 | * less could fail (unless we want to request getatr and setatr | ||
151 | * permissions (only). At least for POSIX we do not have to | ||
152 | * request so much. | ||
153 | */ | ||
154 | int desiredAccess = GENERIC_READ | GENERIC_WRITE; | ||
155 | __u16 fileHandle; | ||
156 | struct cifs_sb_info *cifs_sb; | ||
157 | struct tcon_link *tlink; | ||
158 | struct cifs_tcon *tcon; | ||
159 | char *full_path = NULL; | 170 | char *full_path = NULL; |
160 | FILE_ALL_INFO *buf = NULL; | 171 | FILE_ALL_INFO *buf = NULL; |
161 | struct inode *newinode = NULL; | 172 | struct inode *newinode = NULL; |
162 | int disposition = FILE_OVERWRITE_IF; | 173 | int disposition; |
163 | |||
164 | xid = GetXid(); | ||
165 | |||
166 | cifs_sb = CIFS_SB(inode->i_sb); | ||
167 | tlink = cifs_sb_tlink(cifs_sb); | ||
168 | if (IS_ERR(tlink)) { | ||
169 | FreeXid(xid); | ||
170 | return PTR_ERR(tlink); | ||
171 | } | ||
172 | tcon = tlink_tcon(tlink); | ||
173 | 174 | ||
175 | *oplock = 0; | ||
174 | if (tcon->ses->server->oplocks) | 176 | if (tcon->ses->server->oplocks) |
175 | oplock = REQ_OPLOCK; | 177 | *oplock = REQ_OPLOCK; |
176 | |||
177 | if (nd) | ||
178 | oflags = nd->intent.open.file->f_flags; | ||
179 | else | ||
180 | oflags = O_RDONLY | O_CREAT; | ||
181 | 178 | ||
182 | full_path = build_path_from_dentry(direntry); | 179 | full_path = build_path_from_dentry(direntry); |
183 | if (full_path == NULL) { | 180 | if (full_path == NULL) { |
184 | rc = -ENOMEM; | 181 | rc = -ENOMEM; |
185 | goto cifs_create_out; | 182 | goto out; |
186 | } | 183 | } |
187 | 184 | ||
188 | if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) && | 185 | if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) && |
186 | !tcon->broken_posix_open && | ||
189 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & | 187 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & |
190 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { | 188 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { |
191 | rc = cifs_posix_open(full_path, &newinode, | 189 | rc = cifs_posix_open(full_path, &newinode, |
192 | inode->i_sb, mode, oflags, &oplock, &fileHandle, xid); | 190 | inode->i_sb, mode, oflags, oplock, fileHandle, xid); |
193 | /* EIO could indicate that (posix open) operation is not | 191 | switch (rc) { |
194 | supported, despite what server claimed in capability | 192 | case 0: |
195 | negotiation. EREMOTE indicates DFS junction, which is not | 193 | if (newinode == NULL) { |
196 | handled in posix open */ | 194 | /* query inode info */ |
197 | |||
198 | if (rc == 0) { | ||
199 | if (newinode == NULL) /* query inode info */ | ||
200 | goto cifs_create_get_file_info; | 195 | goto cifs_create_get_file_info; |
201 | else /* success, no need to query */ | 196 | } |
202 | goto cifs_create_set_dentry; | ||
203 | } else if ((rc != -EIO) && (rc != -EREMOTE) && | ||
204 | (rc != -EOPNOTSUPP) && (rc != -EINVAL)) | ||
205 | goto cifs_create_out; | ||
206 | /* else fallthrough to retry, using older open call, this is | ||
207 | case where server does not support this SMB level, and | ||
208 | falsely claims capability (also get here for DFS case | ||
209 | which should be rare for path not covered on files) */ | ||
210 | } | ||
211 | 197 | ||
212 | if (nd) { | 198 | if (!S_ISREG(newinode->i_mode)) { |
213 | /* if the file is going to stay open, then we | 199 | /* |
214 | need to set the desired access properly */ | 200 | * The server may allow us to open things like |
215 | desiredAccess = 0; | 201 | * FIFOs, but the client isn't set up to deal |
216 | if (OPEN_FMODE(oflags) & FMODE_READ) | 202 | * with that. If it's not a regular file, just |
217 | desiredAccess |= GENERIC_READ; /* is this too little? */ | 203 | * close it and proceed as if it were a normal |
218 | if (OPEN_FMODE(oflags) & FMODE_WRITE) | 204 | * lookup. |
219 | desiredAccess |= GENERIC_WRITE; | 205 | */ |
220 | 206 | CIFSSMBClose(xid, tcon, *fileHandle); | |
221 | if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) | 207 | goto cifs_create_get_file_info; |
222 | disposition = FILE_CREATE; | 208 | } |
223 | else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) | 209 | /* success, no need to query */ |
224 | disposition = FILE_OVERWRITE_IF; | 210 | goto cifs_create_set_dentry; |
225 | else if ((oflags & O_CREAT) == O_CREAT) | 211 | |
226 | disposition = FILE_OPEN_IF; | 212 | case -ENOENT: |
227 | else | 213 | goto cifs_create_get_file_info; |
228 | cFYI(1, "Create flag not set in create function"); | 214 | |
215 | case -EIO: | ||
216 | case -EINVAL: | ||
217 | /* | ||
218 | * EIO could indicate that (posix open) operation is not | ||
219 | * supported, despite what server claimed in capability | ||
220 | * negotiation. | ||
221 | * | ||
222 | * POSIX open in samba versions 3.3.1 and earlier could | ||
223 | * incorrectly fail with invalid parameter. | ||
224 | */ | ||
225 | tcon->broken_posix_open = true; | ||
226 | break; | ||
227 | |||
228 | case -EREMOTE: | ||
229 | case -EOPNOTSUPP: | ||
230 | /* | ||
231 | * EREMOTE indicates DFS junction, which is not handled | ||
232 | * in posix open. If either that or op not supported | ||
233 | * returned, follow the normal lookup. | ||
234 | */ | ||
235 | break; | ||
236 | |||
237 | default: | ||
238 | goto out; | ||
239 | } | ||
240 | /* | ||
241 | * fallthrough to retry, using older open call, this is case | ||
242 | * where server does not support this SMB level, and falsely | ||
243 | * claims capability (also get here for DFS case which should be | ||
244 | * rare for path not covered on files) | ||
245 | */ | ||
229 | } | 246 | } |
230 | 247 | ||
248 | desiredAccess = 0; | ||
249 | if (OPEN_FMODE(oflags) & FMODE_READ) | ||
250 | desiredAccess |= GENERIC_READ; /* is this too little? */ | ||
251 | if (OPEN_FMODE(oflags) & FMODE_WRITE) | ||
252 | desiredAccess |= GENERIC_WRITE; | ||
253 | |||
254 | disposition = FILE_OVERWRITE_IF; | ||
255 | if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) | ||
256 | disposition = FILE_CREATE; | ||
257 | else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) | ||
258 | disposition = FILE_OVERWRITE_IF; | ||
259 | else if ((oflags & O_CREAT) == O_CREAT) | ||
260 | disposition = FILE_OPEN_IF; | ||
261 | else | ||
262 | cFYI(1, "Create flag not set in create function"); | ||
263 | |||
231 | /* BB add processing to set equivalent of mode - e.g. via CreateX with | 264 | /* BB add processing to set equivalent of mode - e.g. via CreateX with |
232 | ACLs */ | 265 | ACLs */ |
233 | 266 | ||
234 | buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); | 267 | buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); |
235 | if (buf == NULL) { | 268 | if (buf == NULL) { |
236 | rc = -ENOMEM; | 269 | rc = -ENOMEM; |
237 | goto cifs_create_out; | 270 | goto out; |
238 | } | 271 | } |
239 | 272 | ||
240 | /* | 273 | /* |
@@ -250,7 +283,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, | |||
250 | if (tcon->ses->capabilities & CAP_NT_SMBS) | 283 | if (tcon->ses->capabilities & CAP_NT_SMBS) |
251 | rc = CIFSSMBOpen(xid, tcon, full_path, disposition, | 284 | rc = CIFSSMBOpen(xid, tcon, full_path, disposition, |
252 | desiredAccess, create_options, | 285 | desiredAccess, create_options, |
253 | &fileHandle, &oplock, buf, cifs_sb->local_nls, | 286 | fileHandle, oplock, buf, cifs_sb->local_nls, |
254 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 287 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
255 | else | 288 | else |
256 | rc = -EIO; /* no NT SMB support fall into legacy open below */ | 289 | rc = -EIO; /* no NT SMB support fall into legacy open below */ |
@@ -259,17 +292,17 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, | |||
259 | /* old server, retry the open legacy style */ | 292 | /* old server, retry the open legacy style */ |
260 | rc = SMBLegacyOpen(xid, tcon, full_path, disposition, | 293 | rc = SMBLegacyOpen(xid, tcon, full_path, disposition, |
261 | desiredAccess, create_options, | 294 | desiredAccess, create_options, |
262 | &fileHandle, &oplock, buf, cifs_sb->local_nls, | 295 | fileHandle, oplock, buf, cifs_sb->local_nls, |
263 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 296 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
264 | } | 297 | } |
265 | if (rc) { | 298 | if (rc) { |
266 | cFYI(1, "cifs_create returned 0x%x", rc); | 299 | cFYI(1, "cifs_create returned 0x%x", rc); |
267 | goto cifs_create_out; | 300 | goto out; |
268 | } | 301 | } |
269 | 302 | ||
270 | /* If Open reported that we actually created a file | 303 | /* If Open reported that we actually created a file |
271 | then we now have to set the mode if possible */ | 304 | then we now have to set the mode if possible */ |
272 | if ((tcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) { | 305 | if ((tcon->unix_ext) && (*oplock & CIFS_CREATE_ACTION)) { |
273 | struct cifs_unix_set_info_args args = { | 306 | struct cifs_unix_set_info_args args = { |
274 | .mode = mode, | 307 | .mode = mode, |
275 | .ctime = NO_CHANGE_64, | 308 | .ctime = NO_CHANGE_64, |
@@ -278,6 +311,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, | |||
278 | .device = 0, | 311 | .device = 0, |
279 | }; | 312 | }; |
280 | 313 | ||
314 | *created = true; | ||
281 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { | 315 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { |
282 | args.uid = (__u64) current_fsuid(); | 316 | args.uid = (__u64) current_fsuid(); |
283 | if (inode->i_mode & S_ISGID) | 317 | if (inode->i_mode & S_ISGID) |
@@ -288,7 +322,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, | |||
288 | args.uid = NO_CHANGE_64; | 322 | args.uid = NO_CHANGE_64; |
289 | args.gid = NO_CHANGE_64; | 323 | args.gid = NO_CHANGE_64; |
290 | } | 324 | } |
291 | CIFSSMBUnixSetFileInfo(xid, tcon, &args, fileHandle, | 325 | CIFSSMBUnixSetFileInfo(xid, tcon, &args, *fileHandle, |
292 | current->tgid); | 326 | current->tgid); |
293 | } else { | 327 | } else { |
294 | /* BB implement mode setting via Windows security | 328 | /* BB implement mode setting via Windows security |
@@ -305,11 +339,11 @@ cifs_create_get_file_info: | |||
305 | inode->i_sb, xid); | 339 | inode->i_sb, xid); |
306 | else { | 340 | else { |
307 | rc = cifs_get_inode_info(&newinode, full_path, buf, | 341 | rc = cifs_get_inode_info(&newinode, full_path, buf, |
308 | inode->i_sb, xid, &fileHandle); | 342 | inode->i_sb, xid, fileHandle); |
309 | if (newinode) { | 343 | if (newinode) { |
310 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) | 344 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) |
311 | newinode->i_mode = mode; | 345 | newinode->i_mode = mode; |
312 | if ((oplock & CIFS_CREATE_ACTION) && | 346 | if ((*oplock & CIFS_CREATE_ACTION) && |
313 | (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) { | 347 | (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) { |
314 | newinode->i_uid = current_fsuid(); | 348 | newinode->i_uid = current_fsuid(); |
315 | if (inode->i_mode & S_ISGID) | 349 | if (inode->i_mode & S_ISGID) |
@@ -321,37 +355,139 @@ cifs_create_get_file_info: | |||
321 | } | 355 | } |
322 | 356 | ||
323 | cifs_create_set_dentry: | 357 | cifs_create_set_dentry: |
324 | if (rc == 0) | 358 | if (rc != 0) { |
325 | d_instantiate(direntry, newinode); | ||
326 | else | ||
327 | cFYI(1, "Create worked, get_inode_info failed rc = %d", rc); | 359 | cFYI(1, "Create worked, get_inode_info failed rc = %d", rc); |
360 | goto out; | ||
361 | } | ||
362 | d_drop(direntry); | ||
363 | d_add(direntry, newinode); | ||
328 | 364 | ||
329 | if (newinode && nd) { | 365 | /* ENOENT for create? How weird... */ |
330 | struct cifsFileInfo *pfile_info; | 366 | rc = -ENOENT; |
331 | struct file *filp; | 367 | if (!newinode) { |
368 | CIFSSMBClose(xid, tcon, *fileHandle); | ||
369 | goto out; | ||
370 | } | ||
371 | rc = 0; | ||
332 | 372 | ||
333 | filp = lookup_instantiate_filp(nd, direntry, generic_file_open); | 373 | out: |
334 | if (IS_ERR(filp)) { | 374 | kfree(buf); |
335 | rc = PTR_ERR(filp); | 375 | kfree(full_path); |
336 | CIFSSMBClose(xid, tcon, fileHandle); | 376 | return rc; |
337 | goto cifs_create_out; | 377 | } |
338 | } | ||
339 | 378 | ||
340 | pfile_info = cifs_new_fileinfo(fileHandle, filp, tlink, oplock); | 379 | struct file * |
341 | if (pfile_info == NULL) { | 380 | cifs_atomic_open(struct inode *inode, struct dentry *direntry, |
342 | fput(filp); | 381 | struct opendata *od, unsigned oflags, umode_t mode, |
343 | CIFSSMBClose(xid, tcon, fileHandle); | 382 | bool *created) |
344 | rc = -ENOMEM; | 383 | { |
345 | } | 384 | int rc; |
346 | } else { | 385 | int xid; |
386 | struct tcon_link *tlink; | ||
387 | struct cifs_tcon *tcon; | ||
388 | __u16 fileHandle; | ||
389 | __u32 oplock; | ||
390 | struct file *filp; | ||
391 | struct cifsFileInfo *pfile_info; | ||
392 | |||
393 | /* Posix open is only called (at lookup time) for file create now. For | ||
394 | * opens (rather than creates), because we do not know if it is a file | ||
395 | * or directory yet, and current Samba no longer allows us to do posix | ||
396 | * open on dirs, we could end up wasting an open call on what turns out | ||
397 | * to be a dir. For file opens, we wait to call posix open till | ||
398 | * cifs_open. It could be added to atomic_open in the future but the | ||
399 | * performance tradeoff of the extra network request when EISDIR or | ||
400 | * EACCES is returned would have to be weighed against the 50% reduction | ||
401 | * in network traffic in the other paths. | ||
402 | */ | ||
403 | if (!(oflags & O_CREAT)) { | ||
404 | struct dentry *res = cifs_lookup(inode, direntry, NULL); | ||
405 | if (IS_ERR(res)) | ||
406 | return ERR_CAST(res); | ||
407 | |||
408 | finish_no_open(od, res); | ||
409 | return NULL; | ||
410 | } | ||
411 | |||
412 | rc = check_name(direntry); | ||
413 | if (rc) | ||
414 | return ERR_PTR(rc); | ||
415 | |||
416 | xid = GetXid(); | ||
417 | |||
418 | cFYI(1, "parent inode = 0x%p name is: %s and dentry = 0x%p", | ||
419 | inode, direntry->d_name.name, direntry); | ||
420 | |||
421 | tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb)); | ||
422 | filp = ERR_CAST(tlink); | ||
423 | if (IS_ERR(tlink)) | ||
424 | goto free_xid; | ||
425 | |||
426 | tcon = tlink_tcon(tlink); | ||
427 | |||
428 | rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode, | ||
429 | &oplock, &fileHandle, created); | ||
430 | |||
431 | if (rc) { | ||
432 | filp = ERR_PTR(rc); | ||
433 | goto out; | ||
434 | } | ||
435 | |||
436 | filp = finish_open(od, direntry, generic_file_open); | ||
437 | if (IS_ERR(filp)) { | ||
347 | CIFSSMBClose(xid, tcon, fileHandle); | 438 | CIFSSMBClose(xid, tcon, fileHandle); |
439 | goto out; | ||
348 | } | 440 | } |
349 | 441 | ||
350 | cifs_create_out: | 442 | pfile_info = cifs_new_fileinfo(fileHandle, filp, tlink, oplock); |
351 | kfree(buf); | 443 | if (pfile_info == NULL) { |
352 | kfree(full_path); | 444 | CIFSSMBClose(xid, tcon, fileHandle); |
445 | fput(filp); | ||
446 | filp = ERR_PTR(-ENOMEM); | ||
447 | } | ||
448 | |||
449 | out: | ||
450 | cifs_put_tlink(tlink); | ||
451 | free_xid: | ||
452 | FreeXid(xid); | ||
453 | return filp; | ||
454 | } | ||
455 | |||
456 | int cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, | ||
457 | struct nameidata *nd) | ||
458 | { | ||
459 | int rc; | ||
460 | int xid = GetXid(); | ||
461 | /* | ||
462 | * BB below access is probably too much for mknod to request | ||
463 | * but we have to do query and setpathinfo so requesting | ||
464 | * less could fail (unless we want to request getatr and setatr | ||
465 | * permissions (only). At least for POSIX we do not have to | ||
466 | * request so much. | ||
467 | */ | ||
468 | unsigned oflags = O_EXCL | O_CREAT | O_RDWR; | ||
469 | struct tcon_link *tlink; | ||
470 | __u16 fileHandle; | ||
471 | __u32 oplock; | ||
472 | bool created = true; | ||
473 | |||
474 | cFYI(1, "cifs_create parent inode = 0x%p name is: %s and dentry = 0x%p", | ||
475 | inode, direntry->d_name.name, direntry); | ||
476 | |||
477 | tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb)); | ||
478 | rc = PTR_ERR(tlink); | ||
479 | if (IS_ERR(tlink)) | ||
480 | goto free_xid; | ||
481 | |||
482 | rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode, | ||
483 | &oplock, &fileHandle, &created); | ||
484 | if (!rc) | ||
485 | CIFSSMBClose(xid, tlink_tcon(tlink), fileHandle); | ||
486 | |||
353 | cifs_put_tlink(tlink); | 487 | cifs_put_tlink(tlink); |
488 | free_xid: | ||
354 | FreeXid(xid); | 489 | FreeXid(xid); |
490 | |||
355 | return rc; | 491 | return rc; |
356 | } | 492 | } |
357 | 493 | ||
@@ -492,16 +628,11 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
492 | { | 628 | { |
493 | int xid; | 629 | int xid; |
494 | int rc = 0; /* to get around spurious gcc warning, set to zero here */ | 630 | int rc = 0; /* to get around spurious gcc warning, set to zero here */ |
495 | __u32 oplock; | ||
496 | __u16 fileHandle = 0; | ||
497 | bool posix_open = false; | ||
498 | struct cifs_sb_info *cifs_sb; | 631 | struct cifs_sb_info *cifs_sb; |
499 | struct tcon_link *tlink; | 632 | struct tcon_link *tlink; |
500 | struct cifs_tcon *pTcon; | 633 | struct cifs_tcon *pTcon; |
501 | struct cifsFileInfo *cfile; | ||
502 | struct inode *newInode = NULL; | 634 | struct inode *newInode = NULL; |
503 | char *full_path = NULL; | 635 | char *full_path = NULL; |
504 | struct file *filp; | ||
505 | 636 | ||
506 | xid = GetXid(); | 637 | xid = GetXid(); |
507 | 638 | ||
@@ -518,31 +649,9 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
518 | } | 649 | } |
519 | pTcon = tlink_tcon(tlink); | 650 | pTcon = tlink_tcon(tlink); |
520 | 651 | ||
521 | oplock = pTcon->ses->server->oplocks ? REQ_OPLOCK : 0; | 652 | rc = check_name(direntry); |
522 | 653 | if (rc) | |
523 | /* | ||
524 | * Don't allow the separator character in a path component. | ||
525 | * The VFS will not allow "/", but "\" is allowed by posix. | ||
526 | */ | ||
527 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) { | ||
528 | int i; | ||
529 | for (i = 0; i < direntry->d_name.len; i++) | ||
530 | if (direntry->d_name.name[i] == '\\') { | ||
531 | cFYI(1, "Invalid file name"); | ||
532 | rc = -EINVAL; | ||
533 | goto lookup_out; | ||
534 | } | ||
535 | } | ||
536 | |||
537 | /* | ||
538 | * O_EXCL: optimize away the lookup, but don't hash the dentry. Let | ||
539 | * the VFS handle the create. | ||
540 | */ | ||
541 | if (nd && (nd->flags & LOOKUP_EXCL)) { | ||
542 | d_instantiate(direntry, NULL); | ||
543 | rc = 0; | ||
544 | goto lookup_out; | 654 | goto lookup_out; |
545 | } | ||
546 | 655 | ||
547 | /* can not grab the rename sem here since it would | 656 | /* can not grab the rename sem here since it would |
548 | deadlock in the cases (beginning of sys_rename itself) | 657 | deadlock in the cases (beginning of sys_rename itself) |
@@ -560,80 +669,16 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
560 | } | 669 | } |
561 | cFYI(1, "Full path: %s inode = 0x%p", full_path, direntry->d_inode); | 670 | cFYI(1, "Full path: %s inode = 0x%p", full_path, direntry->d_inode); |
562 | 671 | ||
563 | /* Posix open is only called (at lookup time) for file create now. | ||
564 | * For opens (rather than creates), because we do not know if it | ||
565 | * is a file or directory yet, and current Samba no longer allows | ||
566 | * us to do posix open on dirs, we could end up wasting an open call | ||
567 | * on what turns out to be a dir. For file opens, we wait to call posix | ||
568 | * open till cifs_open. It could be added here (lookup) in the future | ||
569 | * but the performance tradeoff of the extra network request when EISDIR | ||
570 | * or EACCES is returned would have to be weighed against the 50% | ||
571 | * reduction in network traffic in the other paths. | ||
572 | */ | ||
573 | if (pTcon->unix_ext) { | 672 | if (pTcon->unix_ext) { |
574 | if (nd && !(nd->flags & LOOKUP_DIRECTORY) && | 673 | rc = cifs_get_inode_info_unix(&newInode, full_path, |
575 | (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open && | 674 | parent_dir_inode->i_sb, xid); |
576 | (nd->intent.open.file->f_flags & O_CREAT)) { | 675 | } else { |
577 | rc = cifs_posix_open(full_path, &newInode, | ||
578 | parent_dir_inode->i_sb, | ||
579 | nd->intent.open.create_mode, | ||
580 | nd->intent.open.file->f_flags, &oplock, | ||
581 | &fileHandle, xid); | ||
582 | /* | ||
583 | * The check below works around a bug in POSIX | ||
584 | * open in samba versions 3.3.1 and earlier where | ||
585 | * open could incorrectly fail with invalid parameter. | ||
586 | * If either that or op not supported returned, follow | ||
587 | * the normal lookup. | ||
588 | */ | ||
589 | switch (rc) { | ||
590 | case 0: | ||
591 | /* | ||
592 | * The server may allow us to open things like | ||
593 | * FIFOs, but the client isn't set up to deal | ||
594 | * with that. If it's not a regular file, just | ||
595 | * close it and proceed as if it were a normal | ||
596 | * lookup. | ||
597 | */ | ||
598 | if (newInode && !S_ISREG(newInode->i_mode)) { | ||
599 | CIFSSMBClose(xid, pTcon, fileHandle); | ||
600 | break; | ||
601 | } | ||
602 | case -ENOENT: | ||
603 | posix_open = true; | ||
604 | case -EOPNOTSUPP: | ||
605 | break; | ||
606 | default: | ||
607 | pTcon->broken_posix_open = true; | ||
608 | } | ||
609 | } | ||
610 | if (!posix_open) | ||
611 | rc = cifs_get_inode_info_unix(&newInode, full_path, | ||
612 | parent_dir_inode->i_sb, xid); | ||
613 | } else | ||
614 | rc = cifs_get_inode_info(&newInode, full_path, NULL, | 676 | rc = cifs_get_inode_info(&newInode, full_path, NULL, |
615 | parent_dir_inode->i_sb, xid, NULL); | 677 | parent_dir_inode->i_sb, xid, NULL); |
678 | } | ||
616 | 679 | ||
617 | if ((rc == 0) && (newInode != NULL)) { | 680 | if ((rc == 0) && (newInode != NULL)) { |
618 | d_add(direntry, newInode); | 681 | d_add(direntry, newInode); |
619 | if (posix_open) { | ||
620 | filp = lookup_instantiate_filp(nd, direntry, | ||
621 | generic_file_open); | ||
622 | if (IS_ERR(filp)) { | ||
623 | rc = PTR_ERR(filp); | ||
624 | CIFSSMBClose(xid, pTcon, fileHandle); | ||
625 | goto lookup_out; | ||
626 | } | ||
627 | |||
628 | cfile = cifs_new_fileinfo(fileHandle, filp, tlink, | ||
629 | oplock); | ||
630 | if (cfile == NULL) { | ||
631 | fput(filp); | ||
632 | CIFSSMBClose(xid, pTcon, fileHandle); | ||
633 | rc = -ENOMEM; | ||
634 | goto lookup_out; | ||
635 | } | ||
636 | } | ||
637 | /* since paths are not looked up by component - the parent | 682 | /* since paths are not looked up by component - the parent |
638 | directories are presumed to be good here */ | 683 | directories are presumed to be good here */ |
639 | renew_parental_timestamps(direntry); | 684 | renew_parental_timestamps(direntry); |