summaryrefslogtreecommitdiffstats
path: root/fs/cifs/dir.c
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2012-06-05 09:10:23 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-07-14 08:33:15 -0400
commitd2c127197dfc0b2bae62a52e1e0d3e3ff493919e (patch)
tree75a30530499790ace8af09f9442f111f59564647 /fs/cifs/dir.c
parentc8ccbe032feb127a977c66865cb63d72d9a6e08b (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.c441
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 */
140static int
141check_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
138int 160static int cifs_do_create(struct inode *inode, struct dentry *direntry,
139cifs_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
323cifs_create_set_dentry: 357cifs_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); 373out:
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); 379struct file *
341 if (pfile_info == NULL) { 380cifs_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
350cifs_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
449out:
450 cifs_put_tlink(tlink);
451free_xid:
452 FreeXid(xid);
453 return filp;
454}
455
456int 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);
488free_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);