diff options
-rw-r--r-- | fs/cifs/inode.c | 306 |
1 files changed, 139 insertions, 167 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 511c52616794..8dbc7c90309c 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -665,6 +665,101 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino) | |||
665 | return inode; | 665 | return inode; |
666 | } | 666 | } |
667 | 667 | ||
668 | static int | ||
669 | cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid, | ||
670 | char *full_path, __u32 dosattr) | ||
671 | { | ||
672 | int rc; | ||
673 | int oplock = 0; | ||
674 | __u16 netfid; | ||
675 | __u32 netpid; | ||
676 | bool set_time = false; | ||
677 | struct cifsFileInfo *open_file; | ||
678 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); | ||
679 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
680 | struct cifsTconInfo *pTcon = cifs_sb->tcon; | ||
681 | FILE_BASIC_INFO info_buf; | ||
682 | |||
683 | if (attrs->ia_valid & ATTR_ATIME) { | ||
684 | set_time = true; | ||
685 | info_buf.LastAccessTime = | ||
686 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime)); | ||
687 | } else | ||
688 | info_buf.LastAccessTime = 0; | ||
689 | |||
690 | if (attrs->ia_valid & ATTR_MTIME) { | ||
691 | set_time = true; | ||
692 | info_buf.LastWriteTime = | ||
693 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); | ||
694 | } else | ||
695 | info_buf.LastWriteTime = 0; | ||
696 | |||
697 | /* | ||
698 | * Samba throws this field away, but windows may actually use it. | ||
699 | * Do not set ctime unless other time stamps are changed explicitly | ||
700 | * (i.e. by utimes()) since we would then have a mix of client and | ||
701 | * server times. | ||
702 | */ | ||
703 | if (set_time && (attrs->ia_valid & ATTR_CTIME)) { | ||
704 | cFYI(1, ("CIFS - CTIME changed")); | ||
705 | info_buf.ChangeTime = | ||
706 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); | ||
707 | } else | ||
708 | info_buf.ChangeTime = 0; | ||
709 | |||
710 | info_buf.CreationTime = 0; /* don't change */ | ||
711 | info_buf.Attributes = cpu_to_le32(dosattr); | ||
712 | |||
713 | /* | ||
714 | * If the file is already open for write, just use that fileid | ||
715 | */ | ||
716 | open_file = find_writable_file(cifsInode); | ||
717 | if (open_file) { | ||
718 | netfid = open_file->netfid; | ||
719 | netpid = open_file->pid; | ||
720 | goto set_via_filehandle; | ||
721 | } | ||
722 | |||
723 | /* | ||
724 | * NT4 apparently returns success on this call, but it doesn't | ||
725 | * really work. | ||
726 | */ | ||
727 | if (!(pTcon->ses->flags & CIFS_SES_NT4)) { | ||
728 | rc = CIFSSMBSetPathInfo(xid, pTcon, full_path, | ||
729 | &info_buf, cifs_sb->local_nls, | ||
730 | cifs_sb->mnt_cifs_flags & | ||
731 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
732 | if (rc != -EOPNOTSUPP && rc != -EINVAL) | ||
733 | goto out; | ||
734 | } | ||
735 | |||
736 | cFYI(1, ("calling SetFileInfo since SetPathInfo for " | ||
737 | "times not supported by this server")); | ||
738 | rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, | ||
739 | SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, | ||
740 | CREATE_NOT_DIR, &netfid, &oplock, | ||
741 | NULL, cifs_sb->local_nls, | ||
742 | cifs_sb->mnt_cifs_flags & | ||
743 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
744 | |||
745 | if (rc != 0) { | ||
746 | if (rc == -EIO) | ||
747 | rc = -EINVAL; | ||
748 | goto out; | ||
749 | } | ||
750 | |||
751 | netpid = current->tgid; | ||
752 | |||
753 | set_via_filehandle: | ||
754 | rc = CIFSSMBSetFileInfo(xid, pTcon, &info_buf, netfid, netpid); | ||
755 | if (open_file == NULL) | ||
756 | CIFSSMBClose(xid, pTcon, netfid); | ||
757 | else | ||
758 | atomic_dec(&open_file->wrtPending); | ||
759 | out: | ||
760 | return rc; | ||
761 | } | ||
762 | |||
668 | int cifs_unlink(struct inode *dir, struct dentry *dentry) | 763 | int cifs_unlink(struct inode *dir, struct dentry *dentry) |
669 | { | 764 | { |
670 | int rc = 0; | 765 | int rc = 0; |
@@ -675,7 +770,8 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry) | |||
675 | struct super_block *sb = dir->i_sb; | 770 | struct super_block *sb = dir->i_sb; |
676 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 771 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
677 | struct cifsTconInfo *tcon = cifs_sb->tcon; | 772 | struct cifsTconInfo *tcon = cifs_sb->tcon; |
678 | FILE_BASIC_INFO *pinfo_buf; | 773 | struct iattr *attrs; |
774 | __u32 dosattr; | ||
679 | 775 | ||
680 | cFYI(1, ("cifs_unlink, dir=0x%p, dentry=0x%p", dir, dentry)); | 776 | cFYI(1, ("cifs_unlink, dir=0x%p, dentry=0x%p", dir, dentry)); |
681 | 777 | ||
@@ -728,84 +824,55 @@ psx_del_no_retry: | |||
728 | } | 824 | } |
729 | } else if (rc == -EACCES) { | 825 | } else if (rc == -EACCES) { |
730 | /* try only if r/o attribute set in local lookup data? */ | 826 | /* try only if r/o attribute set in local lookup data? */ |
731 | pinfo_buf = kzalloc(sizeof(FILE_BASIC_INFO), GFP_KERNEL); | 827 | attrs = kzalloc(sizeof(*attrs), GFP_KERNEL); |
732 | if (pinfo_buf) { | 828 | if (attrs == NULL) { |
733 | /* ATTRS set to normal clears r/o bit */ | 829 | rc = -ENOMEM; |
734 | pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL); | 830 | goto out_reval; |
735 | if (!(tcon->ses->flags & CIFS_SES_NT4)) | ||
736 | rc = CIFSSMBSetPathInfo(xid, tcon, full_path, | ||
737 | pinfo_buf, | ||
738 | cifs_sb->local_nls, | ||
739 | cifs_sb->mnt_cifs_flags & | ||
740 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
741 | else | ||
742 | rc = -EOPNOTSUPP; | ||
743 | |||
744 | if (rc == -EOPNOTSUPP) { | ||
745 | int oplock = 0; | ||
746 | __u16 netfid; | ||
747 | /* rc = CIFSSMBSetAttrLegacy(xid, tcon, | ||
748 | full_path, | ||
749 | (__u16)ATTR_NORMAL, | ||
750 | cifs_sb->local_nls); | ||
751 | For some strange reason it seems that NT4 eats the | ||
752 | old setattr call without actually setting the | ||
753 | attributes so on to the third attempted workaround | ||
754 | */ | ||
755 | |||
756 | /* BB could scan to see if we already have it open | ||
757 | and pass in pid of opener to function */ | ||
758 | rc = CIFSSMBOpen(xid, tcon, full_path, | ||
759 | FILE_OPEN, SYNCHRONIZE | | ||
760 | FILE_WRITE_ATTRIBUTES, 0, | ||
761 | &netfid, &oplock, NULL, | ||
762 | cifs_sb->local_nls, | ||
763 | cifs_sb->mnt_cifs_flags & | ||
764 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
765 | if (rc == 0) { | ||
766 | rc = CIFSSMBSetFileInfo(xid, tcon, | ||
767 | pinfo_buf, | ||
768 | netfid, | ||
769 | current->tgid); | ||
770 | CIFSSMBClose(xid, tcon, netfid); | ||
771 | } | ||
772 | } | ||
773 | kfree(pinfo_buf); | ||
774 | } | 831 | } |
832 | |||
833 | /* try to reset dos attributes */ | ||
834 | cifsInode = CIFS_I(inode); | ||
835 | dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY; | ||
836 | if (dosattr == 0) | ||
837 | dosattr |= ATTR_NORMAL; | ||
838 | dosattr |= ATTR_HIDDEN; | ||
839 | |||
840 | rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr); | ||
841 | kfree(attrs); | ||
842 | if (rc != 0) | ||
843 | goto out_reval; | ||
844 | rc = CIFSSMBDelFile(xid, tcon, full_path, cifs_sb->local_nls, | ||
845 | cifs_sb->mnt_cifs_flags & | ||
846 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
775 | if (rc == 0) { | 847 | if (rc == 0) { |
776 | rc = CIFSSMBDelFile(xid, tcon, full_path, | 848 | if (inode) |
777 | cifs_sb->local_nls, | 849 | drop_nlink(inode); |
778 | cifs_sb->mnt_cifs_flags & | 850 | } else if (rc == -ETXTBSY) { |
779 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 851 | int oplock = 0; |
780 | if (!rc) { | 852 | __u16 netfid; |
853 | |||
854 | rc = CIFSSMBOpen(xid, tcon, full_path, | ||
855 | FILE_OPEN, DELETE, | ||
856 | CREATE_NOT_DIR | | ||
857 | CREATE_DELETE_ON_CLOSE, | ||
858 | &netfid, &oplock, NULL, | ||
859 | cifs_sb->local_nls, | ||
860 | cifs_sb->mnt_cifs_flags & | ||
861 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
862 | if (rc == 0) { | ||
863 | CIFSSMBRenameOpenFile(xid, tcon, | ||
864 | netfid, NULL, | ||
865 | cifs_sb->local_nls, | ||
866 | cifs_sb->mnt_cifs_flags & | ||
867 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
868 | CIFSSMBClose(xid, tcon, netfid); | ||
781 | if (inode) | 869 | if (inode) |
782 | drop_nlink(inode); | 870 | drop_nlink(inode); |
783 | } else if (rc == -ETXTBSY) { | ||
784 | int oplock = 0; | ||
785 | __u16 netfid; | ||
786 | |||
787 | rc = CIFSSMBOpen(xid, tcon, full_path, | ||
788 | FILE_OPEN, DELETE, | ||
789 | CREATE_NOT_DIR | | ||
790 | CREATE_DELETE_ON_CLOSE, | ||
791 | &netfid, &oplock, NULL, | ||
792 | cifs_sb->local_nls, | ||
793 | cifs_sb->mnt_cifs_flags & | ||
794 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
795 | if (rc == 0) { | ||
796 | CIFSSMBRenameOpenFile(xid, tcon, | ||
797 | netfid, NULL, | ||
798 | cifs_sb->local_nls, | ||
799 | cifs_sb->mnt_cifs_flags & | ||
800 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
801 | CIFSSMBClose(xid, tcon, netfid); | ||
802 | if (inode) | ||
803 | drop_nlink(inode); | ||
804 | } | ||
805 | /* BB if rc = -ETXTBUSY goto the rename logic BB */ | ||
806 | } | 871 | } |
872 | /* BB if rc = -ETXTBUSY goto the rename logic BB */ | ||
807 | } | 873 | } |
808 | } | 874 | } |
875 | out_reval: | ||
809 | if (inode) { | 876 | if (inode) { |
810 | cifsInode = CIFS_I(inode); | 877 | cifsInode = CIFS_I(inode); |
811 | cifsInode->time = 0; /* will force revalidate to get info | 878 | cifsInode->time = 0; /* will force revalidate to get info |
@@ -1499,101 +1566,6 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, | |||
1499 | } | 1566 | } |
1500 | 1567 | ||
1501 | static int | 1568 | static int |
1502 | cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid, | ||
1503 | char *full_path, __u32 dosattr) | ||
1504 | { | ||
1505 | int rc; | ||
1506 | int oplock = 0; | ||
1507 | __u16 netfid; | ||
1508 | __u32 netpid; | ||
1509 | bool set_time = false; | ||
1510 | struct cifsFileInfo *open_file; | ||
1511 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); | ||
1512 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
1513 | struct cifsTconInfo *pTcon = cifs_sb->tcon; | ||
1514 | FILE_BASIC_INFO info_buf; | ||
1515 | |||
1516 | if (attrs->ia_valid & ATTR_ATIME) { | ||
1517 | set_time = true; | ||
1518 | info_buf.LastAccessTime = | ||
1519 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime)); | ||
1520 | } else | ||
1521 | info_buf.LastAccessTime = 0; | ||
1522 | |||
1523 | if (attrs->ia_valid & ATTR_MTIME) { | ||
1524 | set_time = true; | ||
1525 | info_buf.LastWriteTime = | ||
1526 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); | ||
1527 | } else | ||
1528 | info_buf.LastWriteTime = 0; | ||
1529 | |||
1530 | /* | ||
1531 | * Samba throws this field away, but windows may actually use it. | ||
1532 | * Do not set ctime unless other time stamps are changed explicitly | ||
1533 | * (i.e. by utimes()) since we would then have a mix of client and | ||
1534 | * server times. | ||
1535 | */ | ||
1536 | if (set_time && (attrs->ia_valid & ATTR_CTIME)) { | ||
1537 | cFYI(1, ("CIFS - CTIME changed")); | ||
1538 | info_buf.ChangeTime = | ||
1539 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); | ||
1540 | } else | ||
1541 | info_buf.ChangeTime = 0; | ||
1542 | |||
1543 | info_buf.CreationTime = 0; /* don't change */ | ||
1544 | info_buf.Attributes = cpu_to_le32(dosattr); | ||
1545 | |||
1546 | /* | ||
1547 | * If the file is already open for write, just use that fileid | ||
1548 | */ | ||
1549 | open_file = find_writable_file(cifsInode); | ||
1550 | if (open_file) { | ||
1551 | netfid = open_file->netfid; | ||
1552 | netpid = open_file->pid; | ||
1553 | goto set_via_filehandle; | ||
1554 | } | ||
1555 | |||
1556 | /* | ||
1557 | * NT4 apparently returns success on this call, but it doesn't | ||
1558 | * really work. | ||
1559 | */ | ||
1560 | if (!(pTcon->ses->flags & CIFS_SES_NT4)) { | ||
1561 | rc = CIFSSMBSetPathInfo(xid, pTcon, full_path, | ||
1562 | &info_buf, cifs_sb->local_nls, | ||
1563 | cifs_sb->mnt_cifs_flags & | ||
1564 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1565 | if (rc != -EOPNOTSUPP && rc != -EINVAL) | ||
1566 | goto out; | ||
1567 | } | ||
1568 | |||
1569 | cFYI(1, ("calling SetFileInfo since SetPathInfo for " | ||
1570 | "times not supported by this server")); | ||
1571 | rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, | ||
1572 | SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, | ||
1573 | CREATE_NOT_DIR, &netfid, &oplock, | ||
1574 | NULL, cifs_sb->local_nls, | ||
1575 | cifs_sb->mnt_cifs_flags & | ||
1576 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1577 | |||
1578 | if (rc != 0) { | ||
1579 | if (rc == -EIO) | ||
1580 | rc = -EINVAL; | ||
1581 | goto out; | ||
1582 | } | ||
1583 | |||
1584 | netpid = current->tgid; | ||
1585 | |||
1586 | set_via_filehandle: | ||
1587 | rc = CIFSSMBSetFileInfo(xid, pTcon, &info_buf, netfid, netpid); | ||
1588 | if (open_file == NULL) | ||
1589 | CIFSSMBClose(xid, pTcon, netfid); | ||
1590 | else | ||
1591 | atomic_dec(&open_file->wrtPending); | ||
1592 | out: | ||
1593 | return rc; | ||
1594 | } | ||
1595 | |||
1596 | static int | ||
1597 | cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | 1569 | cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) |
1598 | { | 1570 | { |
1599 | int rc; | 1571 | int rc; |