aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2008-05-20 17:52:32 -0400
committerSteve French <sfrench@us.ibm.com>2008-05-20 17:52:32 -0400
commitb9a3260f25ab5d2ba5c8b9508e7952848b9d704b (patch)
tree2c50578e713b4b519635a13cc568bae86729d17e /fs/cifs
parent0e4bbde94fdc33f5b3d793166b21bf768ca3e098 (diff)
[CIFS] Enable DFS support for Windows query path info
Final piece for handling DFS in query_path_info, constructing a fake inode for the junction directory which the submount will cover. This handles the non-Unix (Windows etc.) code path. Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/inode.c324
1 files changed, 178 insertions, 146 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 422d4e219fa4..1cf43e101943 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -161,6 +161,12 @@ static void cifs_unix_info_to_inode(struct inode *inode,
161 spin_unlock(&inode->i_lock); 161 spin_unlock(&inode->i_lock);
162} 162}
163 163
164
165/*
166 * Needed to setup inode data for the directory which is the
167 * junction to the new submount (ie to setup the fake directory
168 * which represents a DFS referral)
169 */
164static void fill_fake_finddataunix(FILE_UNIX_BASIC_INFO *pfnd_dat, 170static void fill_fake_finddataunix(FILE_UNIX_BASIC_INFO *pfnd_dat,
165 struct super_block *sb) 171 struct super_block *sb)
166{ 172{
@@ -370,11 +376,42 @@ static int get_sfu_mode(struct inode *inode,
370#endif 376#endif
371} 377}
372 378
379/*
380 * Needed to setup inode data for the directory which is the
381 * junction to the new submount (ie to setup the fake directory
382 * which represents a DFS referral)
383 */
384static void fill_fake_finddata(FILE_ALL_INFO *pfnd_dat,
385 struct super_block *sb)
386{
387 memset(pfnd_dat, sizeof(FILE_ALL_INFO), 0);
388
389/* __le64 pfnd_dat->AllocationSize = cpu_to_le64(0);
390 __le64 pfnd_dat->EndOfFile = cpu_to_le64(0);
391 __u8 pfnd_dat->DeletePending = 0;
392 __u8 pfnd_data->Directory = 0;
393 __le32 pfnd_dat->EASize = 0;
394 __u64 pfnd_dat->IndexNumber = 0;
395 __u64 pfnd_dat->IndexNumber1 = 0; */
396 pfnd_dat->CreationTime =
397 cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
398 pfnd_dat->LastAccessTime =
399 cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
400 pfnd_dat->LastWriteTime =
401 cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
402 pfnd_dat->ChangeTime =
403 cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
404 pfnd_dat->Attributes = cpu_to_le32(ATTR_DIRECTORY);
405 pfnd_dat->NumberOfLinks = cpu_to_le32(2);
406}
407
373int cifs_get_inode_info(struct inode **pinode, 408int cifs_get_inode_info(struct inode **pinode,
374 const unsigned char *full_path, FILE_ALL_INFO *pfindData, 409 const unsigned char *full_path, FILE_ALL_INFO *pfindData,
375 struct super_block *sb, int xid, const __u16 *pfid) 410 struct super_block *sb, int xid, const __u16 *pfid)
376{ 411{
377 int rc = 0; 412 int rc = 0;
413 __u32 attr;
414 struct cifsInodeInfo *cifsInfo;
378 struct cifsTconInfo *pTcon; 415 struct cifsTconInfo *pTcon;
379 struct inode *inode; 416 struct inode *inode;
380 struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 417 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
@@ -399,7 +436,6 @@ int cifs_get_inode_info(struct inode **pinode,
399 return -ENOMEM; 436 return -ENOMEM;
400 pfindData = (FILE_ALL_INFO *)buf; 437 pfindData = (FILE_ALL_INFO *)buf;
401 438
402try_again_CIFSSMBQPathInfo:
403 /* could do find first instead but this returns more info */ 439 /* could do find first instead but this returns more info */
404 rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData, 440 rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData,
405 0 /* not legacy */, 441 0 /* not legacy */,
@@ -417,171 +453,167 @@ try_again_CIFSSMBQPathInfo:
417 } 453 }
418 } 454 }
419 /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ 455 /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
420 if (rc) { 456 if (rc == -EREMOTE) {
421 if (rc == -EREMOTE && !is_dfs_referral) { 457 is_dfs_referral = true;
422 is_dfs_referral = true; 458 fill_fake_finddata(pfindData, sb);
423 goto try_again_CIFSSMBQPathInfo; 459 rc = 0;
424 } 460 } else if (rc)
425 goto cgii_exit; 461 goto cgii_exit;
426 } else {
427 struct cifsInodeInfo *cifsInfo;
428 __u32 attr = le32_to_cpu(pfindData->Attributes);
429 462
430 /* get new inode */ 463 attr = le32_to_cpu(pfindData->Attributes);
464
465 /* get new inode */
466 if (*pinode == NULL) {
467 *pinode = new_inode(sb);
431 if (*pinode == NULL) { 468 if (*pinode == NULL) {
432 *pinode = new_inode(sb); 469 rc = -ENOMEM;
433 if (*pinode == NULL) { 470 goto cgii_exit;
434 rc = -ENOMEM; 471 }
435 goto cgii_exit; 472 /* Is an i_ino of zero legal? Can we use that to check
436 } 473 if the server supports returning inode numbers? Are
437 /* Is an i_ino of zero legal? Can we use that to check 474 there other sanity checks we can use to ensure that
438 if the server supports returning inode numbers? Are 475 the server is really filling in that field? */
439 there other sanity checks we can use to ensure that
440 the server is really filling in that field? */
441 476
442 /* We can not use the IndexNumber field by default from 477 /* We can not use the IndexNumber field by default from
443 Windows or Samba (in ALL_INFO buf) but we can request 478 Windows or Samba (in ALL_INFO buf) but we can request
444 it explicitly. It may not be unique presumably if 479 it explicitly. It may not be unique presumably if
445 the server has multiple devices mounted under one 480 the server has multiple devices mounted under one share */
446 share */
447 481
448 /* There may be higher info levels that work but are 482 /* There may be higher info levels that work but are
449 there Windows server or network appliances for which 483 there Windows server or network appliances for which
450 IndexNumber field is not guaranteed unique? */ 484 IndexNumber field is not guaranteed unique? */
451 485
452 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { 486 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
453 int rc1 = 0; 487 int rc1 = 0;
454 __u64 inode_num; 488 __u64 inode_num;
455 489
456 rc1 = CIFSGetSrvInodeNumber(xid, pTcon, 490 rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
457 full_path, &inode_num, 491 full_path, &inode_num,
458 cifs_sb->local_nls, 492 cifs_sb->local_nls,
459 cifs_sb->mnt_cifs_flags & 493 cifs_sb->mnt_cifs_flags &
460 CIFS_MOUNT_MAP_SPECIAL_CHR); 494 CIFS_MOUNT_MAP_SPECIAL_CHR);
461 if (rc1) { 495 if (rc1) {
462 cFYI(1, ("GetSrvInodeNum rc %d", rc1)); 496 cFYI(1, ("GetSrvInodeNum rc %d", rc1));
463 /* BB EOPNOSUPP disable SERVER_INUM? */ 497 /* BB EOPNOSUPP disable SERVER_INUM? */
464 } else /* do we need cast or hash to ino? */ 498 } else /* do we need cast or hash to ino? */
465 (*pinode)->i_ino = inode_num; 499 (*pinode)->i_ino = inode_num;
466 } /* else ino incremented to unique num in new_inode*/ 500 } /* else ino incremented to unique num in new_inode*/
467 if (sb->s_flags & MS_NOATIME) 501 if (sb->s_flags & MS_NOATIME)
468 (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME; 502 (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
469 insert_inode_hash(*pinode); 503 insert_inode_hash(*pinode);
470 } 504 }
471 inode = *pinode; 505 inode = *pinode;
472 cifsInfo = CIFS_I(inode); 506 cifsInfo = CIFS_I(inode);
473 cifsInfo->cifsAttrs = attr; 507 cifsInfo->cifsAttrs = attr;
474 cFYI(1, ("Old time %ld", cifsInfo->time)); 508 cFYI(1, ("Old time %ld", cifsInfo->time));
475 cifsInfo->time = jiffies; 509 cifsInfo->time = jiffies;
476 cFYI(1, ("New time %ld", cifsInfo->time)); 510 cFYI(1, ("New time %ld", cifsInfo->time));
477 511
478 /* blksize needs to be multiple of two. So safer to default to 512 /* blksize needs to be multiple of two. So safer to default to
479 blksize and blkbits set in superblock so 2**blkbits and blksize 513 blksize and blkbits set in superblock so 2**blkbits and blksize
480 will match rather than setting to: 514 will match rather than setting to:
481 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ 515 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
482 516
483 /* Linux can not store file creation time so ignore it */ 517 /* Linux can not store file creation time so ignore it */
484 if (pfindData->LastAccessTime) 518 if (pfindData->LastAccessTime)
485 inode->i_atime = cifs_NTtimeToUnix 519 inode->i_atime = cifs_NTtimeToUnix
486 (le64_to_cpu(pfindData->LastAccessTime)); 520 (le64_to_cpu(pfindData->LastAccessTime));
487 else /* do not need to use current_fs_time - time not stored */ 521 else /* do not need to use current_fs_time - time not stored */
488 inode->i_atime = CURRENT_TIME; 522 inode->i_atime = CURRENT_TIME;
489 inode->i_mtime = 523 inode->i_mtime =
490 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); 524 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
491 inode->i_ctime = 525 inode->i_ctime =
492 cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); 526 cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
493 cFYI(0, ("Attributes came in as 0x%x", attr)); 527 cFYI(DBG2, ("Attributes came in as 0x%x", attr));
494 if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) { 528 if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) {
495 inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj; 529 inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj;
496 inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj; 530 inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj;
497 } 531 }
498 532
499 /* set default mode. will override for dirs below */ 533 /* set default mode. will override for dirs below */
500 if (atomic_read(&cifsInfo->inUse) == 0) 534 if (atomic_read(&cifsInfo->inUse) == 0)
501 /* new inode, can safely set these fields */ 535 /* new inode, can safely set these fields */
502 inode->i_mode = cifs_sb->mnt_file_mode; 536 inode->i_mode = cifs_sb->mnt_file_mode;
503 else /* since we set the inode type below we need to mask off 537 else /* since we set the inode type below we need to mask off
504 to avoid strange results if type changes and both 538 to avoid strange results if type changes and both
505 get orred in */ 539 get orred in */
506 inode->i_mode &= ~S_IFMT; 540 inode->i_mode &= ~S_IFMT;
507/* if (attr & ATTR_REPARSE) */ 541/* if (attr & ATTR_REPARSE) */
508 /* We no longer handle these as symlinks because we could not 542 /* We no longer handle these as symlinks because we could not
509 follow them due to the absolute path with drive letter */ 543 follow them due to the absolute path with drive letter */
510 if (attr & ATTR_DIRECTORY) { 544 if (attr & ATTR_DIRECTORY) {
511 /* override default perms since we do not do byte range locking 545 /* override default perms since we do not do byte range locking
512 on dirs */ 546 on dirs */
513 inode->i_mode = cifs_sb->mnt_dir_mode; 547 inode->i_mode = cifs_sb->mnt_dir_mode;
514 inode->i_mode |= S_IFDIR; 548 inode->i_mode |= S_IFDIR;
515 } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && 549 } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
516 (cifsInfo->cifsAttrs & ATTR_SYSTEM) && 550 (cifsInfo->cifsAttrs & ATTR_SYSTEM) &&
517 /* No need to le64 convert size of zero */ 551 /* No need to le64 convert size of zero */
518 (pfindData->EndOfFile == 0)) { 552 (pfindData->EndOfFile == 0)) {
519 inode->i_mode = cifs_sb->mnt_file_mode; 553 inode->i_mode = cifs_sb->mnt_file_mode;
520 inode->i_mode |= S_IFIFO; 554 inode->i_mode |= S_IFIFO;
521/* BB Finish for SFU style symlinks and devices */ 555/* BB Finish for SFU style symlinks and devices */
522 } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && 556 } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
523 (cifsInfo->cifsAttrs & ATTR_SYSTEM)) { 557 (cifsInfo->cifsAttrs & ATTR_SYSTEM)) {
524 if (decode_sfu_inode(inode, 558 if (decode_sfu_inode(inode, le64_to_cpu(pfindData->EndOfFile),
525 le64_to_cpu(pfindData->EndOfFile), 559 full_path, cifs_sb, xid))
526 full_path, 560 cFYI(1, ("Unrecognized sfu inode type"));
527 cifs_sb, xid))
528 cFYI(1, ("Unrecognized sfu inode type"));
529
530 cFYI(1, ("sfu mode 0%o", inode->i_mode));
531 } else {
532 inode->i_mode |= S_IFREG;
533 /* treat the dos attribute of read-only as read-only
534 mode e.g. 555 */
535 if (cifsInfo->cifsAttrs & ATTR_READONLY)
536 inode->i_mode &= ~(S_IWUGO);
537 else if ((inode->i_mode & S_IWUGO) == 0)
538 /* the ATTR_READONLY flag may have been */
539 /* changed on server -- set any w bits */
540 /* allowed by mnt_file_mode */
541 inode->i_mode |= (S_IWUGO &
542 cifs_sb->mnt_file_mode);
543 /* BB add code here -
544 validate if device or weird share or device type? */
545 }
546 561
547 spin_lock(&inode->i_lock); 562 cFYI(1, ("sfu mode 0%o", inode->i_mode));
548 if (is_size_safe_to_change(cifsInfo, 563 } else {
549 le64_to_cpu(pfindData->EndOfFile))) { 564 inode->i_mode |= S_IFREG;
550 /* can not safely shrink the file size here if the 565 /* treat dos attribute of read-only as read-only mode eg 555 */
551 client is writing to it due to potential races */ 566 if (cifsInfo->cifsAttrs & ATTR_READONLY)
552 i_size_write(inode, le64_to_cpu(pfindData->EndOfFile)); 567 inode->i_mode &= ~(S_IWUGO);
553 568 else if ((inode->i_mode & S_IWUGO) == 0)
554 /* 512 bytes (2**9) is the fake blocksize that must be 569 /* the ATTR_READONLY flag may have been */
555 used for this calculation */ 570 /* changed on server -- set any w bits */
556 inode->i_blocks = (512 - 1 + le64_to_cpu( 571 /* allowed by mnt_file_mode */
557 pfindData->AllocationSize)) >> 9; 572 inode->i_mode |= (S_IWUGO & cifs_sb->mnt_file_mode);
558 } 573 /* BB add code to validate if device or weird share or device type? */
559 spin_unlock(&inode->i_lock); 574 }
575
576 spin_lock(&inode->i_lock);
577 if (is_size_safe_to_change(cifsInfo,
578 le64_to_cpu(pfindData->EndOfFile))) {
579 /* can not safely shrink the file size here if the
580 client is writing to it due to potential races */
581 i_size_write(inode, le64_to_cpu(pfindData->EndOfFile));
582
583 /* 512 bytes (2**9) is the fake blocksize that must be
584 used for this calculation */
585 inode->i_blocks = (512 - 1 + le64_to_cpu(
586 pfindData->AllocationSize)) >> 9;
587 }
588 spin_unlock(&inode->i_lock);
560 589
561 inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks); 590 inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
562 591
563 /* BB fill in uid and gid here? with help from winbind? 592 /* BB fill in uid and gid here? with help from winbind?
564 or retrieve from NTFS stream extended attribute */ 593 or retrieve from NTFS stream extended attribute */
565#ifdef CONFIG_CIFS_EXPERIMENTAL 594#ifdef CONFIG_CIFS_EXPERIMENTAL
566 /* fill in 0777 bits from ACL */ 595 /* fill in 0777 bits from ACL */
567 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { 596 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
568 cFYI(1, ("Getting mode bits from ACL")); 597 cFYI(1, ("Getting mode bits from ACL"));
569 acl_to_uid_mode(inode, full_path, pfid); 598 acl_to_uid_mode(inode, full_path, pfid);
570 } 599 }
571#endif 600#endif
572 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { 601 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
573 /* fill in remaining high mode bits e.g. SUID, VTX */ 602 /* fill in remaining high mode bits e.g. SUID, VTX */
574 get_sfu_mode(inode, full_path, cifs_sb, xid); 603 get_sfu_mode(inode, full_path, cifs_sb, xid);
575 } else if (atomic_read(&cifsInfo->inUse) == 0) { 604 } else if (atomic_read(&cifsInfo->inUse) == 0) {
576 inode->i_uid = cifs_sb->mnt_uid; 605 inode->i_uid = cifs_sb->mnt_uid;
577 inode->i_gid = cifs_sb->mnt_gid; 606 inode->i_gid = cifs_sb->mnt_gid;
578 /* set so we do not keep refreshing these fields with 607 /* set so we do not keep refreshing these fields with
579 bad data after user has changed them in memory */ 608 bad data after user has changed them in memory */
580 atomic_set(&cifsInfo->inUse, 1); 609 atomic_set(&cifsInfo->inUse, 1);
581 }
582
583 cifs_set_ops(inode, is_dfs_referral);
584 } 610 }
611
612 cifs_set_ops(inode, is_dfs_referral);
613
614
615
616
585cgii_exit: 617cgii_exit:
586 kfree(buf); 618 kfree(buf);
587 return rc; 619 return rc;