]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - mm/mempolicy.c
mempolicy: use struct mempolicy pointer in shmem_sb_info
[net-next-2.6.git] / mm / mempolicy.c
index 6b751565eed17172349a8e397782907f374b876c..a37a5034f63dda824f15b5ffb89156fea43fb4a3 100644 (file)
@@ -1828,27 +1828,35 @@ restart:
        return 0;
 }
 
-void mpol_shared_policy_init(struct shared_policy *info, unsigned short policy,
-                       unsigned short flags, nodemask_t *policy_nodes)
-{
-       info->root = RB_ROOT;
-       spin_lock_init(&info->lock);
-
-       if (policy != MPOL_DEFAULT) {
-               struct mempolicy *newpol;
-
-               /* Falls back to NULL policy [MPOL_DEFAULT] on any error */
-               newpol = mpol_new(policy, flags, policy_nodes);
-               if (!IS_ERR(newpol)) {
-                       /* Create pseudo-vma that contains just the policy */
-                       struct vm_area_struct pvma;
-
-                       memset(&pvma, 0, sizeof(struct vm_area_struct));
-                       /* Policy covers entire file */
-                       pvma.vm_end = TASK_SIZE;
-                       mpol_set_shared_policy(info, &pvma, newpol);
-                       mpol_put(newpol);
-               }
+/**
+ * mpol_shared_policy_init - initialize shared policy for inode
+ * @sp: pointer to inode shared policy
+ * @mpol:  struct mempolicy to install
+ *
+ * Install non-NULL @mpol in inode's shared policy rb-tree.
+ * On entry, the current task has a reference on a non-NULL @mpol.
+ * This must be released on exit.
+ */
+void mpol_shared_policy_init(struct shared_policy *sp, struct mempolicy *mpol)
+{
+       sp->root = RB_ROOT;             /* empty tree == default mempolicy */
+       spin_lock_init(&sp->lock);
+
+       if (mpol) {
+               struct vm_area_struct pvma;
+               struct mempolicy *new;
+
+               /* contextualize the tmpfs mount point mempolicy */
+               new = mpol_new(mpol->mode, mpol->flags, &mpol->w.user_nodemask);
+               mpol_put(mpol); /* drop our ref on sb mpol */
+               if (IS_ERR(new))
+                       return;         /* no valid nodemask intersection */
+
+               /* Create pseudo-vma that contains just the policy */
+               memset(&pvma, 0, sizeof(struct vm_area_struct));
+               pvma.vm_end = TASK_SIZE;        /* policy covers entire file */
+               mpol_set_shared_policy(sp, &pvma, new); /* adds ref */
+               mpol_put(new);                  /* drop initial ref */
        }
 }
 
@@ -1962,18 +1970,27 @@ static const char * const policy_types[] =
 /**
  * mpol_parse_str - parse string to mempolicy
  * @str:  string containing mempolicy to parse
- * @mode:  pointer to returned policy mode
- * @mode_flags:  pointer to returned flags
- * @policy_nodes:  pointer to returned nodemask
+ * @mpol:  pointer to struct mempolicy pointer, returned on success.
+ * @no_context:  flag whether to "contextualize" the mempolicy
  *
  * Format of input:
  *     <mode>[=<flags>][:<nodelist>]
  *
- * Currently only used for tmpfs/shmem mount options
+ * if @no_context is true, save the input nodemask in w.user_nodemask in
+ * the returned mempolicy.  This will be used to "clone" the mempolicy in
+ * a specific context [cpuset] at a later time.  Used to parse tmpfs mpol
+ * mount option.  Note that if 'static' or 'relative' mode flags were
+ * specified, the input nodemask will already have been saved.  Saving
+ * it again is redundant, but safe.
+ *
+ * On success, returns 0, else 1
  */
-int mpol_parse_str(char *str, unsigned short *mode, unsigned short *mode_flags,
-                       nodemask_t *policy_nodes)
+int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context)
 {
+       struct mempolicy *new = NULL;
+       unsigned short uninitialized_var(mode);
+       unsigned short uninitialized_var(mode_flags);
+       nodemask_t nodes;
        char *nodelist = strchr(str, ':');
        char *flags = strchr(str, '=');
        int i;
@@ -1982,26 +1999,30 @@ int mpol_parse_str(char *str, unsigned short *mode, unsigned short *mode_flags,
        if (nodelist) {
                /* NUL-terminate mode or flags string */
                *nodelist++ = '\0';
-               if (nodelist_parse(nodelist, *policy_nodes))
+               if (nodelist_parse(nodelist, nodes))
                        goto out;
-               if (!nodes_subset(*policy_nodes, node_states[N_HIGH_MEMORY]))
+               if (!nodes_subset(nodes, node_states[N_HIGH_MEMORY]))
                        goto out;
-       }
+       } else
+               nodes_clear(nodes);
+
        if (flags)
                *flags++ = '\0';        /* terminate mode string */
 
        for (i = 0; i <= MPOL_LOCAL; i++) {
                if (!strcmp(str, policy_types[i])) {
-                       *mode = i;
+                       mode = i;
                        break;
                }
        }
        if (i > MPOL_LOCAL)
                goto out;
 
-       switch (*mode) {
+       switch (mode) {
        case MPOL_PREFERRED:
-               /* Insist on a nodelist of one node only */
+               /*
+                * Insist on a nodelist of one node only
+                */
                if (nodelist) {
                        char *rest = nodelist;
                        while (isdigit(*rest))
@@ -2010,63 +2031,73 @@ int mpol_parse_str(char *str, unsigned short *mode, unsigned short *mode_flags,
                                err = 0;
                }
                break;
-       case MPOL_BIND:
-               /* Insist on a nodelist */
-               if (nodelist)
-                       err = 0;
-               break;
        case MPOL_INTERLEAVE:
                /*
                 * Default to online nodes with memory if no nodelist
                 */
                if (!nodelist)
-                       *policy_nodes = node_states[N_HIGH_MEMORY];
+                       nodes = node_states[N_HIGH_MEMORY];
                err = 0;
                break;
-       default:
+       case MPOL_LOCAL:
                /*
-                * MPOL_DEFAULT or MPOL_LOCAL
-                * Don't allow a nodelist nor flags
+                * Don't allow a nodelist;  mpol_new() checks flags
                 */
-               if (!nodelist && !flags)
-                       err = 0;
-               if (*mode == MPOL_DEFAULT)
+               if (nodelist)
                        goto out;
-               /* else MPOL_LOCAL */
-               *mode = MPOL_PREFERRED;
-               nodes_clear(*policy_nodes);
+               mode = MPOL_PREFERRED;
                break;
+
+       /*
+        * case MPOL_BIND:    mpol_new() enforces non-empty nodemask.
+        * case MPOL_DEFAULT: mpol_new() enforces empty nodemask, ignores flags.
+        */
        }
 
-       *mode_flags = 0;
+       mode_flags = 0;
        if (flags) {
                /*
                 * Currently, we only support two mutually exclusive
                 * mode flags.
                 */
                if (!strcmp(flags, "static"))
-                       *mode_flags |= MPOL_F_STATIC_NODES;
+                       mode_flags |= MPOL_F_STATIC_NODES;
                else if (!strcmp(flags, "relative"))
-                       *mode_flags |= MPOL_F_RELATIVE_NODES;
+                       mode_flags |= MPOL_F_RELATIVE_NODES;
                else
                        err = 1;
        }
+
+       new = mpol_new(mode, mode_flags, &nodes);
+       if (IS_ERR(new))
+               err = 1;
+       else if (no_context)
+               new->w.user_nodemask = nodes;   /* save for contextualization */
+
 out:
        /* Restore string for error message */
        if (nodelist)
                *--nodelist = ':';
        if (flags)
                *--flags = '=';
+       if (!err)
+               *mpol = new;
        return err;
 }
 #endif /* CONFIG_TMPFS */
 
-/*
+/**
+ * mpol_to_str - format a mempolicy structure for printing
+ * @buffer:  to contain formatted mempolicy string
+ * @maxlen:  length of @buffer
+ * @pol:  pointer to mempolicy to be formatted
+ * @no_context:  "context free" mempolicy - use nodemask in w.user_nodemask
+ *
  * Convert a mempolicy into a string.
  * Returns the number of characters in buffer (if positive)
  * or an error (negative)
  */
-int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol)
+int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol, int no_context)
 {
        char *p = buffer;
        int l;
@@ -2100,7 +2131,10 @@ int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol)
        case MPOL_BIND:
                /* Fall through */
        case MPOL_INTERLEAVE:
-               nodes = pol->v.nodes;
+               if (no_context)
+                       nodes = pol->w.user_nodemask;
+               else
+                       nodes = pol->v.nodes;
                break;
 
        default:
@@ -2231,7 +2265,7 @@ int show_numa_map(struct seq_file *m, void *v)
                return 0;
 
        pol = get_vma_policy(priv->task, vma, vma->vm_start);
-       mpol_to_str(buffer, sizeof(buffer), pol);
+       mpol_to_str(buffer, sizeof(buffer), pol, 0);
        mpol_cond_put(pol);
 
        seq_printf(m, "%08lx %s", vma->vm_start, buffer);