From patchwork Wed May 27 12:30:27 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Layton X-Patchwork-Id: 26451 Received: from lists.samba.org (mail.samba.org [66.70.73.150]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n4RCW0vq032762 for ; Wed, 27 May 2009 12:32:00 GMT Received: from dp.samba.org (localhost [127.0.0.1]) by lists.samba.org (Postfix) with ESMTP id 68071163CF9 for ; Wed, 27 May 2009 12:31:30 +0000 (GMT) X-Spam-Checker-Version: SpamAssassin 3.1.7 (2006-10-05) on dp.samba.org X-Spam-Level: X-Spam-Status: No, score=-3.8 required=3.8 tests=AWL,BAYES_00, FORGED_RCVD_HELO,SPF_HELO_PASS,SPF_PASS autolearn=ham version=3.1.7 X-Original-To: linux-cifs-client@lists.samba.org Delivered-To: linux-cifs-client@lists.samba.org Received: from mx2.redhat.com (mx2.redhat.com [66.187.237.31]) by lists.samba.org (Postfix) with ESMTP id 9755E163C23 for ; Wed, 27 May 2009 12:30:10 +0000 (GMT) Received: from int-mx2.corp.redhat.com (int-mx2.corp.redhat.com [172.16.27.26]) by mx2.redhat.com (8.13.8/8.13.8) with ESMTP id n4RCUdvO003568; Wed, 27 May 2009 08:30:39 -0400 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx2.corp.redhat.com (8.13.1/8.13.1) with ESMTP id n4RCUdUM017824; Wed, 27 May 2009 08:30:39 -0400 Received: from localhost.localdomain (vpn-12-95.rdu.redhat.com [10.11.12.95]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id n4RCUY8D003374; Wed, 27 May 2009 08:30:38 -0400 From: Jeff Layton To: linux-cifs-client@lists.samba.org Date: Wed, 27 May 2009 08:30:27 -0400 Message-Id: <1243427434-6498-7-git-send-email-jlayton@redhat.com> In-Reply-To: <1243427434-6498-1-git-send-email-jlayton@redhat.com> References: <1243427434-6498-1-git-send-email-jlayton@redhat.com> X-Scanned-By: MIMEDefang 2.58 on 172.16.27.26 Cc: linux-fsdevel@vger.kernel.org Subject: [linux-cifs-client] [PATCH 06/13] cifs: add new cifs_iget function and convert unix codepath to use it X-BeenThere: linux-cifs-client@lists.samba.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: The Linux CIFS VFS client List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-cifs-client-bounces+patchwork-cifs-client=patchwork.kernel.org@lists.samba.org Errors-To: linux-cifs-client-bounces+patchwork-cifs-client=patchwork.kernel.org@lists.samba.org In order to unify some codepaths, introduce a common cifs_fattr struct for storing inode attributes. The different codepaths (unix, legacy, normal, etc...) can fill out this struct with inode info. It can then be passed as an arg to a common set of routines to get and update inodes. Add a new cifs_iget function that uses iget5_locked to identify inodes. This will compare inodes based on the uniqueid value in a cifs_fattr struct. Rather than filling out an already-created inode, have cifs_get_inode_info_unix instead fill out cifs_fattr and hand that off to cifs_iget. cifs_iget can then properly look for hardlinked inodes. With this, we should then have proper hardlink detection and can eventually get rid of some nasty CIFS-specific hacks for handing them. Fixing the unix readdir codepath will be done in a later patch. Signed-off-by: Jeff Layton Reviewed-by: Christoph Hellwig --- fs/cifs/cifsfs.h | 13 ++ fs/cifs/cifsglob.h | 25 ++++ fs/cifs/cifsproto.h | 9 +- fs/cifs/dir.c | 22 ++-- fs/cifs/inode.c | 380 ++++++++++++++++++++++++++------------------------- 5 files changed, 248 insertions(+), 201 deletions(-) diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 3b6a85c..029ed69 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -24,6 +24,19 @@ #define ROOT_I 2 +/* + * ino_t is 32-bits on 32-bit arch. We have to squash the 64-bit value down + * so that it will fit. + */ +static inline ino_t +cifs_uniqueid_to_ino_t(u64 fileid) +{ + ino_t ino = (ino_t) fileid; + if (sizeof(ino_t) < sizeof(u64)) + ino ^= fileid >> (sizeof(u64)-sizeof(ino_t)) * 8; + return ino; +} + extern struct file_system_type cifs_fs_type; extern const struct address_space_operations cifs_addr_ops; extern const struct address_space_operations cifs_addr_ops_smallbuf; diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index a61ab77..966211b 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -371,6 +371,7 @@ struct cifsInodeInfo { bool oplockPending:1; bool delete_pending:1; /* DELETE_ON_CLOSE is set */ u64 server_eof; /* current file size on server */ + u64 uniqueid; /* server inode number */ struct inode vfs_inode; }; @@ -472,6 +473,30 @@ struct dfs_info3_param { char *node_name; }; +/* + * common struct for holding inode info when searching for or updating an + * inode with new info + */ + +#define CIFS_FATTR_DFS_REFERRAL 0x1 + +struct cifs_fattr { + u32 cf_flags; + u32 cf_cifsattrs; + u64 cf_uniqueid; + u64 cf_eof; + u64 cf_bytes; + uid_t cf_uid; + gid_t cf_gid; + umode_t cf_mode; + dev_t cf_rdev; + unsigned int cf_nlink; + unsigned int cf_dtype; + struct timespec cf_atime; + struct timespec cf_mtime; + struct timespec cf_ctime; +}; + static inline void free_dfs_info_param(struct dfs_info3_param *param) { if (param) { diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index f945232..69c4076 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -98,9 +98,14 @@ extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, extern int cifs_posix_open(char *full_path, struct inode **pinode, struct super_block *sb, int mode, int oflags, int *poplock, __u16 *pnetfid, int xid); -extern void posix_fill_in_inode(struct inode *tmp_inode, - FILE_UNIX_BASIC_INFO *pData, int isNewInode); +extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, + FILE_UNIX_BASIC_INFO *info, + struct cifs_sb_info *cifs_sb); +extern void cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr); extern struct inode *cifs_new_inode(struct super_block *sb, __u64 *inum); +extern struct inode *cifs_iget(struct super_block *sb, + struct cifs_fattr *fattr); + extern int cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path, FILE_ALL_INFO *pfile_info, diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 3758965..bf0f107 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -188,6 +188,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode, FILE_UNIX_BASIC_INFO *presp_data; __u32 posix_flags = 0; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); + struct cifs_fattr fattr; cFYI(1, ("posix open %s", full_path)); @@ -236,22 +237,21 @@ int cifs_posix_open(char *full_path, struct inode **pinode, if (presp_data->Type == cpu_to_le32(-1)) goto posix_open_ret; /* open ok, caller does qpathinfo */ - /* get new inode and set it up */ if (!pinode) goto posix_open_ret; /* caller does not need info */ + cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb); + + /* get new inode and set it up */ if (*pinode == NULL) { - __u64 unique_id = le64_to_cpu(presp_data->UniqueId); - *pinode = cifs_new_inode(sb, &unique_id); + *pinode = cifs_iget(sb, &fattr); + if (!*pinode) { + rc = -ENOMEM; + goto posix_open_ret; + } + } else { + cifs_fattr_to_inode(*pinode, &fattr); } - /* else an inode was passed in. Update its info, don't create one */ - - /* We do not need to close the file if new_inode fails since - the caller will retry qpathinfo as long as inode is null */ - if (*pinode == NULL) - goto posix_open_ret; - - posix_fill_in_inode(*pinode, presp_data, 1); cifs_fill_fileinfo(*pinode, *pnetfid, cifs_sb->tcon, write_only); diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index fad882b..d1c7938 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -77,127 +77,146 @@ static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral) } } -static void cifs_unix_info_to_inode(struct inode *inode, - FILE_UNIX_BASIC_INFO *info, int force_uid_gid) +/* populate an inode with info from a cifs_fattr struct */ +void +cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) { - struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); - struct cifsInodeInfo *cifsInfo = CIFS_I(inode); - __u64 num_of_bytes = le64_to_cpu(info->NumOfBytes); - __u64 end_of_file = le64_to_cpu(info->EndOfFile); + struct cifsInodeInfo *cifs_i = CIFS_I(inode); + unsigned long now = jiffies; + + inode->i_atime = fattr->cf_atime; + inode->i_mtime = fattr->cf_mtime; + inode->i_ctime = fattr->cf_ctime; + inode->i_mode = fattr->cf_mode; + inode->i_rdev = fattr->cf_rdev; + inode->i_nlink = fattr->cf_nlink; + inode->i_uid = fattr->cf_uid; + inode->i_gid = fattr->cf_gid; + + cifs_i->cifsAttrs = fattr->cf_cifsattrs; + cifs_i->uniqueid = fattr->cf_uniqueid; + + cFYI(1, ("inode 0x%p old_time=%ld new_time=%ld", inode, + cifs_i->time, now)); + cifs_i->time = now; + + spin_lock(&inode->i_lock); + if (is_size_safe_to_change(cifs_i, fattr->cf_eof)) { + /* + * We can not safely change the file size here if the client + * is writing to it due to potential races. + */ + i_size_write(inode, fattr->cf_eof); + + /* + * i_blocks is not related to (i_size / i_blksize), + * but instead 512 byte (2**9) size is required for + * calculating num blocks. + */ + inode->i_blocks = (512 - 1 + fattr->cf_bytes) >> 9; + } + spin_unlock(&inode->i_lock); + + cifs_set_ops(inode, fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL); +} - inode->i_atime = cifs_NTtimeToUnix(info->LastAccessTime); - inode->i_mtime = - cifs_NTtimeToUnix(info->LastModificationTime); - inode->i_ctime = cifs_NTtimeToUnix(info->LastStatusChange); - inode->i_mode = le64_to_cpu(info->Permissions); +/* Fill a cifs_fattr struct with info from FILE_UNIX_BASIC_INFO. */ +void +cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info, + struct cifs_sb_info *cifs_sb) +{ + memset(fattr, 0, sizeof(*fattr)); + fattr->cf_uniqueid = le64_to_cpu(info->UniqueId); + fattr->cf_bytes = le64_to_cpu(info->NumOfBytes); + fattr->cf_eof = le64_to_cpu(info->EndOfFile); + + fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); + fattr->cf_mtime = cifs_NTtimeToUnix(info->LastModificationTime); + fattr->cf_ctime = cifs_NTtimeToUnix(info->LastStatusChange); + fattr->cf_mode = le64_to_cpu(info->Permissions); /* * Since we set the inode type below we need to mask off * to avoid strange results if bits set above. */ - inode->i_mode &= ~S_IFMT; + fattr->cf_mode &= ~S_IFMT; switch (le32_to_cpu(info->Type)) { case UNIX_FILE: - inode->i_mode |= S_IFREG; + fattr->cf_mode |= S_IFREG; + fattr->cf_dtype = DT_REG; break; case UNIX_SYMLINK: - inode->i_mode |= S_IFLNK; + fattr->cf_mode |= S_IFLNK; + fattr->cf_dtype = DT_LNK; break; case UNIX_DIR: - inode->i_mode |= S_IFDIR; + fattr->cf_mode |= S_IFDIR; + fattr->cf_dtype = DT_DIR; break; case UNIX_CHARDEV: - inode->i_mode |= S_IFCHR; - inode->i_rdev = MKDEV(le64_to_cpu(info->DevMajor), - le64_to_cpu(info->DevMinor) & MINORMASK); + fattr->cf_mode |= S_IFCHR; + fattr->cf_dtype = DT_CHR; + fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor), + le64_to_cpu(info->DevMinor) & MINORMASK); break; case UNIX_BLOCKDEV: - inode->i_mode |= S_IFBLK; - inode->i_rdev = MKDEV(le64_to_cpu(info->DevMajor), - le64_to_cpu(info->DevMinor) & MINORMASK); + fattr->cf_mode |= S_IFBLK; + fattr->cf_dtype = DT_BLK; + fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor), + le64_to_cpu(info->DevMinor) & MINORMASK); break; case UNIX_FIFO: - inode->i_mode |= S_IFIFO; + fattr->cf_mode |= S_IFIFO; + fattr->cf_dtype = DT_FIFO; break; case UNIX_SOCKET: - inode->i_mode |= S_IFSOCK; + fattr->cf_mode |= S_IFSOCK; + fattr->cf_dtype = DT_SOCK; break; default: /* safest to call it a file if we do not know */ - inode->i_mode |= S_IFREG; + fattr->cf_mode |= S_IFREG; + fattr->cf_dtype = DT_REG; cFYI(1, ("unknown type %d", le32_to_cpu(info->Type))); break; } - if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) && - !force_uid_gid) - inode->i_uid = cifs_sb->mnt_uid; + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) + fattr->cf_uid = cifs_sb->mnt_uid; else - inode->i_uid = le64_to_cpu(info->Uid); + fattr->cf_uid = le64_to_cpu(info->Uid); - if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) && - !force_uid_gid) - inode->i_gid = cifs_sb->mnt_gid; + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) + fattr->cf_gid = cifs_sb->mnt_gid; else - inode->i_gid = le64_to_cpu(info->Gid); - - inode->i_nlink = le64_to_cpu(info->Nlinks); + fattr->cf_gid = le64_to_cpu(info->Gid); - cifsInfo->server_eof = end_of_file; - spin_lock(&inode->i_lock); - if (is_size_safe_to_change(cifsInfo, end_of_file)) { - /* - * We can not safely change the file size here if the client - * is writing to it due to potential races. - */ - i_size_write(inode, end_of_file); - - /* - * i_blocks is not related to (i_size / i_blksize), - * but instead 512 byte (2**9) size is required for - * calculating num blocks. - */ - inode->i_blocks = (512 - 1 + num_of_bytes) >> 9; - } - spin_unlock(&inode->i_lock); + fattr->cf_nlink = le64_to_cpu(info->Nlinks); } - /* - * Needed to setup inode data for the directory which is the - * junction to the new submount (ie to setup the fake directory - * which represents a DFS referral) + * Fill a cifs_fattr struct with fake inode info. + * + * Needed to setup cifs_fattr data for the directory which is the + * junction to the new submount (ie to setup the fake directory + * which represents a DFS referral). */ -static void fill_fake_finddataunix(FILE_UNIX_BASIC_INFO *pfnd_dat, - struct super_block *sb) +void +cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb) { - struct inode *pinode = NULL; - - memset(pfnd_dat, 0, sizeof(FILE_UNIX_BASIC_INFO)); + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); -/* __le64 pfnd_dat->EndOfFile = cpu_to_le64(0); - __le64 pfnd_dat->NumOfBytes = cpu_to_le64(0); - __u64 UniqueId = 0; */ - pfnd_dat->LastStatusChange = - cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); - pfnd_dat->LastAccessTime = - cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); - pfnd_dat->LastModificationTime = - cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); - pfnd_dat->Type = cpu_to_le32(UNIX_DIR); - pfnd_dat->Permissions = cpu_to_le64(S_IXUGO | S_IRWXU); - pfnd_dat->Nlinks = cpu_to_le64(2); - if (sb->s_root) - pinode = sb->s_root->d_inode; - if (pinode == NULL) - return; - - /* fill in default values for the remaining based on root - inode since we can not query the server for this inode info */ - pfnd_dat->DevMajor = cpu_to_le64(MAJOR(pinode->i_rdev)); - pfnd_dat->DevMinor = cpu_to_le64(MINOR(pinode->i_rdev)); - pfnd_dat->Uid = cpu_to_le64(pinode->i_uid); - pfnd_dat->Gid = cpu_to_le64(pinode->i_gid); + cFYI(1, ("creating fake fattr for DFS referral")); + + memset(fattr, 0, sizeof(*fattr)); + fattr->cf_mode = S_IFDIR | S_IXUGO | S_IRWXU; + fattr->cf_uid = cifs_sb->mnt_uid; + fattr->cf_gid = cifs_sb->mnt_gid; + fattr->cf_atime = CURRENT_TIME; + fattr->cf_ctime = CURRENT_TIME; + fattr->cf_mtime = CURRENT_TIME; + fattr->cf_nlink = 2; + fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL; } /** @@ -244,66 +263,42 @@ cifs_new_inode(struct super_block *sb, __u64 *inum) } int cifs_get_inode_info_unix(struct inode **pinode, - const unsigned char *full_path, struct super_block *sb, int xid) + const unsigned char *full_path, + struct super_block *sb, int xid) { - int rc = 0; + int rc; FILE_UNIX_BASIC_INFO find_data; - struct cifsTconInfo *pTcon; - struct inode *inode; + struct cifs_fattr fattr; + struct cifsTconInfo *tcon; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); - bool is_dfs_referral = false; - struct cifsInodeInfo *cifsInfo; - __u64 num_of_bytes; - __u64 end_of_file; - pTcon = cifs_sb->tcon; + tcon = cifs_sb->tcon; cFYI(1, ("Getting info on %s", full_path)); /* could have done a find first instead but this returns more info */ - rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &find_data, + rc = CIFSSMBUnixQPathInfo(xid, tcon, full_path, &find_data, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); - if (rc == -EREMOTE && !is_dfs_referral) { - is_dfs_referral = true; - cFYI(DBG2, ("DFS ref")); - /* for DFS, server does not give us real inode data */ - fill_fake_finddataunix(&find_data, sb); - rc = 0; - } else if (rc) - goto cgiiu_exit; - num_of_bytes = le64_to_cpu(find_data.NumOfBytes); - end_of_file = le64_to_cpu(find_data.EndOfFile); + if (!rc) { + cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb); + } else if (rc == -EREMOTE) { + cifs_create_dfs_fattr(&fattr, sb); + rc = 0; + } else { + return rc; + } - /* get new inode */ if (*pinode == NULL) { - __u64 unique_id = le64_to_cpu(find_data.UniqueId); - *pinode = cifs_new_inode(sb, &unique_id); - if (*pinode == NULL) { + /* get new inode */ + *pinode = cifs_iget(sb, &fattr); + if (!*pinode) rc = -ENOMEM; - goto cgiiu_exit; - } + } else { + /* we already have inode, update it */ + cifs_fattr_to_inode(*pinode, &fattr); } - inode = *pinode; - cifsInfo = CIFS_I(inode); - - cFYI(1, ("Old time %ld", cifsInfo->time)); - cifsInfo->time = jiffies; - cFYI(1, ("New time %ld", cifsInfo->time)); - /* this is ok to set on every inode revalidate */ - atomic_set(&cifsInfo->inUse, 1); - - cifs_unix_info_to_inode(inode, &find_data, 0); - - if (num_of_bytes < end_of_file) - cFYI(1, ("allocation size less than end of file")); - cFYI(1, ("Size %ld and blocks %llu", - (unsigned long) inode->i_size, - (unsigned long long)inode->i_blocks)); - - cifs_set_ops(inode, is_dfs_referral); -cgiiu_exit: return rc; } @@ -695,33 +690,85 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb) return full_path; } +static int +cifs_find_inode(struct inode *inode, void *opaque) +{ + struct cifs_fattr *fattr = (struct cifs_fattr *) opaque; + + if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid) + return 0; + + return 1; +} + +static int +cifs_init_inode(struct inode *inode, void *opaque) +{ + struct cifs_fattr *fattr = (struct cifs_fattr *) opaque; + + CIFS_I(inode)->uniqueid = fattr->cf_uniqueid; + return 0; +} + +/* Given fattrs, get a corresponding inode */ +struct inode * +cifs_iget(struct super_block *sb, struct cifs_fattr *fattr) +{ + unsigned long hash; + struct inode *inode; + + cFYI(1,("looking for uniqueid=%llu", fattr->cf_uniqueid)); + + /* hash down to 32-bits on 32-bit arch */ + hash = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid); + + inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr); + + /* we have fattrs in hand, update the inode */ + if (inode) { + cifs_fattr_to_inode(inode, fattr); + if (sb->s_flags & MS_NOATIME) + inode->i_flags |= S_NOATIME | S_NOCMTIME; + if (inode->i_state & I_NEW) { + inode->i_ino = hash; + unlock_new_inode(inode); + } + } + + return inode; +} + /* gets root inode */ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) { int xid; struct cifs_sb_info *cifs_sb; - struct inode *inode; + struct inode *inode = NULL; long rc; char *full_path; - inode = iget_locked(sb, ino); - if (!inode) - return ERR_PTR(-ENOMEM); - if (!(inode->i_state & I_NEW)) - return inode; - - cifs_sb = CIFS_SB(inode->i_sb); + cifs_sb = CIFS_SB(sb); full_path = cifs_build_path_to_root(cifs_sb); if (full_path == NULL) return ERR_PTR(-ENOMEM); xid = GetXid(); - if (cifs_sb->tcon->unix_ext) - rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb, - xid); - else + if (cifs_sb->tcon->unix_ext) { + rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid); + if (!inode) + return ERR_PTR(-ENOMEM); + } else { + inode = iget_locked(sb, ino); + if (!inode) + return ERR_PTR(-ENOMEM); + if (!(inode->i_state & I_NEW)) + return inode; + rc = cifs_get_inode_info(&inode, full_path, NULL, inode->i_sb, xid, NULL); + unlock_new_inode(inode); + } + if (rc && cifs_sb->tcon->ipc) { cFYI(1, ("ipc connection - fake read inode")); inode->i_mode |= S_IFDIR; @@ -737,7 +784,6 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) return ERR_PTR(rc); } - unlock_new_inode(inode); kfree(full_path); /* can not call macro FreeXid here since in a void func @@ -1062,44 +1108,6 @@ out_reval: return rc; } -void posix_fill_in_inode(struct inode *tmp_inode, - FILE_UNIX_BASIC_INFO *pData, int isNewInode) -{ - struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); - loff_t local_size; - struct timespec local_mtime; - - cifsInfo->time = jiffies; - atomic_inc(&cifsInfo->inUse); - - /* save mtime and size */ - local_mtime = tmp_inode->i_mtime; - local_size = tmp_inode->i_size; - - cifs_unix_info_to_inode(tmp_inode, pData, 1); - cifs_set_ops(tmp_inode, false); - - if (!S_ISREG(tmp_inode->i_mode)) - return; - - /* - * No sense invalidating pages for new inode - * since we we have not started caching - * readahead file data yet. - */ - if (isNewInode) - return; - - if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && - (local_size == tmp_inode->i_size)) { - cFYI(1, ("inode exists but unchanged")); - } else { - /* file may have changed on server */ - cFYI(1, ("invalidate inode, readdir detected change")); - invalidate_remote_inode(tmp_inode); - } -} - int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) { int rc = 0, tmprc; @@ -1108,6 +1116,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) struct cifsTconInfo *pTcon; char *full_path = NULL; struct inode *newinode = NULL; + struct cifs_fattr fattr; cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p", mode, inode)); @@ -1146,7 +1155,6 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) cFYI(1, ("posix mkdir returned 0x%x", rc)); d_drop(direntry); } else { - __u64 unique_id; if (pInfo->Type == cpu_to_le32(-1)) { /* no return info, go query for it */ kfree(pInfo); @@ -1160,20 +1168,15 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) else direntry->d_op = &cifs_dentry_ops; - unique_id = le64_to_cpu(pInfo->UniqueId); - newinode = cifs_new_inode(inode->i_sb, &unique_id); - if (newinode == NULL) { + cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb); + newinode = cifs_iget(inode->i_sb, &fattr); + if (!newinode) { kfree(pInfo); goto mkdir_get_info; } - newinode->i_nlink = 2; d_instantiate(direntry, newinode); - /* we already checked in POSIXCreate whether - frame was long enough */ - posix_fill_in_inode(direntry->d_inode, - pInfo, 1 /* NewInode */); #ifdef CONFIG_CIFS_DEBUG2 cFYI(1, ("instantiated dentry %p %s to inode %p", direntry, direntry->d_name.name, newinode)); @@ -1618,6 +1621,7 @@ int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, if (!err) { generic_fillattr(dentry->d_inode, stat); stat->blksize = CIFS_MAX_MSGSIZE; + stat->ino = CIFS_I(dentry->d_inode)->uniqueid; } return err; }