Add a cifs_iget_unix function similar to cifs_iget_unix_basic. This will ID inodes based on the UniqueId value in a FILE_INFO_UNIX struct. Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxx> --- fs/cifs/cifsproto.h | 4 ++ fs/cifs/inode.c | 18 ++++++ fs/cifs/readdir.c | 147 +++++++++++++++++++++++++++++++++++++------------- 3 files changed, 131 insertions(+), 38 deletions(-) diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 51dfd51..53b79ad 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -100,9 +100,13 @@ extern int cifs_posix_open(char *full_path, struct inode **pinode, int *poplock, __u16 *pnetfid, int xid); extern void posix_fill_in_inode(struct inode *tmp_inode, FILE_UNIX_BASIC_INFO *pData); +extern void unix_fill_in_inode(struct inode *tmp_inode, + FILE_UNIX_INFO *pData); extern struct inode *cifs_new_inode(struct super_block *sb, __u64 *inum); extern struct inode *cifs_iget_unix_basic(struct super_block *sb, FILE_UNIX_BASIC_INFO *info); +extern struct inode *cifs_iget_unix(struct super_block *sb, + FILE_UNIX_INFO *info); extern int cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path, FILE_ALL_INFO *pfile_info, diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index c30c318..ac7336a 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -759,6 +759,24 @@ cifs_iget_unix_basic(struct super_block *sb, FILE_UNIX_BASIC_INFO *info) return inode; } +struct inode * +cifs_iget_unix(struct super_block *sb, FILE_UNIX_INFO *info) +{ + struct inode *inode; + + inode = cifs_iget_locked(sb, le64_to_cpu(info->UniqueId)); + if (!inode) + return ERR_PTR(-ENOMEM); + + /* update inode since we have info in hand */ + unix_fill_in_inode(inode, info); + + if (inode->i_state & I_NEW) + unlock_new_inode(inode); + + return inode; +} + /* gets root inode */ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) { diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 1a8be62..4b59ccb 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -56,6 +56,80 @@ static inline void dump_cifs_file_struct(struct file *file, char *label) } #endif /* DEBUG2 */ +static unsigned int +cifs_dentry_type_unix(u32 type) +{ + switch (type) { + case UNIX_FILE: + return DT_REG; + case UNIX_SYMLINK: + return DT_LNK; + case UNIX_DIR: + return DT_DIR; + case UNIX_CHARDEV: + return DT_CHR; + case UNIX_BLOCKDEV: + return DT_BLK; + case UNIX_FIFO: + return DT_FIFO; + case UNIX_SOCKET: + return DT_SOCK; + default: + /* safest to just call it a file */ + cFYI(1, ("unknown inode type %d", type)); + return DT_REG; + } +} + +/* + * Find the dentry that matches "name". If there isn't one, create + * one. If it's a negative dentry, then drop it and recreate it. + */ +static struct dentry * +cifs_readdir_lookup_unix(struct dentry *parent, struct qstr *name, + FILE_UNIX_INFO *info) +{ + struct dentry *dentry, *alias; + struct inode *inode; + struct super_block *sb = parent->d_inode->i_sb; + + cFYI(1, ("For %s", name->name)); + + dentry = d_lookup(parent, name); + if (dentry) { + /* BB: check for inode number change */ + if (dentry->d_inode != NULL) + return dentry; + d_drop(dentry); + dput(dentry); + } + + dentry = d_alloc(parent, name); + if (dentry == NULL) + return NULL; + + inode = cifs_iget_unix(sb, info); + if (IS_ERR(inode)) { + dput(dentry); + return NULL; + } + + if (CIFS_SB(sb)->tcon->nocase) + dentry->d_op = &cifs_ci_dentry_ops; + else + dentry->d_op = &cifs_dentry_ops; + + alias = d_materialise_unique(dentry, inode); + if (alias != NULL) { + dput(dentry); + if (IS_ERR(alias)) + return NULL; + dentry = alias; + } + + 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 @@ -69,7 +143,6 @@ construct_dentry(struct qstr *qstring, struct file *file, cFYI(1, ("For %s", qstring->name)); - qstring->hash = full_name_hash(qstring->name, qstring->len); tmp_dentry = d_lookup(file->f_path.dentry, qstring); if (tmp_dentry) { /* BB: overwrite old name? i.e. tmp_dentry->d_name and @@ -304,8 +377,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, } } -static void unix_fill_in_inode(struct inode *tmp_inode, - FILE_UNIX_INFO *pfindData, unsigned int *pobject_type, int isNewInode) +void unix_fill_in_inode(struct inode *tmp_inode, FILE_UNIX_INFO *pfindData) { loff_t local_size; struct timespec local_mtime; @@ -335,33 +407,25 @@ static void unix_fill_in_inode(struct inode *tmp_inode, to avoid strange results if bits above were corrupt */ tmp_inode->i_mode &= ~S_IFMT; if (type == UNIX_FILE) { - *pobject_type = DT_REG; tmp_inode->i_mode |= S_IFREG; } else if (type == UNIX_SYMLINK) { - *pobject_type = DT_LNK; tmp_inode->i_mode |= S_IFLNK; } else if (type == UNIX_DIR) { - *pobject_type = DT_DIR; tmp_inode->i_mode |= S_IFDIR; } else if (type == UNIX_CHARDEV) { - *pobject_type = DT_CHR; tmp_inode->i_mode |= S_IFCHR; tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor), le64_to_cpu(pfindData->DevMinor) & MINORMASK); } else if (type == UNIX_BLOCKDEV) { - *pobject_type = DT_BLK; tmp_inode->i_mode |= S_IFBLK; tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor), le64_to_cpu(pfindData->DevMinor) & MINORMASK); } else if (type == UNIX_FIFO) { - *pobject_type = DT_FIFO; tmp_inode->i_mode |= S_IFIFO; } else if (type == UNIX_SOCKET) { - *pobject_type = DT_SOCK; tmp_inode->i_mode |= S_IFSOCK; } else { /* safest to just call it a file */ - *pobject_type = DT_REG; tmp_inode->i_mode |= S_IFREG; cFYI(1, ("unknown inode type %d", type)); } @@ -410,7 +474,7 @@ static void unix_fill_in_inode(struct inode *tmp_inode, else tmp_inode->i_data.a_ops = &cifs_addr_ops; - if (isNewInode) + if (tmp_inode->i_state & I_NEW) return; /* No sense invalidating pages for new inode since we have not started caching readahead file data for it yet */ @@ -939,36 +1003,43 @@ static int cifs_filldir(char *pfindEntry, struct file *file, return rc; /* only these two infolevels return valid inode numbers */ - if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX || - 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 (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) { + FILE_UNIX_INFO *info = (FILE_UNIX_INFO *) pfindEntry; - if ((tmp_inode == NULL) || (tmp_dentry == NULL)) - return -ENOMEM; + tmp_dentry = cifs_readdir_lookup_unix(file->f_dentry, &qstring, + info); + if (!tmp_dentry) + return -ENOMEM; - /* 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_UNIX) - unix_fill_in_inode(tmp_inode, - (FILE_UNIX_INFO *)pfindEntry, - &obj_type, rc); - else if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) - fill_in_inode(tmp_inode, 0 /* old level 1 buffer type */, - pfindEntry, &obj_type, rc); - else - fill_in_inode(tmp_inode, 1 /* NT */, pfindEntry, &obj_type, rc); + obj_type = cifs_dentry_type_unix(le32_to_cpu(info->Type)); + } 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 (rc) /* new inode - needs to be tied to dentry */ { - d_instantiate(tmp_dentry, tmp_inode); - if (rc == 2) - d_rehash(tmp_dentry); - } + if ((tmp_inode == NULL) || (tmp_dentry == NULL)) + return -ENOMEM; + + /* 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); + /* new inode - needs to be tied to dentry */ + if (rc) { + d_instantiate(tmp_dentry, tmp_inode); + if (rc == 2) + d_rehash(tmp_dentry); + } + } rc = filldir(direntry, qstring.name, qstring.len, file->f_pos, tmp_inode->i_ino, obj_type); -- 1.6.0.6 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html