diff options
author | Steve French <sfrench@us.ibm.com> | 2007-04-23 18:07:35 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2007-04-23 18:07:35 -0400 |
commit | 2dd29d3133ad4c7926ea03b8431e604373c4ad65 (patch) | |
tree | 67865fc39bc4095fee16b6a6329c778360d51945 /fs/cifs/inode.c | |
parent | 5268df2ead6def933ace27ab4d46f67d2989b905 (diff) |
[CIFS] New CIFS POSIX mkdir performance improvement
Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs/inode.c')
-rw-r--r-- | fs/cifs/inode.c | 184 |
1 files changed, 181 insertions, 3 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index eeea33752e68..9b7e0dbdd826 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * fs/cifs/inode.c | 2 | * fs/cifs/inode.c |
3 | * | 3 | * |
4 | * Copyright (C) International Business Machines Corp., 2002,2005 | 4 | * Copyright (C) International Business Machines Corp., 2002,2007 |
5 | * Author(s): Steve French (sfrench@us.ibm.com) | 5 | * Author(s): Steve French (sfrench@us.ibm.com) |
6 | * | 6 | * |
7 | * This library is free software; you can redistribute it and/or modify | 7 | * This library is free software; you can redistribute it and/or modify |
@@ -734,6 +734,133 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) | |||
734 | return rc; | 734 | return rc; |
735 | } | 735 | } |
736 | 736 | ||
737 | static void posix_fill_in_inode(struct inode *tmp_inode, | ||
738 | FILE_UNIX_BASIC_INFO *pData, int *pobject_type, int isNewInode) | ||
739 | { | ||
740 | loff_t local_size; | ||
741 | struct timespec local_mtime; | ||
742 | |||
743 | struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); | ||
744 | struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); | ||
745 | |||
746 | __u32 type = le32_to_cpu(pData->Type); | ||
747 | __u64 num_of_bytes = le64_to_cpu(pData->NumOfBytes); | ||
748 | __u64 end_of_file = le64_to_cpu(pData->EndOfFile); | ||
749 | cifsInfo->time = jiffies; | ||
750 | atomic_inc(&cifsInfo->inUse); | ||
751 | |||
752 | /* save mtime and size */ | ||
753 | local_mtime = tmp_inode->i_mtime; | ||
754 | local_size = tmp_inode->i_size; | ||
755 | |||
756 | tmp_inode->i_atime = | ||
757 | cifs_NTtimeToUnix(le64_to_cpu(pData->LastAccessTime)); | ||
758 | tmp_inode->i_mtime = | ||
759 | cifs_NTtimeToUnix(le64_to_cpu(pData->LastModificationTime)); | ||
760 | tmp_inode->i_ctime = | ||
761 | cifs_NTtimeToUnix(le64_to_cpu(pData->LastStatusChange)); | ||
762 | |||
763 | tmp_inode->i_mode = le64_to_cpu(pData->Permissions); | ||
764 | /* since we set the inode type below we need to mask off type | ||
765 | to avoid strange results if bits above were corrupt */ | ||
766 | tmp_inode->i_mode &= ~S_IFMT; | ||
767 | if (type == UNIX_FILE) { | ||
768 | *pobject_type = DT_REG; | ||
769 | tmp_inode->i_mode |= S_IFREG; | ||
770 | } else if (type == UNIX_SYMLINK) { | ||
771 | *pobject_type = DT_LNK; | ||
772 | tmp_inode->i_mode |= S_IFLNK; | ||
773 | } else if (type == UNIX_DIR) { | ||
774 | *pobject_type = DT_DIR; | ||
775 | tmp_inode->i_mode |= S_IFDIR; | ||
776 | } else if (type == UNIX_CHARDEV) { | ||
777 | *pobject_type = DT_CHR; | ||
778 | tmp_inode->i_mode |= S_IFCHR; | ||
779 | tmp_inode->i_rdev = MKDEV(le64_to_cpu(pData->DevMajor), | ||
780 | le64_to_cpu(pData->DevMinor) & MINORMASK); | ||
781 | } else if (type == UNIX_BLOCKDEV) { | ||
782 | *pobject_type = DT_BLK; | ||
783 | tmp_inode->i_mode |= S_IFBLK; | ||
784 | tmp_inode->i_rdev = MKDEV(le64_to_cpu(pData->DevMajor), | ||
785 | le64_to_cpu(pData->DevMinor) & MINORMASK); | ||
786 | } else if (type == UNIX_FIFO) { | ||
787 | *pobject_type = DT_FIFO; | ||
788 | tmp_inode->i_mode |= S_IFIFO; | ||
789 | } else if (type == UNIX_SOCKET) { | ||
790 | *pobject_type = DT_SOCK; | ||
791 | tmp_inode->i_mode |= S_IFSOCK; | ||
792 | } else { | ||
793 | /* safest to just call it a file */ | ||
794 | *pobject_type = DT_REG; | ||
795 | tmp_inode->i_mode |= S_IFREG; | ||
796 | cFYI(1,("unknown inode type %d",type)); | ||
797 | } | ||
798 | |||
799 | tmp_inode->i_uid = le64_to_cpu(pData->Uid); | ||
800 | tmp_inode->i_gid = le64_to_cpu(pData->Gid); | ||
801 | tmp_inode->i_nlink = le64_to_cpu(pData->Nlinks); | ||
802 | |||
803 | spin_lock(&tmp_inode->i_lock); | ||
804 | if (is_size_safe_to_change(cifsInfo, end_of_file)) { | ||
805 | /* can not safely change the file size here if the | ||
806 | client is writing to it due to potential races */ | ||
807 | i_size_write(tmp_inode, end_of_file); | ||
808 | |||
809 | /* 512 bytes (2**9) is the fake blocksize that must be used */ | ||
810 | /* for this calculation, not the real blocksize */ | ||
811 | tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9; | ||
812 | } | ||
813 | spin_unlock(&tmp_inode->i_lock); | ||
814 | |||
815 | if (S_ISREG(tmp_inode->i_mode)) { | ||
816 | cFYI(1, ("File inode")); | ||
817 | tmp_inode->i_op = &cifs_file_inode_ops; | ||
818 | |||
819 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { | ||
820 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
821 | tmp_inode->i_fop = &cifs_file_direct_nobrl_ops; | ||
822 | else | ||
823 | tmp_inode->i_fop = &cifs_file_direct_ops; | ||
824 | |||
825 | } else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
826 | tmp_inode->i_fop = &cifs_file_nobrl_ops; | ||
827 | else | ||
828 | tmp_inode->i_fop = &cifs_file_ops; | ||
829 | |||
830 | if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && | ||
831 | (cifs_sb->tcon->ses->server->maxBuf < | ||
832 | PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)) | ||
833 | tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf; | ||
834 | else | ||
835 | tmp_inode->i_data.a_ops = &cifs_addr_ops; | ||
836 | |||
837 | if(isNewInode) | ||
838 | return; /* No sense invalidating pages for new inode since we | ||
839 | have not started caching readahead file data yet */ | ||
840 | |||
841 | if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && | ||
842 | (local_size == tmp_inode->i_size)) { | ||
843 | cFYI(1, ("inode exists but unchanged")); | ||
844 | } else { | ||
845 | /* file may have changed on server */ | ||
846 | cFYI(1, ("invalidate inode, readdir detected change")); | ||
847 | invalidate_remote_inode(tmp_inode); | ||
848 | } | ||
849 | } else if (S_ISDIR(tmp_inode->i_mode)) { | ||
850 | cFYI(1, ("Directory inode")); | ||
851 | tmp_inode->i_op = &cifs_dir_inode_ops; | ||
852 | tmp_inode->i_fop = &cifs_dir_ops; | ||
853 | } else if (S_ISLNK(tmp_inode->i_mode)) { | ||
854 | cFYI(1, ("Symbolic Link inode")); | ||
855 | tmp_inode->i_op = &cifs_symlink_inode_ops; | ||
856 | /* tmp_inode->i_fop = *//* do not need to set to anything */ | ||
857 | } else { | ||
858 | cFYI(1, ("Special inode")); | ||
859 | init_special_inode(tmp_inode, tmp_inode->i_mode, | ||
860 | tmp_inode->i_rdev); | ||
861 | } | ||
862 | } | ||
863 | |||
737 | int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | 864 | int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) |
738 | { | 865 | { |
739 | int rc = 0; | 866 | int rc = 0; |
@@ -755,6 +882,53 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | |||
755 | FreeXid(xid); | 882 | FreeXid(xid); |
756 | return -ENOMEM; | 883 | return -ENOMEM; |
757 | } | 884 | } |
885 | |||
886 | if((pTcon->ses->capabilities & CAP_UNIX) && | ||
887 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & | ||
888 | le64_to_cpu(pTcon->fsUnixInfo.Capability))) { | ||
889 | u32 oplock = 0; | ||
890 | FILE_UNIX_BASIC_INFO * pInfo = | ||
891 | kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); | ||
892 | if(pInfo == NULL) { | ||
893 | rc = -ENOMEM; | ||
894 | goto mkdir_out; | ||
895 | } | ||
896 | |||
897 | rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT, | ||
898 | mode, NULL /* netfid */, pInfo, &oplock, | ||
899 | full_path, cifs_sb->local_nls, | ||
900 | cifs_sb->mnt_cifs_flags & | ||
901 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
902 | if (rc) { | ||
903 | cFYI(1, ("posix mkdir returned 0x%x", rc)); | ||
904 | d_drop(direntry); | ||
905 | } else { | ||
906 | if (pInfo->Type == -1) /* no return info - go query */ | ||
907 | goto mkdir_get_info; | ||
908 | /*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need to set uid/gid */ | ||
909 | inc_nlink(inode); | ||
910 | if (pTcon->nocase) | ||
911 | direntry->d_op = &cifs_ci_dentry_ops; | ||
912 | else | ||
913 | direntry->d_op = &cifs_dentry_ops; | ||
914 | d_instantiate(direntry, newinode); | ||
915 | if (direntry->d_inode) { | ||
916 | int obj_type; | ||
917 | direntry->d_inode->i_nlink = 2; | ||
918 | /* already checked in POSIXCreate whether | ||
919 | frame was long enough */ | ||
920 | posix_fill_in_inode(direntry->d_inode, | ||
921 | pInfo, &obj_type, 1 /* NewInode */); | ||
922 | /* could double check that we actually | ||
923 | * created what we thought we did ie | ||
924 | * a directory | ||
925 | */ | ||
926 | } | ||
927 | } | ||
928 | kfree(pInfo); | ||
929 | goto mkdir_out; | ||
930 | } | ||
931 | |||
758 | /* BB add setting the equivalent of mode via CreateX w/ACLs */ | 932 | /* BB add setting the equivalent of mode via CreateX w/ACLs */ |
759 | rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls, | 933 | rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls, |
760 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 934 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
@@ -762,6 +936,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | |||
762 | cFYI(1, ("cifs_mkdir returned 0x%x", rc)); | 936 | cFYI(1, ("cifs_mkdir returned 0x%x", rc)); |
763 | d_drop(direntry); | 937 | d_drop(direntry); |
764 | } else { | 938 | } else { |
939 | mkdir_get_info: | ||
765 | inc_nlink(inode); | 940 | inc_nlink(inode); |
766 | if (pTcon->ses->capabilities & CAP_UNIX) | 941 | if (pTcon->ses->capabilities & CAP_UNIX) |
767 | rc = cifs_get_inode_info_unix(&newinode, full_path, | 942 | rc = cifs_get_inode_info_unix(&newinode, full_path, |
@@ -775,8 +950,10 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | |||
775 | else | 950 | else |
776 | direntry->d_op = &cifs_dentry_ops; | 951 | direntry->d_op = &cifs_dentry_ops; |
777 | d_instantiate(direntry, newinode); | 952 | d_instantiate(direntry, newinode); |
778 | if (direntry->d_inode) | 953 | /* setting nlink not necessary except in cases where we |
779 | direntry->d_inode->i_nlink = 2; | 954 | * failed to get it from the server or was set bogus */ |
955 | if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2)) | ||
956 | direntry->d_inode->i_nlink = 2; | ||
780 | if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) | 957 | if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) |
781 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { | 958 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { |
782 | CIFSSMBUnixSetPerms(xid, pTcon, full_path, | 959 | CIFSSMBUnixSetPerms(xid, pTcon, full_path, |
@@ -812,6 +989,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | |||
812 | } | 989 | } |
813 | } | 990 | } |
814 | } | 991 | } |
992 | mkdir_out: | ||
815 | kfree(full_path); | 993 | kfree(full_path); |
816 | FreeXid(xid); | 994 | FreeXid(xid); |
817 | return rc; | 995 | return rc; |