Merge branches 'irq-core-for-linus' and 'core-locking-for-linus' of git://git.kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 1 Nov 2010 00:40:24 +0000 (20:40 -0400)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 1 Nov 2010 00:40:24 +0000 (20:40 -0400)
* 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  genirq: Fix up irq_node() for irq_data changes.
  genirq: Add single IRQ reservation helper
  genirq: Warn if enable_irq is called before irq is set up

* 'core-locking-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  semaphore: Remove mutex emulation
  staging: Final semaphore cleanup
  jbd2: Convert jbd2_slab_create_sem to mutex
  hpfs: Convert sbi->hpfs_creation_de to mutex

Fix up trivial change/delete conflicts with deleted 'dream' drivers
(drivers/staging/dream/camera/{mt9d112.c,mt9p012_fox.c,mt9t013.c,s5k3e2fx.c})

1  2  3 
drivers/staging/smbfs/inode.c
fs/hpfs/super.c

index f9c493591ce75f151ead6fbbeed379cb5a8a1290,0000000000000000000000000000000000000000,fa42f40fa2266cc41cd4e20b371d1d7fddc8c44e..540a984bb5160d5942902575803c6c79b087d507
mode 100644,000000,100644..100644
--- /dev/null
@@@@ -1,843 -1,0 -1,843 +1,843 @@@@
-       init_MUTEX(&server->sem);
 + /*
 +  *  inode.c
 +  *
 +  *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
 +  *  Copyright (C) 1997 by Volker Lendecke
 +  *
 +  *  Please add a note about your changes to smbfs in the ChangeLog file.
 +  */
 + 
 + #include <linux/module.h>
 + #include <linux/time.h>
 + #include <linux/kernel.h>
 + #include <linux/mm.h>
 + #include <linux/string.h>
 + #include <linux/stat.h>
 + #include <linux/errno.h>
 + #include <linux/slab.h>
 + #include <linux/init.h>
 + #include <linux/file.h>
 + #include <linux/dcache.h>
 + #include <linux/smp_lock.h>
 + #include <linux/nls.h>
 + #include <linux/seq_file.h>
 + #include <linux/mount.h>
 + #include <linux/net.h>
 + #include <linux/vfs.h>
 + #include <linux/highuid.h>
 + #include <linux/sched.h>
 + 
 + #include <asm/system.h>
 + #include <asm/uaccess.h>
 + 
 + #include "smb_fs.h"
 + #include "smbno.h"
 + #include "smb_mount.h"
 + #include "smb_debug.h"
 + #include "getopt.h"
 + #include "proto.h"
 + 
 + /* Always pick a default string */
 + #ifdef CONFIG_SMB_NLS_REMOTE
 + #define SMB_NLS_REMOTE CONFIG_SMB_NLS_REMOTE
 + #else
 + #define SMB_NLS_REMOTE ""
 + #endif
 + 
 + #define SMB_TTL_DEFAULT 1000
 + 
 + static void smb_evict_inode(struct inode *);
 + static void smb_put_super(struct super_block *);
 + static int  smb_statfs(struct dentry *, struct kstatfs *);
 + static int  smb_show_options(struct seq_file *, struct vfsmount *);
 + 
 + static struct kmem_cache *smb_inode_cachep;
 + 
 + static struct inode *smb_alloc_inode(struct super_block *sb)
 + {
 +      struct smb_inode_info *ei;
 +      ei = (struct smb_inode_info *)kmem_cache_alloc(smb_inode_cachep, GFP_KERNEL);
 +      if (!ei)
 +              return NULL;
 +      return &ei->vfs_inode;
 + }
 + 
 + static void smb_destroy_inode(struct inode *inode)
 + {
 +      kmem_cache_free(smb_inode_cachep, SMB_I(inode));
 + }
 + 
 + static void init_once(void *foo)
 + {
 +      struct smb_inode_info *ei = (struct smb_inode_info *) foo;
 + 
 +      inode_init_once(&ei->vfs_inode);
 + }
 + 
 + static int init_inodecache(void)
 + {
 +      smb_inode_cachep = kmem_cache_create("smb_inode_cache",
 +                                           sizeof(struct smb_inode_info),
 +                                           0, (SLAB_RECLAIM_ACCOUNT|
 +                                              SLAB_MEM_SPREAD),
 +                                           init_once);
 +      if (smb_inode_cachep == NULL)
 +              return -ENOMEM;
 +      return 0;
 + }
 + 
 + static void destroy_inodecache(void)
 + {
 +      kmem_cache_destroy(smb_inode_cachep);
 + }
 + 
 + static int smb_remount(struct super_block *sb, int *flags, char *data)
 + {
 +      *flags |= MS_NODIRATIME;
 +      return 0;
 + }
 + 
 + static const struct super_operations smb_sops =
 + {
 +      .alloc_inode    = smb_alloc_inode,
 +      .destroy_inode  = smb_destroy_inode,
 +      .drop_inode     = generic_delete_inode,
 +      .evict_inode    = smb_evict_inode,
 +      .put_super      = smb_put_super,
 +      .statfs         = smb_statfs,
 +      .show_options   = smb_show_options,
 +      .remount_fs     = smb_remount,
 + };
 + 
 + 
 + /* We are always generating a new inode here */
 + struct inode *
 + smb_iget(struct super_block *sb, struct smb_fattr *fattr)
 + {
 +      struct smb_sb_info *server = SMB_SB(sb);
 +      struct inode *result;
 + 
 +      DEBUG1("smb_iget: %p\n", fattr);
 + 
 +      result = new_inode(sb);
 +      if (!result)
 +              return result;
 +      result->i_ino = fattr->f_ino;
 +      SMB_I(result)->open = 0;
 +      SMB_I(result)->fileid = 0;
 +      SMB_I(result)->access = 0;
 +      SMB_I(result)->flags = 0;
 +      SMB_I(result)->closed = 0;
 +      SMB_I(result)->openers = 0;
 +      smb_set_inode_attr(result, fattr);
 +      if (S_ISREG(result->i_mode)) {
 +              result->i_op = &smb_file_inode_operations;
 +              result->i_fop = &smb_file_operations;
 +              result->i_data.a_ops = &smb_file_aops;
 +      } else if (S_ISDIR(result->i_mode)) {
 +              if (server->opt.capabilities & SMB_CAP_UNIX)
 +                      result->i_op = &smb_dir_inode_operations_unix;
 +              else
 +                      result->i_op = &smb_dir_inode_operations;
 +              result->i_fop = &smb_dir_operations;
 +      } else if (S_ISLNK(result->i_mode)) {
 +              result->i_op = &smb_link_inode_operations;
 +      } else {
 +              init_special_inode(result, result->i_mode, fattr->f_rdev);
 +      }
 +      insert_inode_hash(result);
 +      return result;
 + }
 + 
 + /*
 +  * Copy the inode data to a smb_fattr structure.
 +  */
 + void
 + smb_get_inode_attr(struct inode *inode, struct smb_fattr *fattr)
 + {
 +      memset(fattr, 0, sizeof(struct smb_fattr));
 +      fattr->f_mode   = inode->i_mode;
 +      fattr->f_nlink  = inode->i_nlink;
 +      fattr->f_ino    = inode->i_ino;
 +      fattr->f_uid    = inode->i_uid;
 +      fattr->f_gid    = inode->i_gid;
 +      fattr->f_size   = inode->i_size;
 +      fattr->f_mtime  = inode->i_mtime;
 +      fattr->f_ctime  = inode->i_ctime;
 +      fattr->f_atime  = inode->i_atime;
 +      fattr->f_blocks = inode->i_blocks;
 + 
 +      fattr->attr     = SMB_I(inode)->attr;
 +      /*
 +       * Keep the attributes in sync with the inode permissions.
 +       */
 +      if (fattr->f_mode & S_IWUSR)
 +              fattr->attr &= ~aRONLY;
 +      else
 +              fattr->attr |= aRONLY;
 + }
 + 
 + /*
 +  * Update the inode, possibly causing it to invalidate its pages if mtime/size
 +  * is different from last time.
 +  */
 + void
 + smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr)
 + {
 +      struct smb_inode_info *ei = SMB_I(inode);
 + 
 +      /*
 +       * A size change should have a different mtime, or same mtime
 +       * but different size.
 +       */
 +      time_t last_time = inode->i_mtime.tv_sec;
 +      loff_t last_sz = inode->i_size;
 + 
 +      inode->i_mode   = fattr->f_mode;
 +      inode->i_nlink  = fattr->f_nlink;
 +      inode->i_uid    = fattr->f_uid;
 +      inode->i_gid    = fattr->f_gid;
 +      inode->i_ctime  = fattr->f_ctime;
 +      inode->i_blocks = fattr->f_blocks;
 +      inode->i_size   = fattr->f_size;
 +      inode->i_mtime  = fattr->f_mtime;
 +      inode->i_atime  = fattr->f_atime;
 +      ei->attr = fattr->attr;
 + 
 +      /*
 +       * Update the "last time refreshed" field for revalidation.
 +       */
 +      ei->oldmtime = jiffies;
 + 
 +      if (inode->i_mtime.tv_sec != last_time || inode->i_size != last_sz) {
 +              VERBOSE("%ld changed, old=%ld, new=%ld, oz=%ld, nz=%ld\n",
 +                      inode->i_ino,
 +                      (long) last_time, (long) inode->i_mtime.tv_sec,
 +                      (long) last_sz, (long) inode->i_size);
 + 
 +              if (!S_ISDIR(inode->i_mode))
 +                      invalidate_remote_inode(inode);
 +      }
 + }
 + 
 + /*
 +  * This is called if the connection has gone bad ...
 +  * try to kill off all the current inodes.
 +  */
 + void
 + smb_invalidate_inodes(struct smb_sb_info *server)
 + {
 +      VERBOSE("\n");
 +      shrink_dcache_sb(SB_of(server));
 + }
 + 
 + /*
 +  * This is called to update the inode attributes after
 +  * we've made changes to a file or directory.
 +  */
 + static int
 + smb_refresh_inode(struct dentry *dentry)
 + {
 +      struct inode *inode = dentry->d_inode;
 +      int error;
 +      struct smb_fattr fattr;
 + 
 +      error = smb_proc_getattr(dentry, &fattr);
 +      if (!error) {
 +              smb_renew_times(dentry);
 +              /*
 +               * Check whether the type part of the mode changed,
 +               * and don't update the attributes if it did.
 +               *
 +               * And don't dick with the root inode
 +               */
 +              if (inode->i_ino == 2)
 +                      return error;
 +              if (S_ISLNK(inode->i_mode))
 +                      return error;   /* VFS will deal with it */
 + 
 +              if ((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT)) {
 +                      smb_set_inode_attr(inode, &fattr);
 +              } else {
 +                      /*
 +                       * Big trouble! The inode has become a new object,
 +                       * so any operations attempted on it are invalid.
 +                       *
 +                       * To limit damage, mark the inode as bad so that
 +                       * subsequent lookup validations will fail.
 +                       */
 +                      PARANOIA("%s/%s changed mode, %07o to %07o\n",
 +                               DENTRY_PATH(dentry),
 +                               inode->i_mode, fattr.f_mode);
 + 
 +                      fattr.f_mode = inode->i_mode; /* save mode */
 +                      make_bad_inode(inode);
 +                      inode->i_mode = fattr.f_mode; /* restore mode */
 +                      /*
 +                       * No need to worry about unhashing the dentry: the
 +                       * lookup validation will see that the inode is bad.
 +                       * But we do want to invalidate the caches ...
 +                       */
 +                      if (!S_ISDIR(inode->i_mode))
 +                              invalidate_remote_inode(inode);
 +                      else
 +                              smb_invalid_dir_cache(inode);
 +                      error = -EIO;
 +              }
 +      }
 +      return error;
 + }
 + 
 + /*
 +  * This is called when we want to check whether the inode
 +  * has changed on the server.  If it has changed, we must
 +  * invalidate our local caches.
 +  */
 + int
 + smb_revalidate_inode(struct dentry *dentry)
 + {
 +      struct smb_sb_info *s = server_from_dentry(dentry);
 +      struct inode *inode = dentry->d_inode;
 +      int error = 0;
 + 
 +      DEBUG1("smb_revalidate_inode\n");
 +      lock_kernel();
 + 
 +      /*
 +       * Check whether we've recently refreshed the inode.
 +       */
 +      if (time_before(jiffies, SMB_I(inode)->oldmtime + SMB_MAX_AGE(s))) {
 +              VERBOSE("up-to-date, ino=%ld, jiffies=%lu, oldtime=%lu\n",
 +                      inode->i_ino, jiffies, SMB_I(inode)->oldmtime);
 +              goto out;
 +      }
 + 
 +      error = smb_refresh_inode(dentry);
 + out:
 +      unlock_kernel();
 +      return error;
 + }
 + 
 + /*
 +  * This routine is called when i_nlink == 0 and i_count goes to 0.
 +  * All blocking cleanup operations need to go here to avoid races.
 +  */
 + static void
 + smb_evict_inode(struct inode *ino)
 + {
 +      DEBUG1("ino=%ld\n", ino->i_ino);
 +      truncate_inode_pages(&ino->i_data, 0);
 +      end_writeback(ino);
 +      lock_kernel();
 +      if (smb_close(ino))
 +              PARANOIA("could not close inode %ld\n", ino->i_ino);
 +      unlock_kernel();
 + }
 + 
 + static struct option opts[] = {
 +      { "version",    0, 'v' },
 +      { "win95",      SMB_MOUNT_WIN95, 1 },
 +      { "oldattr",    SMB_MOUNT_OLDATTR, 1 },
 +      { "dirattr",    SMB_MOUNT_DIRATTR, 1 },
 +      { "case",       SMB_MOUNT_CASE, 1 },
 +      { "uid",        0, 'u' },
 +      { "gid",        0, 'g' },
 +      { "file_mode",  0, 'f' },
 +      { "dir_mode",   0, 'd' },
 +      { "iocharset",  0, 'i' },
 +      { "codepage",   0, 'c' },
 +      { "ttl",        0, 't' },
 +      { NULL,         0, 0}
 + };
 + 
 + static int
 + parse_options(struct smb_mount_data_kernel *mnt, char *options)
 + {
 +      int c;
 +      unsigned long flags;
 +      unsigned long value;
 +      char *optarg;
 +      char *optopt;
 + 
 +      flags = 0;
 +      while ( (c = smb_getopt("smbfs", &options, opts,
 +                              &optopt, &optarg, &flags, &value)) > 0) {
 + 
 +              VERBOSE("'%s' -> '%s'\n", optopt, optarg ? optarg : "<none>");
 +              switch (c) {
 +              case 1:
 +                      /* got a "flag" option */
 +                      break;
 +              case 'v':
 +                      if (value != SMB_MOUNT_VERSION) {
 +                      printk ("smbfs: Bad mount version %ld, expected %d\n",
 +                              value, SMB_MOUNT_VERSION);
 +                              return 0;
 +                      }
 +                      mnt->version = value;
 +                      break;
 +              case 'u':
 +                      mnt->uid = value;
 +                      flags |= SMB_MOUNT_UID;
 +                      break;
 +              case 'g':
 +                      mnt->gid = value;
 +                      flags |= SMB_MOUNT_GID;
 +                      break;
 +              case 'f':
 +                      mnt->file_mode = (value & S_IRWXUGO) | S_IFREG;
 +                      flags |= SMB_MOUNT_FMODE;
 +                      break;
 +              case 'd':
 +                      mnt->dir_mode = (value & S_IRWXUGO) | S_IFDIR;
 +                      flags |= SMB_MOUNT_DMODE;
 +                      break;
 +              case 'i':
 +                      strlcpy(mnt->codepage.local_name, optarg, 
 +                              SMB_NLS_MAXNAMELEN);
 +                      break;
 +              case 'c':
 +                      strlcpy(mnt->codepage.remote_name, optarg,
 +                              SMB_NLS_MAXNAMELEN);
 +                      break;
 +              case 't':
 +                      mnt->ttl = value;
 +                      break;
 +              default:
 +                      printk ("smbfs: Unrecognized mount option %s\n",
 +                              optopt);
 +                      return -1;
 +              }
 +      }
 +      mnt->flags = flags;
 +      return c;
 + }
 + 
 + /*
 +  * smb_show_options() is for displaying mount options in /proc/mounts.
 +  * It tries to avoid showing settings that were not changed from their
 +  * defaults.
 +  */
 + static int
 + smb_show_options(struct seq_file *s, struct vfsmount *m)
 + {
 +      struct smb_mount_data_kernel *mnt = SMB_SB(m->mnt_sb)->mnt;
 +      int i;
 + 
 +      for (i = 0; opts[i].name != NULL; i++)
 +              if (mnt->flags & opts[i].flag)
 +                      seq_printf(s, ",%s", opts[i].name);
 + 
 +      if (mnt->flags & SMB_MOUNT_UID)
 +              seq_printf(s, ",uid=%d", mnt->uid);
 +      if (mnt->flags & SMB_MOUNT_GID)
 +              seq_printf(s, ",gid=%d", mnt->gid);
 +      if (mnt->mounted_uid != 0)
 +              seq_printf(s, ",mounted_uid=%d", mnt->mounted_uid);
 + 
 +      /* 
 +       * Defaults for file_mode and dir_mode are unknown to us; they
 +       * depend on the current umask of the user doing the mount.
 +       */
 +      if (mnt->flags & SMB_MOUNT_FMODE)
 +              seq_printf(s, ",file_mode=%04o", mnt->file_mode & S_IRWXUGO);
 +      if (mnt->flags & SMB_MOUNT_DMODE)
 +              seq_printf(s, ",dir_mode=%04o", mnt->dir_mode & S_IRWXUGO);
 + 
 +      if (strcmp(mnt->codepage.local_name, CONFIG_NLS_DEFAULT))
 +              seq_printf(s, ",iocharset=%s", mnt->codepage.local_name);
 +      if (strcmp(mnt->codepage.remote_name, SMB_NLS_REMOTE))
 +              seq_printf(s, ",codepage=%s", mnt->codepage.remote_name);
 + 
 +      if (mnt->ttl != SMB_TTL_DEFAULT)
 +              seq_printf(s, ",ttl=%d", mnt->ttl);
 + 
 +      return 0;
 + }
 + 
 + static void
 + smb_unload_nls(struct smb_sb_info *server)
 + {
 +      unload_nls(server->remote_nls);
 +      unload_nls(server->local_nls);
 + }
 + 
 + static void
 + smb_put_super(struct super_block *sb)
 + {
 +      struct smb_sb_info *server = SMB_SB(sb);
 + 
 +      lock_kernel();
 + 
 +      smb_lock_server(server);
 +      server->state = CONN_INVALID;
 +      smbiod_unregister_server(server);
 + 
 +      smb_close_socket(server);
 + 
 +      if (server->conn_pid)
 +              kill_pid(server->conn_pid, SIGTERM, 1);
 + 
 +      bdi_destroy(&server->bdi);
 +      kfree(server->ops);
 +      smb_unload_nls(server);
 +      sb->s_fs_info = NULL;
 +      smb_unlock_server(server);
 +      put_pid(server->conn_pid);
 +      kfree(server);
 + 
 +      unlock_kernel();
 + }
 + 
 + static int smb_fill_super(struct super_block *sb, void *raw_data, int silent)
 + {
 +      struct smb_sb_info *server;
 +      struct smb_mount_data_kernel *mnt;
 +      struct smb_mount_data *oldmnt;
 +      struct inode *root_inode;
 +      struct smb_fattr root;
 +      int ver;
 +      void *mem;
 +      static int warn_count;
 + 
 +      lock_kernel();
 + 
 +      if (warn_count < 5) {
 +              warn_count++;
 +              printk(KERN_EMERG "smbfs is deprecated and will be removed"
 +                      " from the 2.6.37 kernel. Please migrate to cifs\n");
 +      }
 + 
 +      if (!raw_data)
 +              goto out_no_data;
 + 
 +      oldmnt = (struct smb_mount_data *) raw_data;
 +      ver = oldmnt->version;
 +      if (ver != SMB_MOUNT_OLDVERSION && cpu_to_be32(ver) != SMB_MOUNT_ASCII)
 +              goto out_wrong_data;
 + 
 +      sb->s_flags |= MS_NODIRATIME;
 +      sb->s_blocksize = 1024; /* Eh...  Is this correct? */
 +      sb->s_blocksize_bits = 10;
 +      sb->s_magic = SMB_SUPER_MAGIC;
 +      sb->s_op = &smb_sops;
 +      sb->s_time_gran = 100;
 + 
 +      server = kzalloc(sizeof(struct smb_sb_info), GFP_KERNEL);
 +      if (!server)
 +              goto out_no_server;
 +      sb->s_fs_info = server;
 +      
 +      if (bdi_setup_and_register(&server->bdi, "smbfs", BDI_CAP_MAP_COPY))
 +              goto out_bdi;
 + 
 +      sb->s_bdi = &server->bdi;
 + 
 +      server->super_block = sb;
 +      server->mnt = NULL;
 +      server->sock_file = NULL;
 +      init_waitqueue_head(&server->conn_wq);
  -static int smb_get_sb(struct file_system_type *fs_type,
  -     int flags, const char *dev_name, void *data, struct vfsmount *mnt)
++      sema_init(&server->sem, 1);
 +      INIT_LIST_HEAD(&server->entry);
 +      INIT_LIST_HEAD(&server->xmitq);
 +      INIT_LIST_HEAD(&server->recvq);
 +      server->conn_error = 0;
 +      server->conn_pid = NULL;
 +      server->state = CONN_INVALID; /* no connection yet */
 +      server->generation = 0;
 + 
 +      /* Allocate the global temp buffer and some superblock helper structs */
 +      /* FIXME: move these to the smb_sb_info struct */
 +      VERBOSE("alloc chunk = %lu\n", sizeof(struct smb_ops) +
 +              sizeof(struct smb_mount_data_kernel));
 +      mem = kmalloc(sizeof(struct smb_ops) +
 +                    sizeof(struct smb_mount_data_kernel), GFP_KERNEL);
 +      if (!mem)
 +              goto out_no_mem;
 + 
 +      server->ops = mem;
 +      smb_install_null_ops(server->ops);
 +      server->mnt = mem + sizeof(struct smb_ops);
 + 
 +      /* Setup NLS stuff */
 +      server->remote_nls = NULL;
 +      server->local_nls = NULL;
 + 
 +      mnt = server->mnt;
 + 
 +      memset(mnt, 0, sizeof(struct smb_mount_data_kernel));
 +      strlcpy(mnt->codepage.local_name, CONFIG_NLS_DEFAULT,
 +              SMB_NLS_MAXNAMELEN);
 +      strlcpy(mnt->codepage.remote_name, SMB_NLS_REMOTE,
 +              SMB_NLS_MAXNAMELEN);
 + 
 +      mnt->ttl = SMB_TTL_DEFAULT;
 +      if (ver == SMB_MOUNT_OLDVERSION) {
 +              mnt->version = oldmnt->version;
 + 
 +              SET_UID(mnt->uid, oldmnt->uid);
 +              SET_GID(mnt->gid, oldmnt->gid);
 + 
 +              mnt->file_mode = (oldmnt->file_mode & S_IRWXUGO) | S_IFREG;
 +              mnt->dir_mode = (oldmnt->dir_mode & S_IRWXUGO) | S_IFDIR;
 + 
 +              mnt->flags = (oldmnt->file_mode >> 9) | SMB_MOUNT_UID |
 +                      SMB_MOUNT_GID | SMB_MOUNT_FMODE | SMB_MOUNT_DMODE;
 +      } else {
 +              mnt->file_mode = S_IRWXU | S_IRGRP | S_IXGRP |
 +                              S_IROTH | S_IXOTH | S_IFREG;
 +              mnt->dir_mode = S_IRWXU | S_IRGRP | S_IXGRP |
 +                              S_IROTH | S_IXOTH | S_IFDIR;
 +              if (parse_options(mnt, raw_data))
 +                      goto out_bad_option;
 +      }
 +      mnt->mounted_uid = current_uid();
 +      smb_setcodepage(server, &mnt->codepage);
 + 
 +      /*
 +       * Display the enabled options
 +       * Note: smb_proc_getattr uses these in 2.4 (but was changed in 2.2)
 +       */
 +      if (mnt->flags & SMB_MOUNT_OLDATTR)
 +              printk("SMBFS: Using core getattr (Win 95 speedup)\n");
 +      else if (mnt->flags & SMB_MOUNT_DIRATTR)
 +              printk("SMBFS: Using dir ff getattr\n");
 + 
 +      if (smbiod_register_server(server) < 0) {
 +              printk(KERN_ERR "smbfs: failed to start smbiod\n");
 +              goto out_no_smbiod;
 +      }
 + 
 +      /*
 +       * Keep the super block locked while we get the root inode.
 +       */
 +      smb_init_root_dirent(server, &root, sb);
 +      root_inode = smb_iget(sb, &root);
 +      if (!root_inode)
 +              goto out_no_root;
 + 
 +      sb->s_root = d_alloc_root(root_inode);
 +      if (!sb->s_root)
 +              goto out_no_root;
 + 
 +      smb_new_dentry(sb->s_root);
 + 
 +      unlock_kernel();
 +      return 0;
 + 
 + out_no_root:
 +      iput(root_inode);
 + out_no_smbiod:
 +      smb_unload_nls(server);
 + out_bad_option:
 +      kfree(mem);
 + out_no_mem:
 +      bdi_destroy(&server->bdi);
 + out_bdi:
 +      if (!server->mnt)
 +              printk(KERN_ERR "smb_fill_super: allocation failure\n");
 +      sb->s_fs_info = NULL;
 +      kfree(server);
 +      goto out_fail;
 + out_wrong_data:
 +      printk(KERN_ERR "smbfs: mount_data version %d is not supported\n", ver);
 +      goto out_fail;
 + out_no_data:
 +      printk(KERN_ERR "smb_fill_super: missing data argument\n");
 + out_fail:
 +      unlock_kernel();
 +      return -EINVAL;
 + out_no_server:
 +      printk(KERN_ERR "smb_fill_super: cannot allocate struct smb_sb_info\n");
 +      unlock_kernel();
 +      return -ENOMEM;
 + }
 + 
 + static int
 + smb_statfs(struct dentry *dentry, struct kstatfs *buf)
 + {
 +      int result;
 +      
 +      lock_kernel();
 + 
 +      result = smb_proc_dskattr(dentry, buf);
 + 
 +      unlock_kernel();
 + 
 +      buf->f_type = SMB_SUPER_MAGIC;
 +      buf->f_namelen = SMB_MAXPATHLEN;
 +      return result;
 + }
 + 
 + int smb_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
 + {
 +      int err = smb_revalidate_inode(dentry);
 +      if (!err)
 +              generic_fillattr(dentry->d_inode, stat);
 +      return err;
 + }
 + 
 + int
 + smb_notify_change(struct dentry *dentry, struct iattr *attr)
 + {
 +      struct inode *inode = dentry->d_inode;
 +      struct smb_sb_info *server = server_from_dentry(dentry);
 +      unsigned int mask = (S_IFREG | S_IFDIR | S_IRWXUGO);
 +      int error, changed, refresh = 0;
 +      struct smb_fattr fattr;
 + 
 +      lock_kernel();
 + 
 +      error = smb_revalidate_inode(dentry);
 +      if (error)
 +              goto out;
 + 
 +      if ((error = inode_change_ok(inode, attr)) < 0)
 +              goto out;
 + 
 +      error = -EPERM;
 +      if ((attr->ia_valid & ATTR_UID) && (attr->ia_uid != server->mnt->uid))
 +              goto out;
 + 
 +      if ((attr->ia_valid & ATTR_GID) && (attr->ia_uid != server->mnt->gid))
 +              goto out;
 + 
 +      if ((attr->ia_valid & ATTR_MODE) && (attr->ia_mode & ~mask))
 +              goto out;
 + 
 +      if ((attr->ia_valid & ATTR_SIZE) != 0) {
 +              VERBOSE("changing %s/%s, old size=%ld, new size=%ld\n",
 +                      DENTRY_PATH(dentry),
 +                      (long) inode->i_size, (long) attr->ia_size);
 + 
 +              filemap_write_and_wait(inode->i_mapping);
 + 
 +              error = smb_open(dentry, O_WRONLY);
 +              if (error)
 +                      goto out;
 +              error = server->ops->truncate(inode, attr->ia_size);
 +              if (error)
 +                      goto out;
 +              truncate_setsize(inode, attr->ia_size);
 +              refresh = 1;
 +      }
 + 
 +      if (server->opt.capabilities & SMB_CAP_UNIX) {
 +              /* For now we don't want to set the size with setattr_unix */
 +              attr->ia_valid &= ~ATTR_SIZE;
 +              /* FIXME: only call if we actually want to set something? */
 +              error = smb_proc_setattr_unix(dentry, attr, 0, 0);
 +              if (!error)
 +                      refresh = 1;
 + 
 +              goto out;
 +      }
 + 
 +      /*
 +       * Initialize the fattr and check for changed fields.
 +       * Note: CTIME under SMB is creation time rather than
 +       * change time, so we don't attempt to change it.
 +       */
 +      smb_get_inode_attr(inode, &fattr);
 + 
 +      changed = 0;
 +      if ((attr->ia_valid & ATTR_MTIME) != 0) {
 +              fattr.f_mtime = attr->ia_mtime;
 +              changed = 1;
 +      }
 +      if ((attr->ia_valid & ATTR_ATIME) != 0) {
 +              fattr.f_atime = attr->ia_atime;
 +              /* Earlier protocols don't have an access time */
 +              if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2)
 +                      changed = 1;
 +      }
 +      if (changed) {
 +              error = smb_proc_settime(dentry, &fattr);
 +              if (error)
 +                      goto out;
 +              refresh = 1;
 +      }
 + 
 +      /*
 +       * Check for mode changes ... we're extremely limited in
 +       * what can be set for SMB servers: just the read-only bit.
 +       */
 +      if ((attr->ia_valid & ATTR_MODE) != 0) {
 +              VERBOSE("%s/%s mode change, old=%x, new=%x\n",
 +                      DENTRY_PATH(dentry), fattr.f_mode, attr->ia_mode);
 +              changed = 0;
 +              if (attr->ia_mode & S_IWUSR) {
 +                      if (fattr.attr & aRONLY) {
 +                              fattr.attr &= ~aRONLY;
 +                              changed = 1;
 +                      }
 +              } else {
 +                      if (!(fattr.attr & aRONLY)) {
 +                              fattr.attr |= aRONLY;
 +                              changed = 1;
 +                      }
 +              }
 +              if (changed) {
 +                      error = smb_proc_setattr(dentry, &fattr);
 +                      if (error)
 +                              goto out;
 +                      refresh = 1;
 +              }
 +      }
 +      error = 0;
 + 
 + out:
 +      if (refresh)
 +              smb_refresh_inode(dentry);
 +      unlock_kernel();
 +      return error;
 + }
 + 
  -     return get_sb_nodev(fs_type, flags, data, smb_fill_super, mnt);
 ++static struct dentry *smb_mount(struct file_system_type *fs_type,
 ++     int flags, const char *dev_name, void *data)
 + {
  -     .get_sb         = smb_get_sb,
 ++     return mount_nodev(fs_type, flags, data, smb_fill_super);
 + }
 + 
 + static struct file_system_type smb_fs_type = {
 +      .owner          = THIS_MODULE,
 +      .name           = "smbfs",
 ++     .mount          = smb_mount,
 +      .kill_sb        = kill_anon_super,
 +      .fs_flags       = FS_BINARY_MOUNTDATA,
 + };
 + 
 + static int __init init_smb_fs(void)
 + {
 +      int err;
 +      DEBUG1("registering ...\n");
 + 
 +      err = init_inodecache();
 +      if (err)
 +              goto out_inode;
 +      err = smb_init_request_cache();
 +      if (err)
 +              goto out_request;
 +      err = register_filesystem(&smb_fs_type);
 +      if (err)
 +              goto out;
 +      return 0;
 + out:
 +      smb_destroy_request_cache();
 + out_request:
 +      destroy_inodecache();
 + out_inode:
 +      return err;
 + }
 + 
 + static void __exit exit_smb_fs(void)
 + {
 +      DEBUG1("unregistering ...\n");
 +      unregister_filesystem(&smb_fs_type);
 +      smb_destroy_request_cache();
 +      destroy_inodecache();
 + }
 + 
 + module_init(init_smb_fs)
 + module_exit(exit_smb_fs)
 + MODULE_LICENSE("GPL");
diff --cc fs/hpfs/super.c
Simple merge