OSDN Git Service

pick_link(): take reserving space on stack into a new helper
authorAl Viro <viro@zeniv.linux.org.uk>
Tue, 3 Mar 2020 16:22:34 +0000 (11:22 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Thu, 2 Apr 2020 05:09:25 +0000 (01:09 -0400)
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/namei.c

index 1f3d398..6025406 100644 (file)
@@ -1580,6 +1580,28 @@ static inline int may_lookup(struct nameidata *nd)
        return inode_permission(nd->inode, MAY_EXEC);
 }
 
+static int reserve_stack(struct nameidata *nd, struct path *link, unsigned seq)
+{
+       int error;
+
+       if (unlikely(nd->total_link_count++ >= MAXSYMLINKS))
+               return -ELOOP;
+       error = nd_alloc_stack(nd);
+       if (likely(!error))
+               return 0;
+       if (error == -ECHILD) {
+               // we must grab link first
+               bool grabbed_link = legitimize_path(nd, link, seq);
+               // ... and we must unlazy to be able to clean up
+               error = unlazy_walk(nd);
+               if (unlikely(!grabbed_link))
+                       error = -ECHILD;
+               if (!error)
+                       error = nd_alloc_stack(nd);
+       }
+       return error;
+}
+
 enum {WALK_TRAILING = 1, WALK_MORE = 2, WALK_NOFOLLOW = 4};
 
 static const char *pick_link(struct nameidata *nd, struct path *link,
@@ -1587,31 +1609,13 @@ static const char *pick_link(struct nameidata *nd, struct path *link,
 {
        struct saved *last;
        const char *res;
-       int error;
+       int error = reserve_stack(nd, link, seq);
 
-       if (unlikely(nd->total_link_count++ >= MAXSYMLINKS)) {
-               if (!(nd->flags & LOOKUP_RCU))
-                       path_put(link);
-               return ERR_PTR(-ELOOP);
-       }
-       error = nd_alloc_stack(nd);
        if (unlikely(error)) {
-               if (error == -ECHILD) {
-                       // we must grab link first
-                       bool grabbed_link = legitimize_path(nd, link, seq);
-                       // ... and we must unlazy to be able to clean up
-                       error = unlazy_walk(nd);
-                       if (unlikely(!grabbed_link))
-                               error = -ECHILD;
-                       if (!error)
-                               error = nd_alloc_stack(nd);
-               }
-               if (error) {
+               if (!(nd->flags & LOOKUP_RCU))
                        path_put(link);
-                       return ERR_PTR(error);
-               }
+               return ERR_PTR(error);
        }
-
        last = nd->stack + nd->depth++;
        last->link = *link;
        clear_delayed_call(&last->done);