cifs: convert cifs_get_inode_info and non-posix readdir to use cifs_iget
Jeff Layton [Thu, 9 Jul 2009 05:46:37 +0000 (01:46 -0400)]
cifs: convert cifs_get_inode_info and non-posix readdir to use cifs_iget

Rather than allocating an inode and filling it out, have
cifs_get_inode_info fill out a cifs_fattr and call cifs_iget. This means
a pretty hefty reorganization of cifs_get_inode_info.

For the readdir codepath, add a couple of new functions for filling out
cifs_fattr's from different FindFile response infolevels.

Finally, remove cifs_new_inode since there are no more callers.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Steve French <sfrench@us.ibm.com>

fs/cifs/cifsacl.c
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/inode.c
fs/cifs/readdir.c

index 1403b5d..6941c22 100644 (file)
@@ -327,7 +327,7 @@ static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
 
 static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
                       struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
-                      struct inode *inode)
+                      struct cifs_fattr *fattr)
 {
        int i;
        int num_aces = 0;
@@ -340,7 +340,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
        if (!pdacl) {
                /* no DACL in the security descriptor, set
                   all the permissions for user/group/other */
-               inode->i_mode |= S_IRWXUGO;
+               fattr->cf_mode |= S_IRWXUGO;
                return;
        }
 
@@ -357,7 +357,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
        /* reset rwx permissions for user/group/other.
           Also, if num_aces is 0 i.e. DACL has no ACEs,
           user/group/other have no permissions */
-       inode->i_mode &= ~(S_IRWXUGO);
+       fattr->cf_mode &= ~(S_IRWXUGO);
 
        acl_base = (char *)pdacl;
        acl_size = sizeof(struct cifs_acl);
@@ -379,17 +379,17 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
                        if (compare_sids(&(ppace[i]->sid), pownersid))
                                access_flags_to_mode(ppace[i]->access_req,
                                                     ppace[i]->type,
-                                                    &(inode->i_mode),
+                                                    &fattr->cf_mode,
                                                     &user_mask);
                        if (compare_sids(&(ppace[i]->sid), pgrpsid))
                                access_flags_to_mode(ppace[i]->access_req,
                                                     ppace[i]->type,
-                                                    &(inode->i_mode),
+                                                    &fattr->cf_mode,
                                                     &group_mask);
                        if (compare_sids(&(ppace[i]->sid), &sid_everyone))
                                access_flags_to_mode(ppace[i]->access_req,
                                                     ppace[i]->type,
-                                                    &(inode->i_mode),
+                                                    &fattr->cf_mode,
                                                     &other_mask);
 
 /*                     memcpy((void *)(&(cifscred->aces[i])),
@@ -464,7 +464,7 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
 
 /* Convert CIFS ACL to POSIX form */
 static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
-                         struct inode *inode)
+                         struct cifs_fattr *fattr)
 {
        int rc;
        struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
@@ -472,7 +472,7 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
        char *end_of_acl = ((char *)pntsd) + acl_len;
        __u32 dacloffset;
 
-       if ((inode == NULL) || (pntsd == NULL))
+       if (pntsd == NULL)
                return -EIO;
 
        owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
@@ -497,7 +497,7 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
 
        if (dacloffset)
                parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
-                          group_sid_ptr, inode);
+                          group_sid_ptr, fattr);
        else
                cFYI(1, ("no ACL")); /* BB grant all or default perms? */
 
@@ -508,7 +508,6 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
        memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
                        sizeof(struct cifs_sid)); */
 
-
        return 0;
 }
 
@@ -671,8 +670,9 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
 }
 
 /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
-void acl_to_uid_mode(struct cifs_sb_info *cifs_sb, struct inode *inode,
-                    const char *path, const __u16 *pfid)
+void
+cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
+                 struct inode *inode, const char *path, const __u16 *pfid)
 {
        struct cifs_ntsd *pntsd = NULL;
        u32 acllen = 0;
@@ -687,7 +687,7 @@ void acl_to_uid_mode(struct cifs_sb_info *cifs_sb, struct inode *inode,
 
        /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
        if (pntsd)
-               rc = parse_sec_desc(pntsd, acllen, inode);
+               rc = parse_sec_desc(pntsd, acllen, fattr);
        if (rc)
                cFYI(1, ("parse sec desc failed rc = %d", rc));
 
index e6435cb..8bcf5a4 100644 (file)
@@ -479,6 +479,8 @@ struct dfs_info3_param {
  */
 
 #define CIFS_FATTR_DFS_REFERRAL                0x1
+#define CIFS_FATTR_DELETE_PENDING      0x2
+#define CIFS_FATTR_NEED_REVAL          0x4
 
 struct cifs_fattr {
        u32             cf_flags;
index 37c11c0..da8fbf5 100644 (file)
@@ -102,7 +102,6 @@ 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);
 
@@ -113,8 +112,9 @@ extern int cifs_get_inode_info(struct inode **pinode,
 extern int cifs_get_inode_info_unix(struct inode **pinode,
                        const unsigned char *search_path,
                        struct super_block *sb, int xid);
-extern void acl_to_uid_mode(struct cifs_sb_info *cifs_sb, struct inode *inode,
-                           const char *path, const __u16 *pfid);
+extern void cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
+                             struct cifs_fattr *fattr, struct inode *inode,
+                             const char *path, const __u16 *pfid);
 extern int mode_to_acl(struct inode *inode, const char *path, __u64);
 
 extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
index 55b616b..a807397 100644 (file)
@@ -82,23 +82,34 @@ void
 cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
 {
        struct cifsInodeInfo *cifs_i = CIFS_I(inode);
-       unsigned long now = jiffies;
+       struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+       unsigned long oldtime = cifs_i->time;
 
        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;
 
+       /* if dynperm is set, don't clobber existing mode */
+       if (inode->i_state & I_NEW ||
+           !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM))
+               inode->i_mode = fattr->cf_mode;
+
        cifs_i->cifsAttrs = fattr->cf_cifsattrs;
        cifs_i->uniqueid = fattr->cf_uniqueid;
 
+       if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)
+               cifs_i->time = 0;
+       else
+               cifs_i->time = jiffies;
+
        cFYI(1, ("inode 0x%p old_time=%ld new_time=%ld", inode,
-                cifs_i->time, now));
-       cifs_i->time = now;
+                oldtime, cifs_i->time));
+
+       cifs_i->delete_pending = fattr->cf_flags & CIFS_FATTR_DELETE_PENDING;
 
        /*
         * Can't safely change the file size here if the client is writing to
@@ -219,49 +230,6 @@ cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
        fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL;
 }
 
-/**
- * cifs_new inode - create new inode, initialize, and hash it
- * @sb - pointer to superblock
- * @inum - if valid pointer and serverino is enabled, replace i_ino with val
- *
- * Create a new inode, initialize it for CIFS and hash it. Returns the new
- * inode or NULL if one couldn't be allocated.
- *
- * If the share isn't mounted with "serverino" or inum is a NULL pointer then
- * we'll just use the inode number assigned by new_inode(). Note that this can
- * mean i_ino collisions since the i_ino assigned by new_inode is not
- * guaranteed to be unique.
- */
-struct inode *
-cifs_new_inode(struct super_block *sb, __u64 *inum)
-{
-       struct inode *inode;
-
-       inode = new_inode(sb);
-       if (inode == NULL)
-               return NULL;
-
-       /*
-        * BB: Is i_ino == 0 legal? Here, we assume that it is. If it isn't we
-        *     stop passing inum as ptr. Are there sanity checks we can use to
-        *     ensure that the server is really filling in that field? Also,
-        *     if serverino is disabled, perhaps we should be using iunique()?
-        */
-       if (inum && (CIFS_SB(sb)->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM))
-               inode->i_ino = (unsigned long) *inum;
-
-       /*
-        * must set this here instead of cifs_alloc_inode since VFS will
-        * clobber i_flags
-        */
-       if (sb->s_flags & MS_NOATIME)
-               inode->i_flags |= S_NOATIME | S_NOCMTIME;
-
-       insert_inode_hash(inode);
-
-       return inode;
-}
-
 int cifs_get_inode_info_unix(struct inode **pinode,
                             const unsigned char *full_path,
                             struct super_block *sb, int xid)
@@ -302,9 +270,9 @@ int cifs_get_inode_info_unix(struct inode **pinode,
        return rc;
 }
 
-static int decode_sfu_inode(struct inode *inode, __u64 size,
-                           const unsigned char *path,
-                           struct cifs_sb_info *cifs_sb, int xid)
+static int
+cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
+             struct cifs_sb_info *cifs_sb, int xid)
 {
        int rc;
        int oplock = 0;
@@ -316,10 +284,15 @@ static int decode_sfu_inode(struct inode *inode, __u64 size,
 
        pbuf = buf;
 
-       if (size == 0) {
-               inode->i_mode |= S_IFIFO;
+       fattr->cf_mode &= ~S_IFMT;
+
+       if (fattr->cf_eof == 0) {
+               fattr->cf_mode |= S_IFIFO;
+               fattr->cf_dtype = DT_FIFO;
                return 0;
-       } else if (size < 8) {
+       } else if (fattr->cf_eof < 8) {
+               fattr->cf_mode |= S_IFREG;
+               fattr->cf_dtype = DT_REG;
                return -EINVAL;  /* EOPNOTSUPP? */
        }
 
@@ -331,42 +304,46 @@ static int decode_sfu_inode(struct inode *inode, __u64 size,
        if (rc == 0) {
                int buf_type = CIFS_NO_BUFFER;
                        /* Read header */
-               rc = CIFSSMBRead(xid, pTcon,
-                                netfid,
+               rc = CIFSSMBRead(xid, pTcon, netfid,
                                 24 /* length */, 0 /* offset */,
                                 &bytes_read, &pbuf, &buf_type);
                if ((rc == 0) && (bytes_read >= 8)) {
                        if (memcmp("IntxBLK", pbuf, 8) == 0) {
                                cFYI(1, ("Block device"));
-                               inode->i_mode |= S_IFBLK;
+                               fattr->cf_mode |= S_IFBLK;
+                               fattr->cf_dtype = DT_BLK;
                                if (bytes_read == 24) {
                                        /* we have enough to decode dev num */
                                        __u64 mjr; /* major */
                                        __u64 mnr; /* minor */
                                        mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
                                        mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
-                                       inode->i_rdev = MKDEV(mjr, mnr);
+                                       fattr->cf_rdev = MKDEV(mjr, mnr);
                                }
                        } else if (memcmp("IntxCHR", pbuf, 8) == 0) {
                                cFYI(1, ("Char device"));
-                               inode->i_mode |= S_IFCHR;
+                               fattr->cf_mode |= S_IFCHR;
+                               fattr->cf_dtype = DT_CHR;
                                if (bytes_read == 24) {
                                        /* we have enough to decode dev num */
                                        __u64 mjr; /* major */
                                        __u64 mnr; /* minor */
                                        mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
                                        mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
-                                       inode->i_rdev = MKDEV(mjr, mnr);
+                                       fattr->cf_rdev = MKDEV(mjr, mnr);
                                }
                        } else if (memcmp("IntxLNK", pbuf, 7) == 0) {
                                cFYI(1, ("Symlink"));
-                               inode->i_mode |= S_IFLNK;
+                               fattr->cf_mode |= S_IFLNK;
+                               fattr->cf_dtype = DT_LNK;
                        } else {
-                               inode->i_mode |= S_IFREG; /* file? */
+                               fattr->cf_mode |= S_IFREG; /* file? */
+                               fattr->cf_dtype = DT_REG;
                                rc = -EOPNOTSUPP;
                        }
                } else {
-                       inode->i_mode |= S_IFREG; /* then it is a file */
+                       fattr->cf_mode |= S_IFREG; /* then it is a file */
+                       fattr->cf_dtype = DT_REG;
                        rc = -EOPNOTSUPP; /* or some unknown SFU type */
                }
                CIFSSMBClose(xid, pTcon, netfid);
@@ -376,9 +353,13 @@ static int decode_sfu_inode(struct inode *inode, __u64 size,
 
 #define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID)  /* SETFILEBITS valid bits */
 
-static int get_sfu_mode(struct inode *inode,
-                       const unsigned char *path,
-                       struct cifs_sb_info *cifs_sb, int xid)
+/*
+ * Fetch mode bits as provided by SFU.
+ *
+ * FIXME: Doesn't this clobber the type bit we got from cifs_sfu_type ?
+ */
+static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
+                        struct cifs_sb_info *cifs_sb, int xid)
 {
 #ifdef CONFIG_CIFS_XATTR
        ssize_t rc;
@@ -386,68 +367,80 @@ static int get_sfu_mode(struct inode *inode,
        __u32 mode;
 
        rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS",
-                       ea_value, 4 /* size of buf */, cifs_sb->local_nls,
-               cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+                           ea_value, 4 /* size of buf */, cifs_sb->local_nls,
+                           cifs_sb->mnt_cifs_flags &
+                               CIFS_MOUNT_MAP_SPECIAL_CHR);
        if (rc < 0)
                return (int)rc;
        else if (rc > 3) {
                mode = le32_to_cpu(*((__le32 *)ea_value));
-               inode->i_mode &= ~SFBITS_MASK;
-               cFYI(1, ("special bits 0%o org mode 0%o", mode, inode->i_mode));
-               inode->i_mode = (mode &  SFBITS_MASK) | inode->i_mode;
+               fattr->cf_mode &= ~SFBITS_MASK;
+               cFYI(1, ("special bits 0%o org mode 0%o", mode,
+                        fattr->cf_mode));
+               fattr->cf_mode = (mode & SFBITS_MASK) | fattr->cf_mode;
                cFYI(1, ("special mode bits 0%o", mode));
-               return 0;
-       } else {
-               return 0;
        }
+
+       return 0;
 #else
        return -EOPNOTSUPP;
 #endif
 }
 
-/*
- *     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)
- */
-static void fill_fake_finddata(FILE_ALL_INFO *pfnd_dat,
-                              struct super_block *sb)
+/* Fill a cifs_fattr struct with info from FILE_ALL_INFO */
+void
+cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
+                      struct cifs_sb_info *cifs_sb, bool adjust_tz)
 {
-       memset(pfnd_dat, 0, sizeof(FILE_ALL_INFO));
-
-/*     __le64 pfnd_dat->AllocationSize = cpu_to_le64(0);
-       __le64 pfnd_dat->EndOfFile = cpu_to_le64(0);
-       __u8 pfnd_dat->DeletePending = 0;
-       __u8 pfnd_data->Directory = 0;
-       __le32 pfnd_dat->EASize = 0;
-       __u64 pfnd_dat->IndexNumber = 0;
-       __u64 pfnd_dat->IndexNumber1 = 0;  */
-       pfnd_dat->CreationTime =
-               cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
-       pfnd_dat->LastAccessTime =
-               cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
-       pfnd_dat->LastWriteTime =
-               cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
-       pfnd_dat->ChangeTime =
-               cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
-       pfnd_dat->Attributes = cpu_to_le32(ATTR_DIRECTORY);
-       pfnd_dat->NumberOfLinks = cpu_to_le32(2);
+       memset(fattr, 0, sizeof(*fattr));
+       fattr->cf_cifsattrs = le32_to_cpu(info->Attributes);
+       if (info->DeletePending)
+               fattr->cf_flags |= CIFS_FATTR_DELETE_PENDING;
+
+       if (info->LastAccessTime)
+               fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
+       else
+               fattr->cf_atime = CURRENT_TIME;
+
+       fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
+       fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
+
+       if (adjust_tz) {
+               fattr->cf_ctime.tv_sec += cifs_sb->tcon->ses->server->timeAdj;
+               fattr->cf_mtime.tv_sec += cifs_sb->tcon->ses->server->timeAdj;
+       }
+
+       fattr->cf_eof = le64_to_cpu(info->EndOfFile);
+       fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
+
+       if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
+               fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
+               fattr->cf_dtype = DT_DIR;
+       } else {
+               fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
+               fattr->cf_dtype = DT_REG;
+       }
+
+       /* clear write bits if ATTR_READONLY is set */
+       if (fattr->cf_cifsattrs & ATTR_READONLY)
+               fattr->cf_mode &= ~(S_IWUGO);
+
+       fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
+
+       fattr->cf_uid = cifs_sb->mnt_uid;
+       fattr->cf_gid = cifs_sb->mnt_gid;
 }
 
 int cifs_get_inode_info(struct inode **pinode,
        const unsigned char *full_path, FILE_ALL_INFO *pfindData,
        struct super_block *sb, int xid, const __u16 *pfid)
 {
-       int rc = 0;
-       __u32 attr;
-       struct cifsInodeInfo *cifsInfo;
+       int rc = 0, tmprc;
        struct cifsTconInfo *pTcon;
-       struct inode *inode;
        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
        char *buf = NULL;
        bool adjustTZ = false;
-       bool is_dfs_referral = false;
-       umode_t default_mode;
+       struct cifs_fattr fattr;
 
        pTcon = cifs_sb->tcon;
        cFYI(1, ("Getting info on %s", full_path));
@@ -482,163 +475,82 @@ int cifs_get_inode_info(struct inode **pinode,
                        adjustTZ = true;
                }
        }
-       /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
-       if (rc == -EREMOTE) {
-               is_dfs_referral = true;
-               fill_fake_finddata(pfindData, sb);
+
+       if (!rc) {
+               cifs_all_info_to_fattr(&fattr, (FILE_ALL_INFO *) pfindData,
+                                      cifs_sb, adjustTZ);
+       } else if (rc == -EREMOTE) {
+               cifs_create_dfs_fattr(&fattr, sb);
                rc = 0;
-       } else if (rc)
+       } else {
                goto cgii_exit;
+       }
 
-       attr = le32_to_cpu(pfindData->Attributes);
-
-       /* get new inode */
+       /*
+        * If an inode wasn't passed in, then get the inode number
+        *
+        * Is an i_ino of zero legal? Can we use that to check if the server
+        * supports returning inode numbers?  Are there other sanity checks we
+        * can use to ensure that the server is really filling in that field?
+        *
+        * We can not use the IndexNumber field by default from Windows or
+        * Samba (in ALL_INFO buf) but we can request it explicitly. The SNIA
+        * CIFS spec claims that this value is unique within the scope of a
+        * share, and the windows docs hint that it's actually unique
+        * per-machine.
+        *
+        * There may be higher info levels that work but are there Windows
+        * server or network appliances for which IndexNumber field is not
+        * guaranteed unique?
+        */
        if (*pinode == NULL) {
-               __u64 inode_num;
-               __u64 *pinum = &inode_num;
-
-               /* Is an i_ino of zero legal? Can we use that to check
-                  if the server supports returning inode numbers?  Are
-                  there other sanity checks we can use to ensure that
-                  the server is really filling in that field? */
-
-               /* We can not use the IndexNumber field by default from
-                  Windows or Samba (in ALL_INFO buf) but we can request
-                  it explicitly.  It may not be unique presumably if
-                  the server has multiple devices mounted under one share */
-
-               /* There may be higher info levels that work but are
-                  there Windows server or network appliances for which
-                  IndexNumber field is not guaranteed unique? */
-
                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
                        int rc1 = 0;
 
                        rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
-                                       full_path, pinum,
+                                       full_path, &fattr.cf_uniqueid,
                                        cifs_sb->local_nls,
                                        cifs_sb->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
                        if (rc1) {
-                               cFYI(1, ("GetSrvInodeNum rc %d", rc1));
-                               pinum = NULL;
                                /* BB EOPNOSUPP disable SERVER_INUM? */
+                               cFYI(1, ("GetSrvInodeNum rc %d", rc1));
+                               fattr.cf_uniqueid = iunique(sb, ROOT_I);
                        }
                } else {
-                       pinum = NULL;
+                       fattr.cf_uniqueid = iunique(sb, ROOT_I);
                }
-
-               *pinode = cifs_new_inode(sb, pinum);
-               if (*pinode == NULL) {
-                       rc = -ENOMEM;
-                       goto cgii_exit;
-               }
-       }
-       inode = *pinode;
-       cifsInfo = CIFS_I(inode);
-       cifsInfo->cifsAttrs = attr;
-       cifsInfo->delete_pending = pfindData->DeletePending ? true : false;
-       cFYI(1, ("Old time %ld", cifsInfo->time));
-       cifsInfo->time = jiffies;
-       cFYI(1, ("New time %ld", cifsInfo->time));
-
-       /* blksize needs to be multiple of two. So safer to default to
-       blksize and blkbits set in superblock so 2**blkbits and blksize
-       will match rather than setting to:
-       (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
-
-       /* Linux can not store file creation time so ignore it */
-       if (pfindData->LastAccessTime)
-               inode->i_atime = cifs_NTtimeToUnix(pfindData->LastAccessTime);
-       else /* do not need to use current_fs_time - time not stored */
-               inode->i_atime = CURRENT_TIME;
-       inode->i_mtime = cifs_NTtimeToUnix(pfindData->LastWriteTime);
-       inode->i_ctime = cifs_NTtimeToUnix(pfindData->ChangeTime);
-       cFYI(DBG2, ("Attributes came in as 0x%x", attr));
-       if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) {
-               inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj;
-               inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj;
-       }
-
-       /* get default inode mode */
-       if (attr & ATTR_DIRECTORY)
-               default_mode = cifs_sb->mnt_dir_mode;
-       else
-               default_mode = cifs_sb->mnt_file_mode;
-
-       /* set permission bits */
-       if (atomic_read(&cifsInfo->inUse) == 0 ||
-           (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
-               inode->i_mode = default_mode;
-       else {
-               /* just reenable write bits if !ATTR_READONLY */
-               if ((inode->i_mode & S_IWUGO) == 0 &&
-                   (attr & ATTR_READONLY) == 0)
-                       inode->i_mode |= (S_IWUGO & default_mode);
-
-               inode->i_mode &= ~S_IFMT;
-       }
-       /* clear write bits if ATTR_READONLY is set */
-       if (attr & ATTR_READONLY)
-               inode->i_mode &= ~S_IWUGO;
-
-       /* set inode type */
-       if ((attr & ATTR_SYSTEM) &&
-           (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) {
-               /* no need to fix endianness on 0 */
-               if (pfindData->EndOfFile == 0)
-                       inode->i_mode |= S_IFIFO;
-               else if (decode_sfu_inode(inode,
-                               le64_to_cpu(pfindData->EndOfFile),
-                               full_path, cifs_sb, xid))
-                       cFYI(1, ("unknown SFU file type\n"));
        } else {
-               if (attr & ATTR_DIRECTORY)
-                       inode->i_mode |= S_IFDIR;
-               else
-                       inode->i_mode |= S_IFREG;
+               fattr.cf_uniqueid = CIFS_I(*pinode)->uniqueid;
        }
 
-       cifsInfo->server_eof = le64_to_cpu(pfindData->EndOfFile);
-       spin_lock(&inode->i_lock);
-       if (is_size_safe_to_change(cifsInfo, cifsInfo->server_eof)) {
-               /* can not safely shrink the file size here if the
-                  client is writing to it due to potential races */
-               i_size_write(inode, cifsInfo->server_eof);
-
-               /* 512 bytes (2**9) is the fake blocksize that must be
-                  used for this calculation */
-               inode->i_blocks = (512 - 1 + le64_to_cpu(
-                                  pfindData->AllocationSize)) >> 9;
+       /* query for SFU type info if supported and needed */
+       if (fattr.cf_cifsattrs & ATTR_SYSTEM &&
+           cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
+               tmprc = cifs_sfu_type(&fattr, full_path, cifs_sb, xid);
+               if (tmprc)
+                       cFYI(1, ("cifs_sfu_type failed: %d", tmprc));
        }
-       spin_unlock(&inode->i_lock);
 
-       inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
-
-       /* BB fill in uid and gid here? with help from winbind?
-          or retrieve from NTFS stream extended attribute */
 #ifdef CONFIG_CIFS_EXPERIMENTAL
        /* fill in 0777 bits from ACL */
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
                cFYI(1, ("Getting mode bits from ACL"));
-               acl_to_uid_mode(cifs_sb, inode, full_path, pfid);
+               cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path, pfid);
        }
 #endif
-       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
-               /* fill in remaining high mode bits e.g. SUID, VTX */
-               get_sfu_mode(inode, full_path, cifs_sb, xid);
-       } else if (atomic_read(&cifsInfo->inUse) == 0) {
-               inode->i_uid = cifs_sb->mnt_uid;
-               inode->i_gid = cifs_sb->mnt_gid;
-               /* set so we do not keep refreshing these fields with
-                  bad data after user has changed them in memory */
-               atomic_set(&cifsInfo->inUse, 1);
-       }
-
-       cifs_set_ops(inode, is_dfs_referral);
-
 
+       /* fill in remaining high mode bits e.g. SUID, VTX */
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
+               cifs_sfu_mode(&fattr, full_path, cifs_sb, xid);
 
+       if (!*pinode) {
+               *pinode = cifs_iget(sb, &fattr);
+               if (!*pinode)
+                       rc = -ENOMEM;
+       } else {
+               cifs_fattr_to_inode(*pinode, &fattr);
+       }
 
 cgii_exit:
        kfree(buf);
@@ -753,21 +665,14 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino)
                return ERR_PTR(-ENOMEM);
 
        xid = GetXid();
-       if (cifs_sb->tcon->unix_ext) {
+       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,
+       else
+               rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
                                                xid, NULL);
-               unlock_new_inode(inode);
-       }
+
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
 
        if (rc && cifs_sb->tcon->ipc) {
                cFYI(1, ("ipc connection - fake read inode"));
index 231aa69..f823a4a 100644 (file)
@@ -112,239 +112,74 @@ cifs_readdir_lookup(struct dentry *parent, struct qstr *name,
        return dentry;
 }
 
-/* Returns 1 if new inode created, 2 if both dentry and inode were */
-/* Might check in the future if inode number changed so we can rehash inode */
-static int
-construct_dentry(struct qstr *qstring, struct file *file,
-                struct inode **ptmp_inode, struct dentry **pnew_dentry,
-                __u64 *inum)
+static void
+cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
 {
-       struct dentry *tmp_dentry = NULL;
-       struct super_block *sb = file->f_path.dentry->d_sb;
-       int rc = 0;
+       fattr->cf_uid = cifs_sb->mnt_uid;
+       fattr->cf_gid = cifs_sb->mnt_gid;
 
-       cFYI(1, ("For %s", qstring->name));
-
-       tmp_dentry = d_lookup(file->f_path.dentry, qstring);
-       if (tmp_dentry) {
-               /* BB: overwrite old name? i.e. tmp_dentry->d_name and
-                * tmp_dentry->d_name.len??
-                */
-               cFYI(0, ("existing dentry with inode 0x%p",
-                        tmp_dentry->d_inode));
-               *ptmp_inode = tmp_dentry->d_inode;
-               if (*ptmp_inode == NULL) {
-                       *ptmp_inode = cifs_new_inode(sb, inum);
-                       if (*ptmp_inode == NULL)
-                               return rc;
-                       rc = 1;
-               }
+       if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
+               fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
+               fattr->cf_dtype = DT_DIR;
        } else {
-               tmp_dentry = d_alloc(file->f_path.dentry, qstring);
-               if (tmp_dentry == NULL) {
-                       cERROR(1, ("Failed allocating dentry"));
-                       *ptmp_inode = NULL;
-                       return rc;
-               }
-
-               if (CIFS_SB(sb)->tcon->nocase)
-                       tmp_dentry->d_op = &cifs_ci_dentry_ops;
-               else
-                       tmp_dentry->d_op = &cifs_dentry_ops;
-
-               *ptmp_inode = cifs_new_inode(sb, inum);
-               if (*ptmp_inode == NULL)
-                       return rc;
-               rc = 2;
-       }
-
-       tmp_dentry->d_time = jiffies;
-       *pnew_dentry = tmp_dentry;
-       return rc;
-}
-
-static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
-                         char *buf, unsigned int *pobject_type, int isNewInode)
-{
-       loff_t local_size;
-       struct timespec local_mtime;
-
-       struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
-       struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
-       __u32 attr;
-       __u64 allocation_size;
-       __u64 end_of_file;
-       umode_t default_mode;
-
-       /* save mtime and size */
-       local_mtime = tmp_inode->i_mtime;
-       local_size  = tmp_inode->i_size;
-
-       if (new_buf_type) {
-               FILE_DIRECTORY_INFO *pfindData = (FILE_DIRECTORY_INFO *)buf;
-
-               attr = le32_to_cpu(pfindData->ExtFileAttributes);
-               allocation_size = le64_to_cpu(pfindData->AllocationSize);
-               end_of_file = le64_to_cpu(pfindData->EndOfFile);
-               tmp_inode->i_atime =
-                       cifs_NTtimeToUnix(pfindData->LastAccessTime);
-               tmp_inode->i_mtime =
-                       cifs_NTtimeToUnix(pfindData->LastWriteTime);
-               tmp_inode->i_ctime =
-                       cifs_NTtimeToUnix(pfindData->ChangeTime);
-       } else { /* legacy, OS2 and DOS style */
-               int offset = cifs_sb->tcon->ses->server->timeAdj;
-               FIND_FILE_STANDARD_INFO *pfindData =
-                       (FIND_FILE_STANDARD_INFO *)buf;
-
-               tmp_inode->i_mtime = cnvrtDosUnixTm(pfindData->LastWriteDate,
-                                                   pfindData->LastWriteTime,
-                                                   offset);
-               tmp_inode->i_atime = cnvrtDosUnixTm(pfindData->LastAccessDate,
-                                                   pfindData->LastAccessTime,
-                                                   offset);
-               tmp_inode->i_ctime = cnvrtDosUnixTm(pfindData->LastWriteDate,
-                                                   pfindData->LastWriteTime,
-                                                   offset);
-               attr = le16_to_cpu(pfindData->Attributes);
-               allocation_size = le32_to_cpu(pfindData->AllocationSize);
-               end_of_file = le32_to_cpu(pfindData->DataSize);
-       }
-
-       /* Linux can not store file creation time unfortunately so ignore it */
-
-       cifsInfo->cifsAttrs = attr;
-#ifdef CONFIG_CIFS_EXPERIMENTAL
-       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
-               /* get more accurate mode via ACL - so force inode refresh */
-               cifsInfo->time = 0;
-       } else
-#endif /* CONFIG_CIFS_EXPERIMENTAL */
-               cifsInfo->time = jiffies;
-
-       /* treat dos attribute of read-only as read-only mode bit e.g. 555? */
-       /* 2767 perms - indicate mandatory locking */
-               /* BB fill in uid and gid here? with help from winbind?
-                  or retrieve from NTFS stream extended attribute */
-       if (atomic_read(&cifsInfo->inUse) == 0) {
-               tmp_inode->i_uid = cifs_sb->mnt_uid;
-               tmp_inode->i_gid = cifs_sb->mnt_gid;
+               fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
+               fattr->cf_dtype = DT_REG;
        }
 
-       if (attr & ATTR_DIRECTORY)
-               default_mode = cifs_sb->mnt_dir_mode;
-       else
-               default_mode = cifs_sb->mnt_file_mode;
-
-       /* set initial permissions */
-       if ((atomic_read(&cifsInfo->inUse) == 0) ||
-           (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
-               tmp_inode->i_mode = default_mode;
-       else {
-               /* just reenable write bits if !ATTR_READONLY */
-               if ((tmp_inode->i_mode & S_IWUGO) == 0 &&
-                   (attr & ATTR_READONLY) == 0)
-                       tmp_inode->i_mode |= (S_IWUGO & default_mode);
-
-               tmp_inode->i_mode &= ~S_IFMT;
-       }
-
-       /* clear write bits if ATTR_READONLY is set */
-       if (attr & ATTR_READONLY)
-               tmp_inode->i_mode &= ~S_IWUGO;
+       if (fattr->cf_cifsattrs & ATTR_READONLY)
+               fattr->cf_mode &= ~S_IWUGO;
 
-       /* set inode type */
-       if ((attr & ATTR_SYSTEM) &&
-           (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) {
-               if (end_of_file == 0)  {
-                       tmp_inode->i_mode |= S_IFIFO;
-                       *pobject_type = DT_FIFO;
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL &&
+           fattr->cf_cifsattrs & ATTR_SYSTEM) {
+               if (fattr->cf_eof == 0)  {
+                       fattr->cf_mode &= ~S_IFMT;
+                       fattr->cf_mode |= S_IFIFO;
+                       fattr->cf_dtype = DT_FIFO;
                } else {
                        /*
-                        * trying to get the type can be slow, so just call
-                        * this a regular file for now, and mark for reval
+                        * trying to get the type and mode via SFU can be slow,
+                        * so just call those regular files for now, and mark
+                        * for reval
                         */
-                       tmp_inode->i_mode |= S_IFREG;
-                       *pobject_type = DT_REG;
-                       cifsInfo->time = 0;
-               }
-       } else {
-               if (attr & ATTR_DIRECTORY) {
-                       tmp_inode->i_mode |= S_IFDIR;
-                       *pobject_type = DT_DIR;
-               } else {
-                       tmp_inode->i_mode |= S_IFREG;
-                       *pobject_type = DT_REG;
+                       fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
                }
        }
+}
 
-       /* can not fill in nlink here as in qpathinfo version and Unx search */
-       if (atomic_read(&cifsInfo->inUse) == 0)
-               atomic_set(&cifsInfo->inUse, 1);
+void
+cifs_dir_info_to_fattr(struct cifs_fattr *fattr, FILE_DIRECTORY_INFO *info,
+                      struct cifs_sb_info *cifs_sb)
+{
+       memset(fattr, 0, sizeof(*fattr));
+       fattr->cf_cifsattrs = le32_to_cpu(info->ExtFileAttributes);
+       fattr->cf_eof = le64_to_cpu(info->EndOfFile);
+       fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
+       fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
+       fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
+       fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
+
+       cifs_fill_common_info(fattr, cifs_sb);
+}
 
-       cifsInfo->server_eof = end_of_file;
-       spin_lock(&tmp_inode->i_lock);
-       if (is_size_safe_to_change(cifsInfo, end_of_file)) {
-               /* can not safely change the file size here if the
-               client is writing to it due to potential races */
-               i_size_write(tmp_inode, end_of_file);
+void
+cifs_std_info_to_fattr(struct cifs_fattr *fattr, FIND_FILE_STANDARD_INFO *info,
+                      struct cifs_sb_info *cifs_sb)
+{
+       int offset = cifs_sb->tcon->ses->server->timeAdj;
 
-       /* 512 bytes (2**9) is the fake blocksize that must be used */
-       /* for this calculation, even though the reported blocksize is larger */
-               tmp_inode->i_blocks = (512 - 1 + allocation_size) >> 9;
-       }
-       spin_unlock(&tmp_inode->i_lock);
-
-       if (allocation_size < end_of_file)
-               cFYI(1, ("May be sparse file, allocation less than file size"));
-       cFYI(1, ("File Size %ld and blocks %llu",
-               (unsigned long)tmp_inode->i_size,
-               (unsigned long long)tmp_inode->i_blocks));
-       if (S_ISREG(tmp_inode->i_mode)) {
-               cFYI(1, ("File inode"));
-               tmp_inode->i_op = &cifs_file_inode_ops;
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
-                       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
-                               tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
-                       else
-                               tmp_inode->i_fop = &cifs_file_direct_ops;
-               } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
-                       tmp_inode->i_fop = &cifs_file_nobrl_ops;
-               else
-                       tmp_inode->i_fop = &cifs_file_ops;
-
-               if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
-                  (cifs_sb->tcon->ses->server->maxBuf <
-                       PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
-                       tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
-               else
-                       tmp_inode->i_data.a_ops = &cifs_addr_ops;
-
-               if (isNewInode)
-                       return; /* No sense invalidating pages for new inode
-                                  since have not started caching readahead file
-                                  data yet */
-
-               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);
-               }
-       } else if (S_ISDIR(tmp_inode->i_mode)) {
-               cFYI(1, ("Directory inode"));
-               tmp_inode->i_op = &cifs_dir_inode_ops;
-               tmp_inode->i_fop = &cifs_dir_ops;
-       } else if (S_ISLNK(tmp_inode->i_mode)) {
-               cFYI(1, ("Symbolic Link inode"));
-               tmp_inode->i_op = &cifs_symlink_inode_ops;
-       } else {
-               cFYI(1, ("Init special inode"));
-               init_special_inode(tmp_inode, tmp_inode->i_mode,
-                                  tmp_inode->i_rdev);
-       }
+       memset(fattr, 0, sizeof(*fattr));
+       fattr->cf_atime = cnvrtDosUnixTm(info->LastAccessDate,
+                                           info->LastAccessTime, offset);
+       fattr->cf_ctime = cnvrtDosUnixTm(info->LastWriteDate,
+                                           info->LastWriteTime, offset);
+       fattr->cf_mtime = cnvrtDosUnixTm(info->LastWriteDate,
+                                           info->LastWriteTime, offset);
+
+       fattr->cf_cifsattrs = le16_to_cpu(info->Attributes);
+       fattr->cf_bytes = le32_to_cpu(info->AllocationSize);
+       fattr->cf_eof = le32_to_cpu(info->DataSize);
+
+       cifs_fill_common_info(fattr, cifs_sb);
 }
 
 /* BB eventually need to add the following helper function to
@@ -846,11 +681,10 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir,
        int rc = 0;
        struct qstr qstring;
        struct cifsFileInfo *pCifsF;
-       unsigned int obj_type;
-       __u64  inum;
+       u64    inum;
        ino_t  ino;
+       struct super_block *sb;
        struct cifs_sb_info *cifs_sb;
-       struct inode *tmp_inode;
        struct dentry *tmp_dentry;
        struct cifs_fattr fattr;
 
@@ -870,71 +704,53 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir,
        if (rc != 0)
                return 0;
 
-       cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
+       sb = file->f_path.dentry->d_sb;
+       cifs_sb = CIFS_SB(sb);
 
        qstring.name = scratch_buf;
        rc = cifs_get_name_from_search_buf(&qstring, pfindEntry,
                        pCifsF->srch_inf.info_level,
                        pCifsF->srch_inf.unicode, cifs_sb,
-                       max_len,
-                       &inum /* returned */);
+                       max_len, &inum /* returned */);
 
        if (rc)
                return rc;
 
-       /* only these two infolevels return valid inode numbers */
-       if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
+       if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX)
                cifs_unix_basic_to_fattr(&fattr,
                                 &((FILE_UNIX_INFO *) pfindEntry)->basic,
                                 cifs_sb);
-               tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring,
-                                                &fattr);
-               obj_type = fattr.cf_dtype;
-               ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid);
-       } else {
-               if (pCifsF->srch_inf.info_level ==
-                   SMB_FIND_FILE_ID_FULL_DIR_INFO)
-                       rc = construct_dentry(&qstring, file, &tmp_inode,
-                                               &tmp_dentry, &inum);
-               else
-                       rc = construct_dentry(&qstring, file, &tmp_inode,
-                                               &tmp_dentry, NULL);
-
-               if ((tmp_inode == NULL) || (tmp_dentry == NULL)) {
-                       rc = -ENOMEM;
-                       goto out;
-               }
-
-               /* we pass in rc below, indicating whether it is a new inode,
-                * so we can figure out whether to invalidate the inode cached
-                * data if the file has changed
-                */
-               if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD)
-                       fill_in_inode(tmp_inode, 0, pfindEntry, &obj_type, rc);
-               else
-                       fill_in_inode(tmp_inode, 1, pfindEntry, &obj_type, rc);
+       else if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD)
+               cifs_std_info_to_fattr(&fattr, (FIND_FILE_STANDARD_INFO *)
+                                       pfindEntry, cifs_sb);
+       else
+               cifs_dir_info_to_fattr(&fattr, (FILE_DIRECTORY_INFO *)
+                                       pfindEntry, cifs_sb);
 
-               /* new inode - needs to be tied to dentry */
-               if (rc) {
-                       d_instantiate(tmp_dentry, tmp_inode);
-                       if (rc == 2)
-                               d_rehash(tmp_dentry);
-               }
+       /* FIXME: make _to_fattr functions fill this out */
+       if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_ID_FULL_DIR_INFO)
+               fattr.cf_uniqueid = inum;
+       else
+               fattr.cf_uniqueid = iunique(sb, ROOT_I);
 
-               ino = cifs_uniqueid_to_ino_t(tmp_inode->i_ino);
-       }
+       ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid);
+       tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring, &fattr);
 
        rc = filldir(direntry, qstring.name, qstring.len, file->f_pos,
-                    ino, obj_type);
+                    ino, fattr.cf_dtype);
+
+       /*
+        * we can not return filldir errors to the caller since they are
+        * "normal" when the stat blocksize is too small - we return remapped
+        * error instead
+        *
+        * FIXME: This looks bogus. filldir returns -EOVERFLOW in the above
+        * case already. Why should we be clobbering other errors from it?
+        */
        if (rc) {
                cFYI(1, ("filldir rc = %d", rc));
-               /* we can not return filldir errors to the caller
-               since they are "normal" when the stat blocksize
-               is too small - we return remapped error instead */
                rc = -EOVERFLOW;
        }
-
-out:
        dput(tmp_dentry);
        return rc;
 }