* [PATCH] cifs: fix usage of d_materialise_unique in cifs_get_root
@ 2011-07-18 12:03 Jeff Layton
2011-07-18 16:45 ` Al Viro
0 siblings, 1 reply; 5+ messages in thread
From: Jeff Layton @ 2011-07-18 12:03 UTC (permalink / raw)
To: smfrench; +Cc: linux-cifs, linux-fsdevel, piastryyy, viro
It currently calls d_lookup to get a dentry and then passes that to
d_materialise_unique. This is wrong as d_materialise_unique is intended
to introduce a new dentry into the tree. It also uses d_lookup when
lookup_one_len would generally be a better choice since it does
permission checks.
Also, fix the dentry hash calculation to work with nocase mounts.
Cc: Pavel Shilovsky <piastryyy@gmail.com>
Reported-by: Al Viro <viro@ZenIV.linux.org.uk>
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/cifs/cifsfs.c | 73 +++++++++++++++++++++++++++++++-----------------------
1 files changed, 42 insertions(+), 31 deletions(-)
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 9dd4375..fdb96eb 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -35,6 +35,7 @@
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
+#include <linux/namei.h>
#include <net/ipv6.h>
#include "cifsfs.h"
#include "cifspdu.h"
@@ -556,47 +557,57 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
full_path[i] = 0;
cFYI(1, "get dentry for %s", pstart);
+ dchild = lookup_one_len(pstart, dparent, len);
+ if (dchild != NULL) {
+ if (dchild->d_inode != NULL)
+ goto next_component;
+ cFYI(1, "dentry is negative");
+ dput(dchild);
+ } else {
+ cFYI(1, "dentry does not exist");
+ }
+
name.name = pstart;
name.len = len;
- name.hash = full_name_hash(pstart, len);
- dchild = d_lookup(dparent, &name);
+ if (dparent->d_op && dparent->d_op->d_hash)
+ dparent->d_op->d_hash(dparent, dparent->d_inode, &name);
+ else
+ name.hash = full_name_hash(pstart, len);
+
+ dchild = d_alloc(dparent, &name);
if (dchild == NULL) {
- cFYI(1, "not exists");
- dchild = d_alloc(dparent, &name);
- if (dchild == NULL) {
- dput(dparent);
- dparent = ERR_PTR(-ENOMEM);
- goto out;
- }
+ dput(dparent);
+ dparent = ERR_PTR(-ENOMEM);
+ goto out;
}
cFYI(1, "get inode");
- if (dchild->d_inode == NULL) {
- cFYI(1, "not exists");
- inode = NULL;
- if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext)
- rc = cifs_get_inode_info_unix(&inode, full_path,
- sb, xid);
- else
- rc = cifs_get_inode_info(&inode, full_path,
- NULL, sb, xid, NULL);
- if (rc) {
- dput(dchild);
+ inode = NULL;
+ if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext)
+ rc = cifs_get_inode_info_unix(&inode, full_path,
+ sb, xid);
+ else
+ rc = cifs_get_inode_info(&inode, full_path,
+ NULL, sb, xid, NULL);
+ if (rc) {
+ dput(dchild);
+ dput(dparent);
+ dparent = ERR_PTR(rc);
+ goto out;
+ }
+
+ alias = d_materialise_unique(dchild, inode);
+ if (alias != NULL) {
+ dput(dchild);
+ if (IS_ERR(alias)) {
dput(dparent);
- dparent = ERR_PTR(rc);
+ dparent = ERR_CAST(alias);
goto out;
}
- alias = d_materialise_unique(dchild, inode);
- if (alias != NULL) {
- dput(dchild);
- if (IS_ERR(alias)) {
- dput(dparent);
- dparent = ERR_PTR(-EINVAL); /* XXX */
- goto out;
- }
- dchild = alias;
- }
+ dchild = alias;
}
+
+next_component:
cFYI(1, "parent %p, child %p", dparent, dchild);
dput(dparent);
--
1.7.6
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH] cifs: fix usage of d_materialise_unique in cifs_get_root
2011-07-18 12:03 [PATCH] cifs: fix usage of d_materialise_unique in cifs_get_root Jeff Layton
@ 2011-07-18 16:45 ` Al Viro
2011-07-18 17:34 ` Al Viro
0 siblings, 1 reply; 5+ messages in thread
From: Al Viro @ 2011-07-18 16:45 UTC (permalink / raw)
To: Jeff Layton; +Cc: smfrench, linux-cifs, linux-fsdevel, piastryyy
On Mon, Jul 18, 2011 at 08:03:14AM -0400, Jeff Layton wrote:
> It currently calls d_lookup to get a dentry and then passes that to
> d_materialise_unique. This is wrong as d_materialise_unique is intended
> to introduce a new dentry into the tree. It also uses d_lookup when
> lookup_one_len would generally be a better choice since it does
> permission checks.
>
> Also, fix the dentry hash calculation to work with nocase mounts.
Huh? First of all, lookup_one_len() doesn't return NULL on failure,
it returns ERR_PTR(). What's more, it already does d_alloc(), ->lookup(),
etc. and you don't need to bother with d_materialise_unique() and this
lookup-by-hand code in there. Or with calculating hash - also done
by lookup_one_len(), TYVM... If anything, I'd start with this as the first
approximation and probably looked into simplifying the loop a bit more -
lookup_one_len() doesn't need name component to be NUL-terminated...
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 112fbd96..2d74619 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -574,51 +574,13 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
full_path[i] = 0;
cFYI(1, "get dentry for %s", pstart);
- name.name = pstart;
- name.len = len;
- name.hash = full_name_hash(pstart, len);
- dchild = d_lookup(dparent, &name);
- if (dchild == NULL) {
- cFYI(1, "not exists");
- dchild = d_alloc(dparent, &name);
- if (dchild == NULL) {
- dput(dparent);
- dparent = ERR_PTR(-ENOMEM);
- goto out;
- }
- }
-
- cFYI(1, "get inode");
- if (dchild->d_inode == NULL) {
- cFYI(1, "not exists");
- inode = NULL;
- if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext)
- rc = cifs_get_inode_info_unix(&inode, full_path,
- sb, xid);
- else
- rc = cifs_get_inode_info(&inode, full_path,
- NULL, sb, xid, NULL);
- if (rc) {
- dput(dchild);
- dput(dparent);
- dparent = ERR_PTR(rc);
- goto out;
- }
- alias = d_materialise_unique(dchild, inode);
- if (alias != NULL) {
- dput(dchild);
- if (IS_ERR(alias)) {
- dput(dparent);
- dparent = ERR_PTR(-EINVAL); /* XXX */
- goto out;
- }
- dchild = alias;
- }
- }
- cFYI(1, "parent %p, child %p", dparent, dchild);
-
+ mutex_lock(&dparent->d_inode->i_mutex);
+ dchild = lookup_one_len(pstart, dparent->d_inode, len);
+ mutex_unlock(&dparent->d_inode->i_mutex);
dput(dparent);
dparent = dchild;
+ if (IS_ERR(dparent))
+ break;
len = 0;
pstart = full_path + i + 1;
full_path[i] = sep;
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH] cifs: fix usage of d_materialise_unique in cifs_get_root
2011-07-18 16:45 ` Al Viro
@ 2011-07-18 17:34 ` Al Viro
[not found] ` <20110718173454.GC11013-3bDd1+5oDREiFSDQTTA3OLVCufUGDwFn@public.gmane.org>
0 siblings, 1 reply; 5+ messages in thread
From: Al Viro @ 2011-07-18 17:34 UTC (permalink / raw)
To: Jeff Layton; +Cc: smfrench, linux-cifs, linux-fsdevel, piastryyy
On Mon, Jul 18, 2011 at 05:45:02PM +0100, Al Viro wrote:
> lookup-by-hand code in there. Or with calculating hash - also done
> by lookup_one_len(), TYVM... If anything, I'd start with this as the first
> approximation and probably looked into simplifying the loop a bit more -
> lookup_one_len() doesn't need name component to be NUL-terminated...
Fix cifs_get_root()
Add missing ->i_mutex, convert to lookup_one_len() instead of
(broken) open-coded analog, cope with getting something like
a//b as relative pathname. Simplify the hell out of it, while
we are there...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 112fbd96..cbbb55e 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -35,6 +35,7 @@
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
+#include <linux/namei.h>
#include <net/ipv6.h>
#include "cifsfs.h"
#include "cifspdu.h"
@@ -542,14 +543,12 @@ static const struct super_operations cifs_super_ops = {
static struct dentry *
cifs_get_root(struct smb_vol *vol, struct super_block *sb)
{
- int xid, rc;
- struct inode *inode;
- struct qstr name;
- struct dentry *dparent = NULL, *dchild = NULL, *alias;
+ struct dentry *dentry;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
- unsigned int i, full_len, len;
- char *full_path = NULL, *pstart;
+ char *full_path = NULL;
+ char *s, *p;
char sep;
+ int xid;
full_path = cifs_build_path_to_root(vol, cifs_sb,
cifs_sb_master_tcon(cifs_sb));
@@ -560,73 +559,32 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
xid = GetXid();
sep = CIFS_DIR_SEP(cifs_sb);
- dparent = dget(sb->s_root);
- full_len = strlen(full_path);
- full_path[full_len] = sep;
- pstart = full_path + 1;
-
- for (i = 1, len = 0; i <= full_len; i++) {
- if (full_path[i] != sep || !len) {
- len++;
- continue;
- }
-
- full_path[i] = 0;
- cFYI(1, "get dentry for %s", pstart);
-
- name.name = pstart;
- name.len = len;
- name.hash = full_name_hash(pstart, len);
- dchild = d_lookup(dparent, &name);
- if (dchild == NULL) {
- cFYI(1, "not exists");
- dchild = d_alloc(dparent, &name);
- if (dchild == NULL) {
- dput(dparent);
- dparent = ERR_PTR(-ENOMEM);
- goto out;
- }
- }
-
- cFYI(1, "get inode");
- if (dchild->d_inode == NULL) {
- cFYI(1, "not exists");
- inode = NULL;
- if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext)
- rc = cifs_get_inode_info_unix(&inode, full_path,
- sb, xid);
- else
- rc = cifs_get_inode_info(&inode, full_path,
- NULL, sb, xid, NULL);
- if (rc) {
- dput(dchild);
- dput(dparent);
- dparent = ERR_PTR(rc);
- goto out;
- }
- alias = d_materialise_unique(dchild, inode);
- if (alias != NULL) {
- dput(dchild);
- if (IS_ERR(alias)) {
- dput(dparent);
- dparent = ERR_PTR(-EINVAL); /* XXX */
- goto out;
- }
- dchild = alias;
- }
- }
- cFYI(1, "parent %p, child %p", dparent, dchild);
-
- dput(dparent);
- dparent = dchild;
- len = 0;
- pstart = full_path + i + 1;
- full_path[i] = sep;
- }
-out:
+ dentry = dget(sb->s_root);
+ p = s = full_path;
+
+ do {
+ struct inode *dir = dentry->d_inode;
+ struct dentry *child;
+
+ /* skip separators */
+ while (*s == sep)
+ s++;
+ if (!*s)
+ break;
+ p = s++;
+ /* next separator */
+ while (*s && *s != sep)
+ s++;
+
+ mutex_lock(&dir->i_mutex);
+ child = lookup_one_len(p, dentry, s - p);
+ mutex_unlock(&dir->i_mutex);
+ dput(dentry);
+ dentry = child;
+ } while (!IS_ERR(dentry));
_FreeXid(xid);
kfree(full_path);
- return dparent;
+ return dentry;
}
static int cifs_set_super(struct super_block *sb, void *data)
^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2011-07-18 17:54 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-07-18 12:03 [PATCH] cifs: fix usage of d_materialise_unique in cifs_get_root Jeff Layton
2011-07-18 16:45 ` Al Viro
2011-07-18 17:34 ` Al Viro
[not found] ` <20110718173454.GC11013-3bDd1+5oDREiFSDQTTA3OLVCufUGDwFn@public.gmane.org>
2011-07-18 17:49 ` Jeff Layton
2011-07-18 17:54 ` Al Viro
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).