]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 23 Oct 2008 17:22:40 +0000 (10:22 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 23 Oct 2008 17:22:40 +0000 (10:22 -0700)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: (46 commits)
  [PATCH] fs: add a sanity check in d_free
  [PATCH] i_version: remount support
  [patch] vfs: make security_inode_setattr() calling consistent
  [patch 1/3] FS_MBCACHE: don't needlessly make it built-in
  [PATCH] move executable checking into ->permission()
  [PATCH] fs/dcache.c: update comment of d_validate()
  [RFC PATCH] touch_mnt_namespace when the mount flags change
  [PATCH] reiserfs: add missing llseek method
  [PATCH] fix ->llseek for more directories
  [PATCH vfs-2.6 6/6] vfs: add LOOKUP_RENAME_TARGET intent
  [PATCH vfs-2.6 5/6] vfs: remove LOOKUP_PARENT from non LOOKUP_PARENT lookup
  [PATCH vfs-2.6 4/6] vfs: remove unnecessary fsnotify_d_instantiate()
  [PATCH vfs-2.6 3/6] vfs: add __d_instantiate() helper
  [PATCH vfs-2.6 2/6] vfs: add d_ancestor()
  [PATCH vfs-2.6 1/6] vfs: replace parent == dentry->d_parent by IS_ROOT()
  [PATCH] get rid of on-stack dentry in udf
  [PATCH 2/2] anondev: switch to IDA
  [PATCH 1/2] anondev: init IDR statically
  [JFFS2] Use d_splice_alias() not d_add() in jffs2_lookup()
  [PATCH] Optimise NFS readdir hack slightly.
  ...

1  2 
fs/ext3/super.c
fs/nfsd/export.c
fs/nfsd/vfs.c
init/main.c

diff --combined fs/ext3/super.c
index cac29ee3b14ab62054b6f45d74f36adaecab5200,5b7fee10566fb10cd9ace4e07e37aa0399dcbca9..34b6fca765d725fdf60f0d0ee7e924a0927f39c4
@@@ -393,8 -393,7 +393,8 @@@ static void ext3_put_super (struct supe
        int i;
  
        ext3_xattr_put_super(sb);
 -      journal_destroy(sbi->s_journal);
 +      if (journal_destroy(sbi->s_journal) < 0)
 +              ext3_abort(sb, __func__, "Couldn't clean up the journal");
        if (!(sb->s_flags & MS_RDONLY)) {
                EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);
                es->s_state = cpu_to_le16(sbi->s_mount_state);
@@@ -2297,9 -2296,7 +2297,9 @@@ static void ext3_mark_recovery_complete
        journal_t *journal = EXT3_SB(sb)->s_journal;
  
        journal_lock_updates(journal);
 -      journal_flush(journal);
 +      if (journal_flush(journal) < 0)
 +              goto out;
 +
        lock_super(sb);
        if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER) &&
            sb->s_flags & MS_RDONLY) {
                ext3_commit_super(sb, es, 1);
        }
        unlock_super(sb);
 +
 +out:
        journal_unlock_updates(journal);
  }
  
@@@ -2409,13 -2404,7 +2409,13 @@@ static void ext3_write_super_lockfs(str
  
                /* Now we set up the journal barrier. */
                journal_lock_updates(journal);
 -              journal_flush(journal);
 +
 +              /*
 +               * We don't want to clear needs_recovery flag when we failed
 +               * to flush the journal.
 +               */
 +              if (journal_flush(journal) < 0)
 +                      return;
  
                /* Journal blocked and flushed, clear needs_recovery flag. */
                EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);
@@@ -2794,30 -2783,30 +2794,30 @@@ static int ext3_quota_on_mount(struct s
   * Standard function to be called on quota_on
   */
  static int ext3_quota_on(struct super_block *sb, int type, int format_id,
-                        char *path, int remount)
+                        char *name, int remount)
  {
        int err;
-       struct nameidata nd;
+       struct path path;
  
        if (!test_opt(sb, QUOTA))
                return -EINVAL;
-       /* When remounting, no checks are needed and in fact, path is NULL */
+       /* When remounting, no checks are needed and in fact, name is NULL */
        if (remount)
-               return vfs_quota_on(sb, type, format_id, path, remount);
+               return vfs_quota_on(sb, type, format_id, name, remount);
  
-       err = path_lookup(path, LOOKUP_FOLLOW, &nd);
+       err = kern_path(name, LOOKUP_FOLLOW, &path);
        if (err)
                return err;
  
        /* Quotafile not on the same filesystem? */
-       if (nd.path.mnt->mnt_sb != sb) {
-               path_put(&nd.path);
+       if (path.mnt->mnt_sb != sb) {
+               path_put(&path);
                return -EXDEV;
        }
        /* Journaling quota? */
        if (EXT3_SB(sb)->s_qf_names[type]) {
                /* Quotafile not of fs root? */
-               if (nd.path.dentry->d_parent->d_inode != sb->s_root->d_inode)
+               if (path.dentry->d_parent != sb->s_root)
                        printk(KERN_WARNING
                                "EXT3-fs: Quota file not on filesystem root. "
                                "Journaled quota will not work.\n");
         * When we journal data on quota file, we have to flush journal to see
         * all updates to the file when we bypass pagecache...
         */
-       if (ext3_should_journal_data(nd.path.dentry->d_inode)) {
+       if (ext3_should_journal_data(path.dentry->d_inode)) {
                /*
                 * We don't need to lock updates but journal_flush() could
                 * otherwise be livelocked...
                 */
                journal_lock_updates(EXT3_SB(sb)->s_journal);
 -              journal_flush(EXT3_SB(sb)->s_journal);
 +              err = journal_flush(EXT3_SB(sb)->s_journal);
                journal_unlock_updates(EXT3_SB(sb)->s_journal);
 +              if (err) {
 +                      path_put(&nd.path);
 +                      return err;
 +              }
        }
  
-       err = vfs_quota_on_path(sb, type, format_id, &nd.path);
-       path_put(&nd.path);
+       err = vfs_quota_on_path(sb, type, format_id, &path);
+       path_put(&path);
        return err;
  }
  
diff --combined fs/nfsd/export.c
index 5cd882b8871aea82445291e15db6769d7c3ee27c,676201dbdf84308a22c479e2523d2e8401388676..5839b229cd0ea9bbd631441b89a07e639be0a98f
@@@ -99,7 -99,7 +99,7 @@@ static int expkey_parse(struct cache_de
        int fsidtype;
        char *ep;
        struct svc_expkey key;
 -      struct svc_expkey *ek;
 +      struct svc_expkey *ek = NULL;
  
        if (mesg[mlen-1] != '\n')
                return -EINVAL;
  
        buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
        err = -ENOMEM;
 -      if (!buf) goto out;
 +      if (!buf)
 +              goto out;
  
        err = -EINVAL;
        if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
  
        /* now we want a pathname, or empty meaning NEGATIVE  */
        err = -EINVAL;
 -      if ((len=qword_get(&mesg, buf, PAGE_SIZE)) < 0)
 +      len = qword_get(&mesg, buf, PAGE_SIZE);
 +      if (len < 0)
                goto out;
        dprintk("Path seems to be <%s>\n", buf);
        err = 0;
        if (len == 0) {
                set_bit(CACHE_NEGATIVE, &key.h.flags);
                ek = svc_expkey_update(&key, ek);
 -              if (ek)
 -                      cache_put(&ek->h, &svc_expkey_cache);
 -              else err = -ENOMEM;
 +              if (!ek)
 +                      err = -ENOMEM;
        } else {
-               struct nameidata nd;
-               err = path_lookup(buf, 0, &nd);
+               err = kern_path(buf, 0, &key.ek_path);
                if (err)
                        goto out;
  
                dprintk("Found the path %s\n", buf);
-               key.ek_path = nd.path;
  
                ek = svc_expkey_update(&key, ek);
 -              if (ek)
 -                      cache_put(&ek->h, &svc_expkey_cache);
 -              else
 +              if (!ek)
                        err = -ENOMEM;
-               path_put(&nd.path);
+               path_put(&key.ek_path);
        }
        cache_flush();
   out:
 +      if (ek)
 +              cache_put(&ek->h, &svc_expkey_cache);
        if (dom)
                auth_domain_put(dom);
        kfree(buf);
@@@ -501,35 -498,22 +499,22 @@@ static int svc_export_parse(struct cach
        int len;
        int err;
        struct auth_domain *dom = NULL;
-       struct nameidata nd;
-       struct svc_export exp, *expp;
+       struct svc_export exp = {}, *expp;
        int an_int;
  
-       nd.path.dentry = NULL;
-       exp.ex_pathname = NULL;
-       /* fs locations */
-       exp.ex_fslocs.locations = NULL;
-       exp.ex_fslocs.locations_count = 0;
-       exp.ex_fslocs.migrated = 0;
-       exp.ex_uuid = NULL;
-       /* secinfo */
-       exp.ex_nflavors = 0;
        if (mesg[mlen-1] != '\n')
                return -EINVAL;
        mesg[mlen-1] = 0;
  
        buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
-       err = -ENOMEM;
-       if (!buf) goto out;
+       if (!buf)
+               return -ENOMEM;
  
        /* client */
-       len = qword_get(&mesg, buf, PAGE_SIZE);
        err = -EINVAL;
-       if (len <= 0) goto out;
+       len = qword_get(&mesg, buf, PAGE_SIZE);
+       if (len <= 0)
+               goto out;
  
        err = -ENOENT;
        dom = auth_domain_find(buf);
  
        /* path */
        err = -EINVAL;
-       if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
-               goto out;
-       err = path_lookup(buf, 0, &nd);
-       if (err) goto out_no_path;
+       if ((len = qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
+               goto out1;
+       err = kern_path(buf, 0, &exp.ex_path);
+       if (err)
+               goto out1;
  
-       exp.h.flags = 0;
        exp.ex_client = dom;
-       exp.ex_path.mnt = nd.path.mnt;
-       exp.ex_path.dentry = nd.path.dentry;
-       exp.ex_pathname = kstrdup(buf, GFP_KERNEL);
        err = -ENOMEM;
+       exp.ex_pathname = kstrdup(buf, GFP_KERNEL);
        if (!exp.ex_pathname)
-               goto out;
+               goto out2;
  
        /* expiry */
        err = -EINVAL;
        exp.h.expiry_time = get_expiry(&mesg);
        if (exp.h.expiry_time == 0)
-               goto out;
+               goto out3;
  
        /* flags */
        err = get_int(&mesg, &an_int);
                err = 0;
                set_bit(CACHE_NEGATIVE, &exp.h.flags);
        } else {
-               if (err || an_int < 0) goto out;        
+               if (err || an_int < 0)
+                       goto out3;
                exp.ex_flags= an_int;
        
                /* anon uid */
                err = get_int(&mesg, &an_int);
-               if (err) goto out;
+               if (err)
+                       goto out3;
                exp.ex_anon_uid= an_int;
  
                /* anon gid */
                err = get_int(&mesg, &an_int);
-               if (err) goto out;
+               if (err)
+                       goto out3;
                exp.ex_anon_gid= an_int;
  
                /* fsid */
                err = get_int(&mesg, &an_int);
-               if (err) goto out;
+               if (err)
+                       goto out3;
                exp.ex_fsid = an_int;
  
                while ((len = qword_get(&mesg, buf, PAGE_SIZE)) > 0) {
                                 */
                                break;
                        if (err)
-                               goto out;
+                               goto out4;
                }
  
-               err = check_export(nd.path.dentry->d_inode, exp.ex_flags,
+               err = check_export(exp.ex_path.dentry->d_inode, exp.ex_flags,
                                   exp.ex_uuid);
-               if (err) goto out;
+               if (err)
+                       goto out4;
        }
  
        expp = svc_export_lookup(&exp);
                err = -ENOMEM;
        else
                exp_put(expp);
 out:
out4:
        nfsd4_fslocs_free(&exp.ex_fslocs);
        kfree(exp.ex_uuid);
+ out3:
        kfree(exp.ex_pathname);
-       if (nd.path.dentry)
-               path_put(&nd.path);
 out_no_path:
-       if (dom)
-               auth_domain_put(dom);
+ out2:
+       path_put(&exp.ex_path);
out1:
+       auth_domain_put(dom);
+ out:
        kfree(buf);
        return err;
  }
@@@ -999,7 -989,7 +990,7 @@@ exp_export(struct nfsctl_export *nxp
        struct svc_export       *exp = NULL;
        struct svc_export       new;
        struct svc_expkey       *fsid_key = NULL;
-       struct nameidata nd;
+       struct path path;
        int             err;
  
        /* Consistency check */
  
  
        /* Look up the dentry */
-       err = path_lookup(nxp->ex_path, 0, &nd);
+       err = kern_path(nxp->ex_path, 0, &path);
        if (err)
                goto out_put_clp;
        err = -EINVAL;
  
-       exp = exp_get_by_name(clp, nd.path.mnt, nd.path.dentry, NULL);
+       exp = exp_get_by_name(clp, path.mnt, path.dentry, NULL);
  
        memset(&new, 0, sizeof(new));
  
        if ((nxp->ex_flags & NFSEXP_FSID) &&
            (!IS_ERR(fsid_key = exp_get_fsid_key(clp, nxp->ex_dev))) &&
            fsid_key->ek_path.mnt &&
-           (fsid_key->ek_path.mnt != nd.path.mnt ||
-            fsid_key->ek_path.dentry != nd.path.dentry))
+           (fsid_key->ek_path.mnt != path.mnt ||
+            fsid_key->ek_path.dentry != path.dentry))
                goto finish;
  
        if (!IS_ERR(exp)) {
                goto finish;
        }
  
-       err = check_export(nd.path.dentry->d_inode, nxp->ex_flags, NULL);
+       err = check_export(path.dentry->d_inode, nxp->ex_flags, NULL);
        if (err) goto finish;
  
        err = -ENOMEM;
        if (!new.ex_pathname)
                goto finish;
        new.ex_client = clp;
-       new.ex_path = nd.path;
+       new.ex_path = path;
        new.ex_flags = nxp->ex_flags;
        new.ex_anon_uid = nxp->ex_anon_uid;
        new.ex_anon_gid = nxp->ex_anon_gid;
@@@ -1091,7 -1081,7 +1082,7 @@@ finish
                exp_put(exp);
        if (fsid_key && !IS_ERR(fsid_key))
                cache_put(&fsid_key->h, &svc_expkey_cache);
-       path_put(&nd.path);
+       path_put(&path);
  out_put_clp:
        auth_domain_put(clp);
  out_unlock:
@@@ -1122,7 -1112,7 +1113,7 @@@ exp_unexport(struct nfsctl_export *nxp
  {
        struct auth_domain *dom;
        svc_export *exp;
-       struct nameidata nd;
+       struct path path;
        int             err;
  
        /* Consistency check */
                goto out_unlock;
        }
  
-       err = path_lookup(nxp->ex_path, 0, &nd);
+       err = kern_path(nxp->ex_path, 0, &path);
        if (err)
                goto out_domain;
  
        err = -EINVAL;
-       exp = exp_get_by_name(dom, nd.path.mnt, nd.path.dentry, NULL);
-       path_put(&nd.path);
+       exp = exp_get_by_name(dom, path.mnt, path.dentry, NULL);
+       path_put(&path);
        if (IS_ERR(exp))
                goto out_domain;
  
@@@ -1167,26 -1157,26 +1158,26 @@@ out_unlock
   * since its harder to fool a kernel module than a user space program.
   */
  int
- exp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize)
+ exp_rootfh(svc_client *clp, char *name, struct knfsd_fh *f, int maxsize)
  {
        struct svc_export       *exp;
-       struct nameidata        nd;
+       struct path             path;
        struct inode            *inode;
        struct svc_fh           fh;
        int                     err;
  
        err = -EPERM;
        /* NB: we probably ought to check that it's NUL-terminated */
-       if (path_lookup(path, 0, &nd)) {
-               printk("nfsd: exp_rootfh path not found %s", path);
+       if (kern_path(name, 0, &path)) {
+               printk("nfsd: exp_rootfh path not found %s", name);
                return err;
        }
-       inode = nd.path.dentry->d_inode;
+       inode = path.dentry->d_inode;
  
        dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n",
-                path, nd.path.dentry, clp->name,
+                name, path.dentry, clp->name,
                 inode->i_sb->s_id, inode->i_ino);
-       exp = exp_parent(clp, nd.path.mnt, nd.path.dentry, NULL);
+       exp = exp_parent(clp, path.mnt, path.dentry, NULL);
        if (IS_ERR(exp)) {
                err = PTR_ERR(exp);
                goto out;
         * fh must be initialized before calling fh_compose
         */
        fh_init(&fh, maxsize);
-       if (fh_compose(&fh, exp, nd.path.dentry, NULL))
+       if (fh_compose(&fh, exp, path.dentry, NULL))
                err = -EINVAL;
        else
                err = 0;
        fh_put(&fh);
        exp_put(exp);
  out:
-       path_put(&nd.path);
+       path_put(&path);
        return err;
  }
  
diff --combined fs/nfsd/vfs.c
index 9609eb51d727147ac745f4d89f3e2110dae222ae,49d4b8725ca374e778b1cca112ffa4bc5ac791f1..0bc56f6d9276b96878edd55837354d6c5ea87d02
@@@ -410,7 -410,6 +410,7 @@@ out_nfserr
  static ssize_t nfsd_getxattr(struct dentry *dentry, char *key, void **buf)
  {
        ssize_t buflen;
 +      ssize_t ret;
  
        buflen = vfs_getxattr(dentry, key, NULL, 0);
        if (buflen <= 0)
        if (!*buf)
                return -ENOMEM;
  
 -      return vfs_getxattr(dentry, key, *buf, buflen);
 +      ret = vfs_getxattr(dentry, key, *buf, buflen);
 +      if (ret < 0)
 +              kfree(*buf);
 +      return ret;
  }
  #endif
  
        return err;
  }
  
+ /*
+  * We do this buffering because we must not call back into the file
+  * system's ->lookup() method from the filldir callback. That may well
+  * deadlock a number of file systems.
+  *
+  * This is based heavily on the implementation of same in XFS.
+  */
+ struct buffered_dirent {
+       u64             ino;
+       loff_t          offset;
+       int             namlen;
+       unsigned int    d_type;
+       char            name[];
+ };
+ struct readdir_data {
+       char            *dirent;
+       size_t          used;
+       int             full;
+ };
+ static int nfsd_buffered_filldir(void *__buf, const char *name, int namlen,
+                                loff_t offset, u64 ino, unsigned int d_type)
+ {
+       struct readdir_data *buf = __buf;
+       struct buffered_dirent *de = (void *)(buf->dirent + buf->used);
+       unsigned int reclen;
+       reclen = ALIGN(sizeof(struct buffered_dirent) + namlen, sizeof(u64));
+       if (buf->used + reclen > PAGE_SIZE) {
+               buf->full = 1;
+               return -EINVAL;
+       }
+       de->namlen = namlen;
+       de->offset = offset;
+       de->ino = ino;
+       de->d_type = d_type;
+       memcpy(de->name, name, namlen);
+       buf->used += reclen;
+       return 0;
+ }
+ static int nfsd_buffered_readdir(struct file *file, filldir_t func,
+                                struct readdir_cd *cdp, loff_t *offsetp)
+ {
+       struct readdir_data buf;
+       struct buffered_dirent *de;
+       int host_err;
+       int size;
+       loff_t offset;
+       buf.dirent = (void *)__get_free_page(GFP_KERNEL);
+       if (!buf.dirent)
+               return -ENOMEM;
+       offset = *offsetp;
+       cdp->err = nfserr_eof; /* will be cleared on successful read */
+       while (1) {
+               unsigned int reclen;
+               buf.used = 0;
+               buf.full = 0;
+               host_err = vfs_readdir(file, nfsd_buffered_filldir, &buf);
+               if (buf.full)
+                       host_err = 0;
+               if (host_err < 0)
+                       break;
+               size = buf.used;
+               if (!size)
+                       break;
+               de = (struct buffered_dirent *)buf.dirent;
+               while (size > 0) {
+                       offset = de->offset;
+                       if (func(cdp, de->name, de->namlen, de->offset,
+                                de->ino, de->d_type))
+                               goto done;
+                       if (cdp->err != nfs_ok)
+                               goto done;
+                       reclen = ALIGN(sizeof(*de) + de->namlen,
+                                      sizeof(u64));
+                       size -= reclen;
+                       de = (struct buffered_dirent *)((char *)de + reclen);
+               }
+               offset = vfs_llseek(file, 0, SEEK_CUR);
+               if (!buf.full)
+                       break;
+       }
+  done:
+       free_page((unsigned long)(buf.dirent));
+       if (host_err)
+               return nfserrno(host_err);
+       *offsetp = offset;
+       return cdp->err;
+ }
  /*
   * Read entries from a directory.
   * The  NFSv3/4 verifier we ignore for now.
@@@ -1826,7 -1931,6 +1935,6 @@@ nfsd_readdir(struct svc_rqst *rqstp, st
             struct readdir_cd *cdp, filldir_t func)
  {
        __be32          err;
-       int             host_err;
        struct file     *file;
        loff_t          offset = *offsetp;
  
                goto out_close;
        }
  
-       /*
-        * Read the directory entries. This silly loop is necessary because
-        * readdir() is not guaranteed to fill up the entire buffer, but
-        * may choose to do less.
-        */
-       do {
-               cdp->err = nfserr_eof; /* will be cleared on successful read */
-               host_err = vfs_readdir(file, func, cdp);
-       } while (host_err >=0 && cdp->err == nfs_ok);
-       if (host_err)
-               err = nfserrno(host_err);
-       else
-               err = cdp->err;
-       *offsetp = vfs_llseek(file, 0, 1);
+       err = nfsd_buffered_readdir(file, func, cdp, offsetp);
  
        if (err == nfserr_eof || err == nfserr_toosmall)
                err = nfs_ok; /* can still be found in ->err */
diff --combined init/main.c
index b038fa142041eadc67369792aeeb97492c2819dd,c6a1024a27a33a45c4fdb7f3d87da80fe391c44b..130d1a0eef113ef62f873d386f689f8533591d28
@@@ -52,7 -52,6 +52,7 @@@
  #include <linux/key.h>
  #include <linux/unwind.h>
  #include <linux/buffer_head.h>
 +#include <linux/page_cgroup.h>
  #include <linux/debug_locks.h>
  #include <linux/debugobjects.h>
  #include <linux/lockdep.h>
@@@ -648,7 -647,6 +648,7 @@@ asmlinkage void __init start_kernel(voi
        vmalloc_init();
        vfs_caches_init_early();
        cpuset_init_early();
 +      page_cgroup_init();
        mem_init();
        enable_debug_pagealloc();
        cpu_hotplug_init();
        fork_init(num_physpages);
        proc_caches_init();
        buffer_init();
-       unnamed_dev_init();
        key_init();
        security_init();
        vfs_caches_init(num_physpages);
  }
  
  static int initcall_debug;
 -
 -static int __init initcall_debug_setup(char *str)
 -{
 -      initcall_debug = 1;
 -      return 1;
 -}
 -__setup("initcall_debug", initcall_debug_setup);
 +core_param(initcall_debug, initcall_debug, bool, 0644);
  
  int do_one_initcall(initcall_t fn)
  {
@@@ -769,6 -772,8 +768,6 @@@ static void __init do_initcalls(void
  static void __init do_basic_setup(void)
  {
        rcu_init_sched(); /* needed by module_init stage. */
 -      /* drivers will send hotplug events */
 -      init_workqueues();
        usermodehelper_init();
        driver_init();
        init_irq_proc();
@@@ -852,8 -857,6 +851,8 @@@ static int __init kernel_init(void * un
  
        cad_pid = task_pid(current);
  
 +      init_workqueues();
 +
        smp_prepare_cpus(setup_max_cpus);
  
        do_pre_smp_initcalls();