From: Al Viro <[email protected]>

Signed-off-by: Al Viro <[email protected]>
---
 fs/namei.c | 37 ++++++++++++++++++++++++++-----------
 1 file changed, 26 insertions(+), 11 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index 090214b..4d6065d 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -536,10 +536,19 @@ static void restore_nameidata(struct nameidata *old)
 
 static int __nd_alloc_stack(struct nameidata *nd)
 {
-       struct saved *p = kmalloc(MAXSYMLINKS * sizeof(struct saved),
+       struct saved *p;
+
+       if (nd->flags & LOOKUP_RCU) {
+               p= kmalloc(MAXSYMLINKS * sizeof(struct saved),
+                                 GFP_ATOMIC);
+               if (unlikely(!p))
+                       return -ECHILD;
+       } else {
+               p= kmalloc(MAXSYMLINKS * sizeof(struct saved),
                                  GFP_KERNEL);
-       if (unlikely(!p))
-               return -ENOMEM;
+               if (unlikely(!p))
+                       return -ENOMEM;
+       }
        memcpy(p, nd->internal, sizeof(nd->internal));
        nd->stack = p;
        return 0;
@@ -949,8 +958,10 @@ const char *get_link(struct nameidata *nd)
        int error;
        const char *res;
 
-       BUG_ON(nd->flags & LOOKUP_RCU);
-
+       if (nd->flags & LOOKUP_RCU) {
+               if (unlikely(unlazy_walk(nd, NULL, 0)))
+                       return ERR_PTR(-ECHILD);
+       }
        cond_resched();
 
        touch_atime(&last->link);
@@ -1632,17 +1643,21 @@ static int pick_link(struct nameidata *nd, struct path 
*link,
                path_to_nameidata(link, nd);
                return -ELOOP;
        }
-       if (nd->flags & LOOKUP_RCU) {
-               if (unlikely(unlazy_link(nd, link, seq)))
-                       return -ECHILD;
-       } else {
+       if (!(nd->flags & LOOKUP_RCU)) {
                if (link->mnt == nd->path.mnt)
                        mntget(link->mnt);
        }
        error = nd_alloc_stack(nd);
        if (unlikely(error)) {
-               path_put(link);
-               return error;
+               if (error == -ECHILD) {
+                       if (unlikely(unlazy_link(nd, link, seq)))
+                               return -ECHILD;
+                       error = nd_alloc_stack(nd);
+               }
+               if (error) {
+                       path_put(link);
+                       return error;
+               }
        }
 
        last = nd->stack + nd->depth++;
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to