From patchwork Sun Apr 5 13:09:21 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Layton X-Patchwork-Id: 16425 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 n35DAAb9003871 for ; Sun, 5 Apr 2009 13:10:10 GMT Received: from dp.samba.org (localhost [127.0.0.1]) by lists.samba.org (Postfix) with ESMTP id B5B39163CDC for ; Sun, 5 Apr 2009 13:09:51 +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 CEB71163C11 for ; Sun, 5 Apr 2009 13:09:06 +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 n35D9OJ6001419; Sun, 5 Apr 2009 09:09:24 -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 n35D9P41027836; Sun, 5 Apr 2009 09:09:26 -0400 Received: from localhost.localdomain (vpn-12-24.rdu.redhat.com [10.11.12.24]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id n35D9M63018279; Sun, 5 Apr 2009 09:09:24 -0400 From: Jeff Layton To: linux-cifs-client@lists.samba.org Date: Sun, 5 Apr 2009 09:09:21 -0400 Message-Id: <1238936961-6979-4-git-send-email-jlayton@redhat.com> In-Reply-To: <1238936961-6979-1-git-send-email-jlayton@redhat.com> References: <1238936961-6979-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 3/3] cifs: add cifs_iget_unix and have readdir codepath 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 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 --- 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);