]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.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>
Tue, 10 Aug 2010 18:26:52 +0000 (11:26 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 10 Aug 2010 18:26:52 +0000 (11:26 -0700)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: (96 commits)
  no need for list_for_each_entry_safe()/resetting with superblock list
  Fix sget() race with failing mount
  vfs: don't hold s_umount over close_bdev_exclusive() call
  sysv: do not mark superblock dirty on remount
  sysv: do not mark superblock dirty on mount
  btrfs: remove junk sb_dirt change
  BFS: clean up the superblock usage
  AFFS: wait for sb synchronization when needed
  AFFS: clean up dirty flag usage
  cifs: truncate fallout
  mbcache: fix shrinker function return value
  mbcache: Remove unused features
  add f_flags to struct statfs(64)
  pass a struct path to vfs_statfs
  update VFS documentation for method changes.
  All filesystems that need invalidate_inode_buffers() are doing that explicitly
  convert remaining ->clear_inode() to ->evict_inode()
  Make ->drop_inode() just return whether inode needs to be dropped
  fs/inode.c:clear_inode() is gone
  fs/inode.c:evict() doesn't care about delete vs. non-delete paths now
  ...

Fix up trivial conflicts in fs/nilfs2/super.c

44 files changed:
1  2 
drivers/staging/pohmelfs/inode.c
fs/9p/v9fs_vfs.h
fs/9p/vfs_inode.c
fs/9p/vfs_super.c
fs/block_dev.c
fs/cifs/cifsfs.c
fs/cifs/inode.c
fs/compat.c
fs/ext3/inode.c
fs/ext3/super.c
fs/ext4/ext4.h
fs/ext4/ialloc.c
fs/ext4/inode.c
fs/ext4/super.c
fs/ext4/xattr.c
fs/freevxfs/vxfs_super.c
fs/fs-writeback.c
fs/fuse/dir.c
fs/gfs2/aops.c
fs/gfs2/super.c
fs/ncpfs/inode.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/super.c
fs/nfsd/nfs4xdr.c
fs/nfsd/vfs.c
fs/nilfs2/dir.c
fs/nilfs2/nilfs.h
fs/nilfs2/recovery.c
fs/nilfs2/super.c
fs/ocfs2/dlmfs/dlmfs.c
fs/ocfs2/super.c
fs/proc/base.c
fs/quota/dquot.c
fs/reiserfs/inode.c
fs/ubifs/super.c
fs/udf/file.c
fs/udf/super.c
include/linux/buffer_head.h
include/linux/ext3_fs.h
include/linux/fs.h
include/linux/mm.h
include/linux/reiserfs_fs.h
mm/shmem.c

index bc1c6051a6f66847d8d6dc9d9c84810517d6520f,100e3a3c1b10470ea31e4738e9785edeb3783ba2..97dae297ca3c1483006c05b52f25b92386971330
@@@ -815,7 -815,7 +815,7 @@@ static int pohmelfs_readpages(struct fi
  }
  
  /*
 - * Small addres space operations for POHMELFS.
 + * Small address space operations for POHMELFS.
   */
  const struct address_space_operations pohmelfs_aops = {
        .readpage               = pohmelfs_readpage,
@@@ -847,7 -847,7 +847,7 @@@ static void pohmelfs_destroy_inode(stru
  }
  
  /*
 - * ->alloc_inode() callback. Allocates inode and initilizes private data.
 + * ->alloc_inode() callback. Allocates inode and initializes private data.
   */
  static struct inode *pohmelfs_alloc_inode(struct super_block *sb)
  {
@@@ -968,12 -968,18 +968,18 @@@ int pohmelfs_setattr_raw(struct inode *
                goto err_out_exit;
        }
  
-       err = inode_setattr(inode, attr);
-       if (err) {
-               dprintk("%s: ino: %llu, failed to set the attributes.\n", __func__, POHMELFS_I(inode)->ino);
-               goto err_out_exit;
+       if ((attr->ia_valid & ATTR_SIZE) &&
+           attr->ia_size != i_size_read(inode)) {
+               err = vmtruncate(inode, attr->ia_size);
+               if (err) {
+                       dprintk("%s: ino: %llu, failed to set the attributes.\n", __func__, POHMELFS_I(inode)->ino);
+                       goto err_out_exit;
+               }
        }
  
+       setattr_copy(inode, attr);
+       mark_inode_dirty(inode);
        dprintk("%s: ino: %llu, mode: %o -> %o, uid: %u -> %u, gid: %u -> %u, size: %llu -> %llu.\n",
                        __func__, POHMELFS_I(inode)->ino, inode->i_mode, attr->ia_mode,
                        inode->i_uid, attr->ia_uid, inode->i_gid, attr->ia_gid, inode->i_size, attr->ia_size);
@@@ -1217,7 -1223,7 +1223,7 @@@ void pohmelfs_fill_inode(struct inode *
        }
  }
  
- static void pohmelfs_drop_inode(struct inode *inode)
+ static int pohmelfs_drop_inode(struct inode *inode)
  {
        struct pohmelfs_sb *psb = POHMELFS_SB(inode->i_sb);
        struct pohmelfs_inode *pi = POHMELFS_I(inode);
        list_del_init(&pi->inode_entry);
        spin_unlock(&psb->ino_lock);
  
-       generic_drop_inode(inode);
+       return generic_drop_inode(inode);
  }
  
  static struct pohmelfs_inode *pohmelfs_get_inode_from_list(struct pohmelfs_sb *psb,
@@@ -1266,7 -1272,7 +1272,7 @@@ static void pohmelfs_put_super(struct s
  {
        struct pohmelfs_sb *psb = POHMELFS_SB(sb);
        struct pohmelfs_inode *pi;
 -      unsigned int count;
 +      unsigned int count = 0;
        unsigned int in_drop_list = 0;
        struct inode *inode, *tmp;
  
diff --combined fs/9p/v9fs_vfs.h
index f47c6bbb01b308115eedf8cb228e5dc694fe6560,3d056fe01b508ceb39864fcf14bebfb1b421dac1..88418c419ea7e70269572372d60eff91c6a4171c
@@@ -52,10 -52,9 +52,10 @@@ void v9fs_destroy_inode(struct inode *i
  #endif
  
  struct inode *v9fs_get_inode(struct super_block *sb, int mode);
- void v9fs_clear_inode(struct inode *inode);
+ void v9fs_evict_inode(struct inode *inode);
  ino_t v9fs_qid2ino(struct p9_qid *qid);
  void v9fs_stat2inode(struct p9_wstat *, struct inode *, struct super_block *);
 +void v9fs_stat2inode_dotl(struct p9_stat_dotl *, struct inode *);
  int v9fs_dir_release(struct inode *inode, struct file *filp);
  int v9fs_file_open(struct inode *inode, struct file *file);
  void v9fs_inode2stat(struct inode *inode, struct p9_wstat *stat);
diff --combined fs/9p/vfs_inode.c
index 6e94f3247cec5fb7e354583c31ded72254a3b623,b81ce206508d7c3c04b1cdd054e5d2472b61a71b..d97c34a24f7a32b26f8b983d71fac6ac7598f522
@@@ -35,7 -35,6 +35,7 @@@
  #include <linux/idr.h>
  #include <linux/sched.h>
  #include <linux/slab.h>
 +#include <linux/xattr.h>
  #include <net/9p/9p.h>
  #include <net/9p/client.h>
  
@@@ -43,7 -42,6 +43,7 @@@
  #include "v9fs_vfs.h"
  #include "fid.h"
  #include "cache.h"
 +#include "xattr.h"
  
  static const struct inode_operations v9fs_dir_inode_operations;
  static const struct inode_operations v9fs_dir_inode_operations_dotu;
@@@ -237,41 -235,6 +237,41 @@@ void v9fs_destroy_inode(struct inode *i
  }
  #endif
  
 +/**
 + * v9fs_get_fsgid_for_create - Helper function to get the gid for creating a
 + * new file system object. This checks the S_ISGID to determine the owning
 + * group of the new file system object.
 + */
 +
 +static gid_t v9fs_get_fsgid_for_create(struct inode *dir_inode)
 +{
 +      BUG_ON(dir_inode == NULL);
 +
 +      if (dir_inode->i_mode & S_ISGID) {
 +              /* set_gid bit is set.*/
 +              return dir_inode->i_gid;
 +      }
 +      return current_fsgid();
 +}
 +
 +/**
 + * v9fs_dentry_from_dir_inode - helper function to get the dentry from
 + * dir inode.
 + *
 + */
 +
 +static struct dentry *v9fs_dentry_from_dir_inode(struct inode *inode)
 +{
 +      struct dentry *dentry;
 +
 +      spin_lock(&dcache_lock);
 +      /* Directory should have only one entry. */
 +      BUG_ON(S_ISDIR(inode->i_mode) && !list_is_singular(&inode->i_dentry));
 +      dentry = list_entry(inode->i_dentry.next, struct dentry, d_alias);
 +      spin_unlock(&dcache_lock);
 +      return dentry;
 +}
 +
  /**
   * v9fs_get_inode - helper function to setup an inode
   * @sb: superblock
@@@ -304,13 -267,7 +304,13 @@@ struct inode *v9fs_get_inode(struct sup
        case S_IFBLK:
        case S_IFCHR:
        case S_IFSOCK:
 -              if (!v9fs_proto_dotu(v9ses)) {
 +              if (v9fs_proto_dotl(v9ses)) {
 +                      inode->i_op = &v9fs_file_inode_operations_dotl;
 +                      inode->i_fop = &v9fs_file_operations_dotl;
 +              } else if (v9fs_proto_dotu(v9ses)) {
 +                      inode->i_op = &v9fs_file_inode_operations;
 +                      inode->i_fop = &v9fs_file_operations;
 +              } else {
                        P9_DPRINTK(P9_DEBUG_ERROR,
                                   "special files without extended mode\n");
                        err = -EINVAL;
@@@ -430,8 -387,10 +430,10 @@@ error
   * @inode: inode to release
   *
   */
- void v9fs_clear_inode(struct inode *inode)
+ void v9fs_evict_inode(struct inode *inode)
  {
+       truncate_inode_pages(inode->i_mapping, 0);
+       end_writeback(inode);
        filemap_fdatawrite(inode->i_mapping);
  
  #ifdef CONFIG_9P_FSCACHE
  #endif
  }
  
 -/**
 - * v9fs_inode_from_fid - populate an inode by issuing a attribute request
 - * @v9ses: session information
 - * @fid: fid to issue attribute request for
 - * @sb: superblock on which to create inode
 - *
 - */
 -
  static struct inode *
 -v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
 +v9fs_inode(struct v9fs_session_info *v9ses, struct p9_fid *fid,
        struct super_block *sb)
  {
        int err, umode;
 -      struct inode *ret;
 +      struct inode *ret = NULL;
        struct p9_wstat *st;
  
 -      ret = NULL;
        st = p9_client_stat(fid);
        if (IS_ERR(st))
                return ERR_CAST(st);
  #endif
        p9stat_free(st);
        kfree(st);
 -
        return ret;
 -
  error:
        p9stat_free(st);
        kfree(st);
        return ERR_PTR(err);
  }
  
 +static struct inode *
 +v9fs_inode_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid,
 +      struct super_block *sb)
 +{
 +      struct inode *ret = NULL;
 +      int err;
 +      struct p9_stat_dotl *st;
 +
 +      st = p9_client_getattr_dotl(fid, P9_STATS_BASIC);
 +      if (IS_ERR(st))
 +              return ERR_CAST(st);
 +
 +      ret = v9fs_get_inode(sb, st->st_mode);
 +      if (IS_ERR(ret)) {
 +              err = PTR_ERR(ret);
 +              goto error;
 +      }
 +
 +      v9fs_stat2inode_dotl(st, ret);
 +      ret->i_ino = v9fs_qid2ino(&st->qid);
 +#ifdef CONFIG_9P_FSCACHE
 +      v9fs_vcookie_set_qid(ret, &st->qid);
 +      v9fs_cache_inode_get_cookie(ret);
 +#endif
 +      kfree(st);
 +      return ret;
 +error:
 +      kfree(st);
 +      return ERR_PTR(err);
 +}
 +
 +/**
 + * v9fs_inode_from_fid - Helper routine to populate an inode by
 + * issuing a attribute request
 + * @v9ses: session information
 + * @fid: fid to issue attribute request for
 + * @sb: superblock on which to create inode
 + *
 + */
 +static inline struct inode *
 +v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
 +                      struct super_block *sb)
 +{
 +      if (v9fs_proto_dotl(v9ses))
 +              return v9fs_inode_dotl(v9ses, fid, sb);
 +      else
 +              return v9fs_inode(v9ses, fid, sb);
 +}
 +
  /**
   * v9fs_remove - helper function to remove files and directories
   * @dir: directory inode that is being deleted
@@@ -643,118 -564,6 +645,118 @@@ error
        return ERR_PTR(err);
  }
  
 +/**
 + * v9fs_vfs_create_dotl - VFS hook to create files for 9P2000.L protocol.
 + * @dir: directory inode that is being created
 + * @dentry:  dentry that is being deleted
 + * @mode: create permissions
 + * @nd: path information
 + *
 + */
 +
 +static int
 +v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int mode,
 +              struct nameidata *nd)
 +{
 +      int err = 0;
 +      char *name = NULL;
 +      gid_t gid;
 +      int flags;
 +      struct v9fs_session_info *v9ses;
 +      struct p9_fid *fid = NULL;
 +      struct p9_fid *dfid, *ofid;
 +      struct file *filp;
 +      struct p9_qid qid;
 +      struct inode *inode;
 +
 +      v9ses = v9fs_inode2v9ses(dir);
 +      if (nd && nd->flags & LOOKUP_OPEN)
 +              flags = nd->intent.open.flags - 1;
 +      else
 +              flags = O_RDWR;
 +
 +      name = (char *) dentry->d_name.name;
 +      P9_DPRINTK(P9_DEBUG_VFS, "v9fs_vfs_create_dotl: name:%s flags:0x%x "
 +                      "mode:0x%x\n", name, flags, mode);
 +
 +      dfid = v9fs_fid_lookup(dentry->d_parent);
 +      if (IS_ERR(dfid)) {
 +              err = PTR_ERR(dfid);
 +              P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
 +              return err;
 +      }
 +
 +      /* clone a fid to use for creation */
 +      ofid = p9_client_walk(dfid, 0, NULL, 1);
 +      if (IS_ERR(ofid)) {
 +              err = PTR_ERR(ofid);
 +              P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
 +              return err;
 +      }
 +
 +      gid = v9fs_get_fsgid_for_create(dir);
 +      err = p9_client_create_dotl(ofid, name, flags, mode, gid, &qid);
 +      if (err < 0) {
 +              P9_DPRINTK(P9_DEBUG_VFS,
 +                              "p9_client_open_dotl failed in creat %d\n",
 +                              err);
 +              goto error;
 +      }
 +
 +      /* No need to populate the inode if we are not opening the file AND
 +       * not in cached mode.
 +       */
 +      if (!v9ses->cache && !(nd && nd->flags & LOOKUP_OPEN)) {
 +              /* Not in cached mode. No need to populate inode with stat */
 +              dentry->d_op = &v9fs_dentry_operations;
 +              p9_client_clunk(ofid);
 +              d_instantiate(dentry, NULL);
 +              return 0;
 +      }
 +
 +      /* Now walk from the parent so we can get an unopened fid. */
 +      fid = p9_client_walk(dfid, 1, &name, 1);
 +      if (IS_ERR(fid)) {
 +              err = PTR_ERR(fid);
 +              P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
 +              fid = NULL;
 +              goto error;
 +      }
 +
 +      /* instantiate inode and assign the unopened fid to dentry */
 +      inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
 +      if (IS_ERR(inode)) {
 +              err = PTR_ERR(inode);
 +              P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err);
 +              goto error;
 +      }
 +      dentry->d_op = &v9fs_cached_dentry_operations;
 +      d_instantiate(dentry, inode);
 +      err = v9fs_fid_add(dentry, fid);
 +      if (err < 0)
 +              goto error;
 +
 +      /* if we are opening a file, assign the open fid to the file */
 +      if (nd && nd->flags & LOOKUP_OPEN) {
 +              filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created);
 +              if (IS_ERR(filp)) {
 +                      p9_client_clunk(ofid);
 +                      return PTR_ERR(filp);
 +              }
 +              filp->private_data = ofid;
 +      } else
 +              p9_client_clunk(ofid);
 +
 +      return 0;
 +
 +error:
 +      if (ofid)
 +              p9_client_clunk(ofid);
 +      if (fid)
 +              p9_client_clunk(fid);
 +      return err;
 +}
 +
  /**
   * v9fs_vfs_create - VFS hook to create files
   * @dir: directory inode that is being created
@@@ -845,83 -654,6 +847,83 @@@ static int v9fs_vfs_mkdir(struct inode 
        return err;
  }
  
 +
 +/**
 + * v9fs_vfs_mkdir_dotl - VFS mkdir hook to create a directory
 + * @dir:  inode that is being unlinked
 + * @dentry: dentry that is being unlinked
 + * @mode: mode for new directory
 + *
 + */
 +
 +static int v9fs_vfs_mkdir_dotl(struct inode *dir, struct dentry *dentry,
 +                                      int mode)
 +{
 +      int err;
 +      struct v9fs_session_info *v9ses;
 +      struct p9_fid *fid = NULL, *dfid = NULL;
 +      gid_t gid;
 +      char *name;
 +      struct inode *inode;
 +      struct p9_qid qid;
 +      struct dentry *dir_dentry;
 +
 +      P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
 +      err = 0;
 +      v9ses = v9fs_inode2v9ses(dir);
 +
 +      mode |= S_IFDIR;
 +      dir_dentry = v9fs_dentry_from_dir_inode(dir);
 +      dfid = v9fs_fid_lookup(dir_dentry);
 +      if (IS_ERR(dfid)) {
 +              err = PTR_ERR(dfid);
 +              P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
 +              dfid = NULL;
 +              goto error;
 +      }
 +
 +      gid = v9fs_get_fsgid_for_create(dir);
 +      if (gid < 0) {
 +              P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_fsgid_for_create failed\n");
 +              goto error;
 +      }
 +
 +      name = (char *) dentry->d_name.name;
 +      err = p9_client_mkdir_dotl(dfid, name, mode, gid, &qid);
 +      if (err < 0)
 +              goto error;
 +
 +      /* instantiate inode and assign the unopened fid to the dentry */
 +      if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
 +              fid = p9_client_walk(dfid, 1, &name, 1);
 +              if (IS_ERR(fid)) {
 +                      err = PTR_ERR(fid);
 +                      P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
 +                              err);
 +                      fid = NULL;
 +                      goto error;
 +              }
 +
 +              inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
 +              if (IS_ERR(inode)) {
 +                      err = PTR_ERR(inode);
 +                      P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n",
 +                              err);
 +                      goto error;
 +              }
 +              dentry->d_op = &v9fs_cached_dentry_operations;
 +              d_instantiate(dentry, inode);
 +              err = v9fs_fid_add(dentry, fid);
 +              if (err < 0)
 +                      goto error;
 +              fid = NULL;
 +      }
 +error:
 +      if (fid)
 +              p9_client_clunk(fid);
 +      return err;
 +}
 +
  /**
   * v9fs_vfs_lookup - VFS lookup hook to "walk" to a new inode
   * @dir:  inode that is being walked from
@@@ -948,7 -680,6 +950,7 @@@ static struct dentry *v9fs_vfs_lookup(s
  
        sb = dir->i_sb;
        v9ses = v9fs_inode2v9ses(dir);
 +      /* We can walk d_parent because we hold the dir->i_mutex */
        dfid = v9fs_fid_lookup(dentry->d_parent);
        if (IS_ERR(dfid))
                return ERR_CAST(dfid);
@@@ -1056,33 -787,27 +1058,33 @@@ v9fs_vfs_rename(struct inode *old_dir, 
                goto clunk_olddir;
        }
  
 +      down_write(&v9ses->rename_sem);
        if (v9fs_proto_dotl(v9ses)) {
                retval = p9_client_rename(oldfid, newdirfid,
                                        (char *) new_dentry->d_name.name);
                if (retval != -ENOSYS)
                        goto clunk_newdir;
        }
 +      if (old_dentry->d_parent != new_dentry->d_parent) {
 +              /*
 +               * 9P .u can only handle file rename in the same directory
 +               */
  
 -      /* 9P can only handle file rename in the same directory */
 -      if (memcmp(&olddirfid->qid, &newdirfid->qid, sizeof(newdirfid->qid))) {
                P9_DPRINTK(P9_DEBUG_ERROR,
                                "old dir and new dir are different\n");
                retval = -EXDEV;
                goto clunk_newdir;
        }
 -
        v9fs_blank_wstat(&wstat);
        wstat.muid = v9ses->uname;
        wstat.name = (char *) new_dentry->d_name.name;
        retval = p9_client_wstat(oldfid, &wstat);
  
  clunk_newdir:
 +      if (!retval)
 +              /* successful rename */
 +              d_move(old_dentry, new_dentry);
 +      up_write(&v9ses->rename_sem);
        p9_client_clunk(newdirfid);
  
  clunk_olddir:
@@@ -1130,42 -855,6 +1132,42 @@@ v9fs_vfs_getattr(struct vfsmount *mnt, 
        return 0;
  }
  
 +static int
 +v9fs_vfs_getattr_dotl(struct vfsmount *mnt, struct dentry *dentry,
 +               struct kstat *stat)
 +{
 +      int err;
 +      struct v9fs_session_info *v9ses;
 +      struct p9_fid *fid;
 +      struct p9_stat_dotl *st;
 +
 +      P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry);
 +      err = -EPERM;
 +      v9ses = v9fs_inode2v9ses(dentry->d_inode);
 +      if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
 +              return simple_getattr(mnt, dentry, stat);
 +
 +      fid = v9fs_fid_lookup(dentry);
 +      if (IS_ERR(fid))
 +              return PTR_ERR(fid);
 +
 +      /* Ask for all the fields in stat structure. Server will return
 +       * whatever it supports
 +       */
 +
 +      st = p9_client_getattr_dotl(fid, P9_STATS_ALL);
 +      if (IS_ERR(st))
 +              return PTR_ERR(st);
 +
 +      v9fs_stat2inode_dotl(st, dentry->d_inode);
 +      generic_fillattr(dentry->d_inode, stat);
 +      /* Change block size to what the server returned */
 +      stat->blksize = st->st_blksize;
 +
 +      kfree(st);
 +      return 0;
 +}
 +
  /**
   * v9fs_vfs_setattr - set file metadata
   * @dentry: file whose metadata to set
@@@ -1209,55 -898,21 +1211,64 @@@ static int v9fs_vfs_setattr(struct dent
        }
  
        retval = p9_client_wstat(fid, &wstat);
-       if (retval >= 0)
-               retval = inode_setattr(dentry->d_inode, iattr);
+       if (retval < 0)
+               return retval;
  
-       return retval;
+       if ((iattr->ia_valid & ATTR_SIZE) &&
+           iattr->ia_size != i_size_read(dentry->d_inode)) {
+               retval = vmtruncate(dentry->d_inode, iattr->ia_size);
+               if (retval)
+                       return retval;
+       }
+       setattr_copy(dentry->d_inode, iattr);
+       mark_inode_dirty(dentry->d_inode);
+       return 0;
  }
  
 +/**
 + * v9fs_vfs_setattr_dotl - set file metadata
 + * @dentry: file whose metadata to set
 + * @iattr: metadata assignment structure
 + *
 + */
 +
 +static int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
 +{
 +      int retval;
 +      struct v9fs_session_info *v9ses;
 +      struct p9_fid *fid;
 +      struct p9_iattr_dotl p9attr;
 +
 +      P9_DPRINTK(P9_DEBUG_VFS, "\n");
 +
 +      retval = inode_change_ok(dentry->d_inode, iattr);
 +      if (retval)
 +              return retval;
 +
 +      p9attr.valid = iattr->ia_valid;
 +      p9attr.mode = iattr->ia_mode;
 +      p9attr.uid = iattr->ia_uid;
 +      p9attr.gid = iattr->ia_gid;
 +      p9attr.size = iattr->ia_size;
 +      p9attr.atime_sec = iattr->ia_atime.tv_sec;
 +      p9attr.atime_nsec = iattr->ia_atime.tv_nsec;
 +      p9attr.mtime_sec = iattr->ia_mtime.tv_sec;
 +      p9attr.mtime_nsec = iattr->ia_mtime.tv_nsec;
 +
 +      retval = -EPERM;
 +      v9ses = v9fs_inode2v9ses(dentry->d_inode);
 +      fid = v9fs_fid_lookup(dentry);
 +      if (IS_ERR(fid))
 +              return PTR_ERR(fid);
 +
 +      retval = p9_client_setattr(fid, &p9attr);
 +      if (retval >= 0)
 +              retval = inode_setattr(dentry->d_inode, iattr);
 +
 +      return retval;
 +}
 +
  /**
   * v9fs_stat2inode - populate an inode structure with mistat info
   * @stat: Plan 9 metadata (mistat) structure
@@@ -1335,77 -990,6 +1346,77 @@@ v9fs_stat2inode(struct p9_wstat *stat, 
        inode->i_blocks = (i_size_read(inode) + 512 - 1) >> 9;
  }
  
 +/**
 + * v9fs_stat2inode_dotl - populate an inode structure with stat info
 + * @stat: stat structure
 + * @inode: inode to populate
 + * @sb: superblock of filesystem
 + *
 + */
 +
 +void
 +v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode)
 +{
 +
 +      if ((stat->st_result_mask & P9_STATS_BASIC) == P9_STATS_BASIC) {
 +              inode->i_atime.tv_sec = stat->st_atime_sec;
 +              inode->i_atime.tv_nsec = stat->st_atime_nsec;
 +              inode->i_mtime.tv_sec = stat->st_mtime_sec;
 +              inode->i_mtime.tv_nsec = stat->st_mtime_nsec;
 +              inode->i_ctime.tv_sec = stat->st_ctime_sec;
 +              inode->i_ctime.tv_nsec = stat->st_ctime_nsec;
 +              inode->i_uid = stat->st_uid;
 +              inode->i_gid = stat->st_gid;
 +              inode->i_nlink = stat->st_nlink;
 +              inode->i_mode = stat->st_mode;
 +              inode->i_rdev = new_decode_dev(stat->st_rdev);
 +
 +              if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode)))
 +                      init_special_inode(inode, inode->i_mode, inode->i_rdev);
 +
 +              i_size_write(inode, stat->st_size);
 +              inode->i_blocks = stat->st_blocks;
 +      } else {
 +              if (stat->st_result_mask & P9_STATS_ATIME) {
 +                      inode->i_atime.tv_sec = stat->st_atime_sec;
 +                      inode->i_atime.tv_nsec = stat->st_atime_nsec;
 +              }
 +              if (stat->st_result_mask & P9_STATS_MTIME) {
 +                      inode->i_mtime.tv_sec = stat->st_mtime_sec;
 +                      inode->i_mtime.tv_nsec = stat->st_mtime_nsec;
 +              }
 +              if (stat->st_result_mask & P9_STATS_CTIME) {
 +                      inode->i_ctime.tv_sec = stat->st_ctime_sec;
 +                      inode->i_ctime.tv_nsec = stat->st_ctime_nsec;
 +              }
 +              if (stat->st_result_mask & P9_STATS_UID)
 +                      inode->i_uid = stat->st_uid;
 +              if (stat->st_result_mask & P9_STATS_GID)
 +                      inode->i_gid = stat->st_gid;
 +              if (stat->st_result_mask & P9_STATS_NLINK)
 +                      inode->i_nlink = stat->st_nlink;
 +              if (stat->st_result_mask & P9_STATS_MODE) {
 +                      inode->i_mode = stat->st_mode;
 +                      if ((S_ISBLK(inode->i_mode)) ||
 +                                              (S_ISCHR(inode->i_mode)))
 +                              init_special_inode(inode, inode->i_mode,
 +                                                              inode->i_rdev);
 +              }
 +              if (stat->st_result_mask & P9_STATS_RDEV)
 +                      inode->i_rdev = new_decode_dev(stat->st_rdev);
 +              if (stat->st_result_mask & P9_STATS_SIZE)
 +                      i_size_write(inode, stat->st_size);
 +              if (stat->st_result_mask & P9_STATS_BLOCKS)
 +                      inode->i_blocks = stat->st_blocks;
 +      }
 +      if (stat->st_result_mask & P9_STATS_GEN)
 +                      inode->i_generation = stat->st_gen;
 +
 +      /* Currently we don't support P9_STATS_BTIME and P9_STATS_DATA_VERSION
 +       * because the inode structure does not have fields for them.
 +       */
 +}
 +
  /**
   * v9fs_qid2ino - convert qid into inode number
   * @qid: qid to hash
@@@ -1449,7 -1033,7 +1460,7 @@@ static int v9fs_readlink(struct dentry 
        if (IS_ERR(fid))
                return PTR_ERR(fid);
  
 -      if (!v9fs_proto_dotu(v9ses))
 +      if (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses))
                return -EBADF;
  
        st = p9_client_stat(fid);
@@@ -1554,99 -1138,6 +1565,99 @@@ static int v9fs_vfs_mkspecial(struct in
        return 0;
  }
  
 +/**
 + * v9fs_vfs_symlink_dotl - helper function to create symlinks
 + * @dir: directory inode containing symlink
 + * @dentry: dentry for symlink
 + * @symname: symlink data
 + *
 + * See Also: 9P2000.L RFC for more information
 + *
 + */
 +
 +static int
 +v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,
 +              const char *symname)
 +{
 +      struct v9fs_session_info *v9ses;
 +      struct p9_fid *dfid;
 +      struct p9_fid *fid = NULL;
 +      struct inode *inode;
 +      struct p9_qid qid;
 +      char *name;
 +      int err;
 +      gid_t gid;
 +
 +      name = (char *) dentry->d_name.name;
 +      P9_DPRINTK(P9_DEBUG_VFS, "v9fs_vfs_symlink_dotl : %lu,%s,%s\n",
 +                      dir->i_ino, name, symname);
 +      v9ses = v9fs_inode2v9ses(dir);
 +
 +      dfid = v9fs_fid_lookup(dentry->d_parent);
 +      if (IS_ERR(dfid)) {
 +              err = PTR_ERR(dfid);
 +              P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
 +              return err;
 +      }
 +
 +      gid = v9fs_get_fsgid_for_create(dir);
 +
 +      if (gid < 0) {
 +              P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_egid failed %d\n", gid);
 +              goto error;
 +      }
 +
 +      /* Server doesn't alter fid on TSYMLINK. Hence no need to clone it. */
 +      err = p9_client_symlink(dfid, name, (char *)symname, gid, &qid);
 +
 +      if (err < 0) {
 +              P9_DPRINTK(P9_DEBUG_VFS, "p9_client_symlink failed %d\n", err);
 +              goto error;
 +      }
 +
 +      if (v9ses->cache) {
 +              /* Now walk from the parent so we can get an unopened fid. */
 +              fid = p9_client_walk(dfid, 1, &name, 1);
 +              if (IS_ERR(fid)) {
 +                      err = PTR_ERR(fid);
 +                      P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
 +                                      err);
 +                      fid = NULL;
 +                      goto error;
 +              }
 +
 +              /* instantiate inode and assign the unopened fid to dentry */
 +              inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
 +              if (IS_ERR(inode)) {
 +                      err = PTR_ERR(inode);
 +                      P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n",
 +                                      err);
 +                      goto error;
 +              }
 +              dentry->d_op = &v9fs_cached_dentry_operations;
 +              d_instantiate(dentry, inode);
 +              err = v9fs_fid_add(dentry, fid);
 +              if (err < 0)
 +                      goto error;
 +              fid = NULL;
 +      } else {
 +              /* Not in cached mode. No need to populate inode with stat */
 +              inode = v9fs_get_inode(dir->i_sb, S_IFLNK);
 +              if (IS_ERR(inode)) {
 +                      err = PTR_ERR(inode);
 +                      goto error;
 +              }
 +              dentry->d_op = &v9fs_dentry_operations;
 +              d_instantiate(dentry, inode);
 +      }
 +
 +error:
 +      if (fid)
 +              p9_client_clunk(fid);
 +
 +      return err;
 +}
 +
  /**
   * v9fs_vfs_symlink - helper function to create symlinks
   * @dir: directory inode containing symlink
@@@ -1705,76 -1196,6 +1716,76 @@@ clunk_fid
        return retval;
  }
  
 +/**
 + * v9fs_vfs_link_dotl - create a hardlink for dotl
 + * @old_dentry: dentry for file to link to
 + * @dir: inode destination for new link
 + * @dentry: dentry for link
 + *
 + */
 +
 +static int
 +v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir,
 +              struct dentry *dentry)
 +{
 +      int err;
 +      struct p9_fid *dfid, *oldfid;
 +      char *name;
 +      struct v9fs_session_info *v9ses;
 +      struct dentry *dir_dentry;
 +
 +      P9_DPRINTK(P9_DEBUG_VFS, "dir ino: %lu, old_name: %s, new_name: %s\n",
 +                      dir->i_ino, old_dentry->d_name.name,
 +                      dentry->d_name.name);
 +
 +      v9ses = v9fs_inode2v9ses(dir);
 +      dir_dentry = v9fs_dentry_from_dir_inode(dir);
 +      dfid = v9fs_fid_lookup(dir_dentry);
 +      if (IS_ERR(dfid))
 +              return PTR_ERR(dfid);
 +
 +      oldfid = v9fs_fid_lookup(old_dentry);
 +      if (IS_ERR(oldfid))
 +              return PTR_ERR(oldfid);
 +
 +      name = (char *) dentry->d_name.name;
 +
 +      err = p9_client_link(dfid, oldfid, (char *)dentry->d_name.name);
 +
 +      if (err < 0) {
 +              P9_DPRINTK(P9_DEBUG_VFS, "p9_client_link failed %d\n", err);
 +              return err;
 +      }
 +
 +      if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
 +              /* Get the latest stat info from server. */
 +              struct p9_fid *fid;
 +              struct p9_stat_dotl *st;
 +
 +              fid = v9fs_fid_lookup(old_dentry);
 +              if (IS_ERR(fid))
 +                      return PTR_ERR(fid);
 +
 +              st = p9_client_getattr_dotl(fid, P9_STATS_BASIC);
 +              if (IS_ERR(st))
 +                      return PTR_ERR(st);
 +
 +              v9fs_stat2inode_dotl(st, old_dentry->d_inode);
 +
 +              kfree(st);
 +      } else {
 +              /* Caching disabled. No need to get upto date stat info.
 +               * This dentry will be released immediately. So, just i_count++
 +               */
 +              atomic_inc(&old_dentry->d_inode->i_count);
 +      }
 +
 +      dentry->d_op = old_dentry->d_op;
 +      d_instantiate(dentry, old_dentry->d_inode);
 +
 +      return err;
 +}
 +
  /**
   * v9fs_vfs_mknod - create a special file
   * @dir: inode destination for new link
@@@ -1820,100 -1241,6 +1831,100 @@@ v9fs_vfs_mknod(struct inode *dir, struc
        return retval;
  }
  
 +/**
 + * v9fs_vfs_mknod_dotl - create a special file
 + * @dir: inode destination for new link
 + * @dentry: dentry for file
 + * @mode: mode for creation
 + * @rdev: device associated with special file
 + *
 + */
 +static int
 +v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int mode,
 +              dev_t rdev)
 +{
 +      int err;
 +      char *name;
 +      struct v9fs_session_info *v9ses;
 +      struct p9_fid *fid = NULL, *dfid = NULL;
 +      struct inode *inode;
 +      gid_t gid;
 +      struct p9_qid qid;
 +      struct dentry *dir_dentry;
 +
 +      P9_DPRINTK(P9_DEBUG_VFS,
 +              " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino,
 +              dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev));
 +
 +      if (!new_valid_dev(rdev))
 +              return -EINVAL;
 +
 +      v9ses = v9fs_inode2v9ses(dir);
 +      dir_dentry = v9fs_dentry_from_dir_inode(dir);
 +      dfid = v9fs_fid_lookup(dir_dentry);
 +      if (IS_ERR(dfid)) {
 +              err = PTR_ERR(dfid);
 +              P9_DPRINTK(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
 +              dfid = NULL;
 +              goto error;
 +      }
 +
 +      gid = v9fs_get_fsgid_for_create(dir);
 +      if (gid < 0) {
 +              P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_fsgid_for_create failed\n");
 +              goto error;
 +      }
 +
 +      name = (char *) dentry->d_name.name;
 +
 +      err = p9_client_mknod_dotl(dfid, name, mode, rdev, gid, &qid);
 +      if (err < 0)
 +              goto error;
 +
 +      /* instantiate inode and assign the unopened fid to the dentry */
 +      if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
 +              fid = p9_client_walk(dfid, 1, &name, 1);
 +              if (IS_ERR(fid)) {
 +                      err = PTR_ERR(fid);
 +                      P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
 +                              err);
 +                      fid = NULL;
 +                      goto error;
 +              }
 +
 +              inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
 +              if (IS_ERR(inode)) {
 +                      err = PTR_ERR(inode);
 +                      P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n",
 +                              err);
 +                      goto error;
 +              }
 +              dentry->d_op = &v9fs_cached_dentry_operations;
 +              d_instantiate(dentry, inode);
 +              err = v9fs_fid_add(dentry, fid);
 +              if (err < 0)
 +                      goto error;
 +              fid = NULL;
 +      } else {
 +              /*
 +               * Not in cached mode. No need to populate inode with stat.
 +               * socket syscall returns a fd, so we need instantiate
 +               */
 +              inode = v9fs_get_inode(dir->i_sb, mode);
 +              if (IS_ERR(inode)) {
 +                      err = PTR_ERR(inode);
 +                      goto error;
 +              }
 +              dentry->d_op = &v9fs_dentry_operations;
 +              d_instantiate(dentry, inode);
 +      }
 +
 +error:
 +      if (fid)
 +              p9_client_clunk(fid);
 +      return err;
 +}
 +
  static const struct inode_operations v9fs_dir_inode_operations_dotu = {
        .create = v9fs_vfs_create,
        .lookup = v9fs_vfs_lookup,
        .unlink = v9fs_vfs_unlink,
        .mkdir = v9fs_vfs_mkdir,
        .rmdir = v9fs_vfs_rmdir,
 -      .mknod = v9fs_vfs_mknod,
 +      .mknod = v9fs_vfs_mknod_dotl,
        .rename = v9fs_vfs_rename,
        .getattr = v9fs_vfs_getattr,
        .setattr = v9fs_vfs_setattr,
  };
  
  static const struct inode_operations v9fs_dir_inode_operations_dotl = {
 -      .create = v9fs_vfs_create,
 +      .create = v9fs_vfs_create_dotl,
        .lookup = v9fs_vfs_lookup,
 -      .symlink = v9fs_vfs_symlink,
 -      .link = v9fs_vfs_link,
 +      .link = v9fs_vfs_link_dotl,
 +      .symlink = v9fs_vfs_symlink_dotl,
        .unlink = v9fs_vfs_unlink,
 -      .mkdir = v9fs_vfs_mkdir,
 +      .mkdir = v9fs_vfs_mkdir_dotl,
        .rmdir = v9fs_vfs_rmdir,
 -      .mknod = v9fs_vfs_mknod,
 +      .mknod = v9fs_vfs_mknod_dotl,
        .rename = v9fs_vfs_rename,
 -      .getattr = v9fs_vfs_getattr,
 -      .setattr = v9fs_vfs_setattr,
 +      .getattr = v9fs_vfs_getattr_dotl,
 +      .setattr = v9fs_vfs_setattr_dotl,
 +      .setxattr = generic_setxattr,
 +      .getxattr = generic_getxattr,
 +      .removexattr = generic_removexattr,
 +      .listxattr = v9fs_listxattr,
 +
  };
  
  static const struct inode_operations v9fs_dir_inode_operations = {
@@@ -1965,12 -1287,8 +1976,12 @@@ static const struct inode_operations v9
  };
  
  static const struct inode_operations v9fs_file_inode_operations_dotl = {
 -      .getattr = v9fs_vfs_getattr,
 -      .setattr = v9fs_vfs_setattr,
 +      .getattr = v9fs_vfs_getattr_dotl,
 +      .setattr = v9fs_vfs_setattr_dotl,
 +      .setxattr = generic_setxattr,
 +      .getxattr = generic_getxattr,
 +      .removexattr = generic_removexattr,
 +      .listxattr = v9fs_listxattr,
  };
  
  static const struct inode_operations v9fs_symlink_inode_operations = {
@@@ -1985,10 -1303,6 +1996,10 @@@ static const struct inode_operations v9
        .readlink = generic_readlink,
        .follow_link = v9fs_vfs_follow_link,
        .put_link = v9fs_vfs_put_link,
 -      .getattr = v9fs_vfs_getattr,
 -      .setattr = v9fs_vfs_setattr,
 +      .getattr = v9fs_vfs_getattr_dotl,
 +      .setattr = v9fs_vfs_setattr_dotl,
 +      .setxattr = generic_setxattr,
 +      .getxattr = generic_getxattr,
 +      .removexattr = generic_removexattr,
 +      .listxattr = v9fs_listxattr,
  };
diff --combined fs/9p/vfs_super.c
index 4b9ede0b41b71f94fb1ae00031c7b5417cf37683,c6122bf547df2c0b179f4ecb01aa486d2ac01a3c..f9311077de6842091df9f257e3e6d91c641a0622
@@@ -45,7 -45,6 +45,7 @@@
  #include "v9fs.h"
  #include "v9fs_vfs.h"
  #include "fid.h"
 +#include "xattr.h"
  
  static const struct super_operations v9fs_super_ops, v9fs_super_ops_dotl;
  
@@@ -78,10 -77,9 +78,10 @@@ v9fs_fill_super(struct super_block *sb
        sb->s_blocksize_bits = fls(v9ses->maxdata - 1);
        sb->s_blocksize = 1 << sb->s_blocksize_bits;
        sb->s_magic = V9FS_MAGIC;
 -      if (v9fs_proto_dotl(v9ses))
 +      if (v9fs_proto_dotl(v9ses)) {
                sb->s_op = &v9fs_super_ops_dotl;
 -      else
 +              sb->s_xattr = v9fs_xattr_handlers;
 +      } else
                sb->s_op = &v9fs_super_ops;
        sb->s_bdi = &v9ses->bdi;
  
@@@ -109,6 -107,7 +109,6 @@@ static int v9fs_get_sb(struct file_syst
        struct inode *inode = NULL;
        struct dentry *root = NULL;
        struct v9fs_session_info *v9ses = NULL;
 -      struct p9_wstat *st = NULL;
        int mode = S_IRWXUGO | S_ISVTX;
        struct p9_fid *fid;
        int retval = 0;
                goto close_session;
        }
  
 -      st = p9_client_stat(fid);
 -      if (IS_ERR(st)) {
 -              retval = PTR_ERR(st);
 -              goto clunk_fid;
 -      }
 -
        sb = sget(fs_type, NULL, v9fs_set_super, v9ses);
        if (IS_ERR(sb)) {
                retval = PTR_ERR(sb);
 -              goto free_stat;
 +              goto clunk_fid;
        }
        v9fs_fill_super(sb, v9ses, flags, data);
  
        }
  
        sb->s_root = root;
 -      root->d_inode->i_ino = v9fs_qid2ino(&st->qid);
  
 -      v9fs_stat2inode(st, root->d_inode, sb);
 +      if (v9fs_proto_dotl(v9ses)) {
 +              struct p9_stat_dotl *st = NULL;
 +              st = p9_client_getattr_dotl(fid, P9_STATS_BASIC);
 +              if (IS_ERR(st)) {
 +                      retval = PTR_ERR(st);
 +                      goto clunk_fid;
 +              }
 +
 +              v9fs_stat2inode_dotl(st, root->d_inode);
 +              kfree(st);
 +      } else {
 +              struct p9_wstat *st = NULL;
 +              st = p9_client_stat(fid);
 +              if (IS_ERR(st)) {
 +                      retval = PTR_ERR(st);
 +                      goto clunk_fid;
 +              }
 +
 +              root->d_inode->i_ino = v9fs_qid2ino(&st->qid);
 +              v9fs_stat2inode(st, root->d_inode, sb);
 +
 +              p9stat_free(st);
 +              kfree(st);
 +      }
  
        v9fs_fid_add(root, fid);
 -      p9stat_free(st);
 -      kfree(st);
  
  P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n");
        simple_set_mnt(mnt, sb);
        return 0;
  
 -free_stat:
 -      p9stat_free(st);
 -      kfree(st);
 -
  clunk_fid:
        p9_client_clunk(fid);
  
@@@ -187,6 -176,8 +187,6 @@@ close_session
        return retval;
  
  release_sb:
 -      p9stat_free(st);
 -      kfree(st);
        deactivate_locked_super(sb);
        return retval;
  }
@@@ -266,7 -257,7 +266,7 @@@ static const struct super_operations v9
        .destroy_inode = v9fs_destroy_inode,
  #endif
        .statfs = simple_statfs,
-       .clear_inode = v9fs_clear_inode,
+       .evict_inode = v9fs_evict_inode,
        .show_options = generic_show_options,
        .umount_begin = v9fs_umount_begin,
  };
@@@ -277,7 -268,7 +277,7 @@@ static const struct super_operations v9
        .destroy_inode = v9fs_destroy_inode,
  #endif
        .statfs = v9fs_statfs,
-       .clear_inode = v9fs_clear_inode,
+       .evict_inode = v9fs_evict_inode,
        .show_options = generic_show_options,
        .umount_begin = v9fs_umount_begin,
  };
@@@ -287,5 -278,4 +287,5 @@@ struct file_system_type v9fs_fs_type = 
        .get_sb = v9fs_get_sb,
        .kill_sb = v9fs_kill_super,
        .owner = THIS_MODULE,
 +      .fs_flags = FS_RENAME_DOES_D_MOVE,
  };
diff --combined fs/block_dev.c
index b3171fb0dc9ab4f90eac307ed5782541f2736a0f,de7b4d0c7e30840e011a816217ebf58bf065346a..451afbd543b522157d05f84c1f490b46884e7826
@@@ -172,9 -172,8 +172,8 @@@ blkdev_direct_IO(int rw, struct kiocb *
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
  
-       return blockdev_direct_IO_no_locking_newtrunc(rw, iocb, inode,
-                               I_BDEV(inode), iov, offset, nr_segs,
-                               blkdev_get_blocks, NULL);
+       return __blockdev_direct_IO(rw, iocb, inode, I_BDEV(inode), iov, offset,
+                                   nr_segs, blkdev_get_blocks, NULL, NULL, 0);
  }
  
  int __sync_blockdev(struct block_device *bdev, int wait)
@@@ -309,9 -308,8 +308,8 @@@ static int blkdev_write_begin(struct fi
                        loff_t pos, unsigned len, unsigned flags,
                        struct page **pagep, void **fsdata)
  {
-       *pagep = NULL;
-       return block_write_begin_newtrunc(file, mapping, pos, len, flags,
-                               pagep, fsdata, blkdev_get_block);
+       return block_write_begin(mapping, pos, len, flags, pagep,
+                                blkdev_get_block);
  }
  
  static int blkdev_write_end(struct file *file, struct address_space *mapping,
@@@ -428,10 -426,13 +426,13 @@@ static inline void __bd_forget(struct i
        inode->i_mapping = &inode->i_data;
  }
  
- static void bdev_clear_inode(struct inode *inode)
+ static void bdev_evict_inode(struct inode *inode)
  {
        struct block_device *bdev = &BDEV_I(inode)->bdev;
        struct list_head *p;
+       truncate_inode_pages(&inode->i_data, 0);
+       invalidate_inode_buffers(inode); /* is it needed here? */
+       end_writeback(inode);
        spin_lock(&bdev_lock);
        while ( (p = bdev->bd_inodes.next) != &bdev->bd_inodes ) {
                __bd_forget(list_entry(p, struct inode, i_devices));
@@@ -445,7 -446,7 +446,7 @@@ static const struct super_operations bd
        .alloc_inode = bdev_alloc_inode,
        .destroy_inode = bdev_destroy_inode,
        .drop_inode = generic_delete_inode,
-       .clear_inode = bdev_clear_inode,
+       .evict_inode = bdev_evict_inode,
  };
  
  static int bd_get_sb(struct file_system_type *fs_type,
@@@ -681,8 -682,8 +682,8 @@@ retry
        if (!bd_may_claim(bdev, whole, holder))
                return -EBUSY;
  
 -      /* if someone else is claiming, wait for it to finish */
 -      if (whole->bd_claiming && whole->bd_claiming != holder) {
 +      /* if claiming is already in progress, wait for it to finish */
 +      if (whole->bd_claiming) {
                wait_queue_head_t *wq = bit_waitqueue(&whole->bd_claiming, 0);
                DEFINE_WAIT(wait);
  
diff --combined fs/cifs/cifsfs.c
index a5ed10c9afef09828c84cdc8434cc65f3b1bcbc8,5574a42b7bb6b6eed9abafb00a27277db79f737d..b7431afdd76d57fb17ef70385428dd5c132020f2
@@@ -45,6 -45,7 +45,6 @@@
  #include "cifs_fs_sb.h"
  #include <linux/mm.h>
  #include <linux/key-type.h>
 -#include "dns_resolve.h"
  #include "cifs_spnego.h"
  #include "fscache.h"
  #define CIFS_MAGIC_NUMBER 0xFF534D42  /* the first four bytes of SMB PDUs */
@@@ -329,8 -330,10 +329,10 @@@ cifs_destroy_inode(struct inode *inode
  }
  
  static void
- cifs_clear_inode(struct inode *inode)
+ cifs_evict_inode(struct inode *inode)
  {
+       truncate_inode_pages(&inode->i_data, 0);
+       end_writeback(inode);
        cifs_fscache_release_inode_cookie(inode);
  }
  
@@@ -479,14 -482,13 +481,13 @@@ static int cifs_remount(struct super_bl
        return 0;
  }
  
void cifs_drop_inode(struct inode *inode)
static int cifs_drop_inode(struct inode *inode)
  {
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
  
-       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
-               return generic_drop_inode(inode);
-       return generic_delete_inode(inode);
+       /* no serverino => unconditional eviction */
+       return !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) ||
+               generic_drop_inode(inode);
  }
  
  static const struct super_operations cifs_super_ops = {
        .alloc_inode = cifs_alloc_inode,
        .destroy_inode = cifs_destroy_inode,
        .drop_inode     = cifs_drop_inode,
-       .clear_inode    = cifs_clear_inode,
+       .evict_inode    = cifs_evict_inode,
  /*    .delete_inode   = cifs_delete_inode,  */  /* Do not need above
        function unless later we add lazy close of inodes or unless the
        kernel forgets to call us with the same number of releases (closes)
@@@ -933,13 -935,27 +934,13 @@@ init_cifs(void
        if (rc)
                goto out_unregister_filesystem;
  #endif
 -#ifdef CONFIG_CIFS_DFS_UPCALL
 -      rc = cifs_init_dns_resolver();
 -      if (rc)
 -              goto out_unregister_key_type;
 -#endif
 -      rc = slow_work_register_user(THIS_MODULE);
 -      if (rc)
 -              goto out_unregister_resolver_key;
  
        return 0;
  
 - out_unregister_resolver_key:
 -#ifdef CONFIG_CIFS_DFS_UPCALL
 -      cifs_exit_dns_resolver();
 - out_unregister_key_type:
 -#endif
  #ifdef CONFIG_CIFS_UPCALL
 -      unregister_key_type(&cifs_spnego_key_type);
   out_unregister_filesystem:
 -#endif
        unregister_filesystem(&cifs_fs_type);
 +#endif
   out_destroy_request_bufs:
        cifs_destroy_request_bufs();
   out_destroy_mids:
@@@ -961,6 -977,7 +962,6 @@@ exit_cifs(void
        cifs_fscache_unregister();
  #ifdef CONFIG_CIFS_DFS_UPCALL
        cifs_dfs_release_automount_timer();
 -      cifs_exit_dns_resolver();
  #endif
  #ifdef CONFIG_CIFS_UPCALL
        unregister_key_type(&cifs_spnego_key_type);
diff --combined fs/cifs/inode.c
index dc4c47ab95881acaa90551b44ff1cb0b9c2b8b5e,ddbe8a84c51de407dd48d7bb2a5db63caecbf6cf..4bc47e5b5f29af38d601f699face0e1f16b31a9f
@@@ -732,9 -732,15 +732,9 @@@ cifs_find_inode(struct inode *inode, vo
        if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT))
                return 0;
  
 -      /*
 -       * uh oh -- it's a directory. We can't use it since hardlinked dirs are
 -       * verboten. Disable serverino and return it as if it were found, the
 -       * caller can discard it, generate a uniqueid and retry the find
 -       */
 -      if (S_ISDIR(inode->i_mode) && !list_empty(&inode->i_dentry)) {
 +      /* if it's not a directory or has no dentries, then flag it */
 +      if (S_ISDIR(inode->i_mode) && !list_empty(&inode->i_dentry))
                fattr->cf_flags |= CIFS_FATTR_INO_COLLISION;
 -              cifs_autodisable_serverino(CIFS_SB(inode->i_sb));
 -      }
  
        return 1;
  }
@@@ -748,27 -754,6 +748,27 @@@ cifs_init_inode(struct inode *inode, vo
        return 0;
  }
  
 +/*
 + * walk dentry list for an inode and report whether it has aliases that
 + * are hashed. We use this to determine if a directory inode can actually
 + * be used.
 + */
 +static bool
 +inode_has_hashed_dentries(struct inode *inode)
 +{
 +      struct dentry *dentry;
 +
 +      spin_lock(&dcache_lock);
 +      list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
 +              if (!d_unhashed(dentry) || IS_ROOT(dentry)) {
 +                      spin_unlock(&dcache_lock);
 +                      return true;
 +              }
 +      }
 +      spin_unlock(&dcache_lock);
 +      return false;
 +}
 +
  /* Given fattrs, get a corresponding inode */
  struct inode *
  cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
@@@ -784,16 -769,12 +784,16 @@@ retry_iget5_locked
  
        inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr);
        if (inode) {
 -              /* was there a problematic inode number collision? */
 +              /* was there a potentially problematic inode collision? */
                if (fattr->cf_flags & CIFS_FATTR_INO_COLLISION) {
 -                      iput(inode);
 -                      fattr->cf_uniqueid = iunique(sb, ROOT_I);
                        fattr->cf_flags &= ~CIFS_FATTR_INO_COLLISION;
 -                      goto retry_iget5_locked;
 +
 +                      if (inode_has_hashed_dentries(inode)) {
 +                              cifs_autodisable_serverino(CIFS_SB(sb));
 +                              iput(inode);
 +                              fattr->cf_uniqueid = iunique(sb, ROOT_I);
 +                              goto retry_iget5_locked;
 +                      }
                }
  
                cifs_fattr_to_inode(inode, fattr);
@@@ -1698,26 -1679,16 +1698,16 @@@ static int cifs_truncate_page(struct ad
        return rc;
  }
  
- static int cifs_vmtruncate(struct inode *inode, loff_t offset)
+ static void cifs_setsize(struct inode *inode, loff_t offset)
  {
        loff_t oldsize;
-       int err;
  
        spin_lock(&inode->i_lock);
-       err = inode_newsize_ok(inode, offset);
-       if (err) {
-               spin_unlock(&inode->i_lock);
-               goto out;
-       }
        oldsize = inode->i_size;
        i_size_write(inode, offset);
        spin_unlock(&inode->i_lock);
        truncate_pagecache(inode, oldsize, offset);
-       if (inode->i_op->truncate)
-               inode->i_op->truncate(inode);
- out:
-       return err;
  }
  
  static int
@@@ -1790,7 -1761,7 +1780,7 @@@ cifs_set_file_size(struct inode *inode
  
        if (rc == 0) {
                cifsInode->server_eof = attrs->ia_size;
-               rc = cifs_vmtruncate(inode, attrs->ia_size);
+               cifs_setsize(inode, attrs->ia_size);
                cifs_truncate_page(inode->i_mapping, inode->i_size);
        }
  
@@@ -1815,14 -1786,12 +1805,12 @@@ cifs_setattr_unix(struct dentry *dirent
  
        xid = GetXid();
  
-       if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
-               /* check if we have permission to change attrs */
-               rc = inode_change_ok(inode, attrs);
-               if (rc < 0)
-                       goto out;
-               else
-                       rc = 0;
-       }
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
+               attrs->ia_valid |= ATTR_FORCE;
+       rc = inode_change_ok(inode, attrs);
+       if (rc < 0)
+               goto out;
  
        full_path = build_path_from_dentry(direntry);
        if (full_path == NULL) {
                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
        }
  
-       if (!rc) {
-               rc = inode_setattr(inode, attrs);
+       if (rc)
+               goto out;
  
-               /* force revalidate when any of these times are set since some
-                  of the fs types (eg ext3, fat) do not have fine enough
-                  time granularity to match protocol, and we do not have a
-                  a way (yet) to query the server fs's time granularity (and
-                  whether it rounds times down).
-               */
-               if (!rc && (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME)))
-                       cifsInode->time = 0;
-       }
+       if ((attrs->ia_valid & ATTR_SIZE) &&
+           attrs->ia_size != i_size_read(inode))
+               truncate_setsize(inode, attrs->ia_size);
+       setattr_copy(inode, attrs);
+       mark_inode_dirty(inode);
+       /* force revalidate when any of these times are set since some
+          of the fs types (eg ext3, fat) do not have fine enough
+          time granularity to match protocol, and we do not have a
+          a way (yet) to query the server fs's time granularity (and
+          whether it rounds times down).
+       */
+       if (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME))
+               cifsInode->time = 0;
  out:
        kfree(args);
        kfree(full_path);
@@@ -1944,14 -1919,13 +1938,13 @@@ cifs_setattr_nounix(struct dentry *dire
        cFYI(1, "setattr on file %s attrs->iavalid 0x%x",
                 direntry->d_name.name, attrs->ia_valid);
  
-       if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
-               /* check if we have permission to change attrs */
-               rc = inode_change_ok(inode, attrs);
-               if (rc < 0) {
-                       FreeXid(xid);
-                       return rc;
-               } else
-                       rc = 0;
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
+               attrs->ia_valid |= ATTR_FORCE;
+       rc = inode_change_ok(inode, attrs);
+       if (rc < 0) {
+               FreeXid(xid);
+               return rc;
        }
  
        full_path = build_path_from_dentry(direntry);
  
        /* do not need local check to inode_check_ok since the server does
           that */
-       if (!rc)
-               rc = inode_setattr(inode, attrs);
+       if (rc)
+               goto cifs_setattr_exit;
+       if ((attrs->ia_valid & ATTR_SIZE) &&
+           attrs->ia_size != i_size_read(inode))
+               truncate_setsize(inode, attrs->ia_size);
+       setattr_copy(inode, attrs);
+       mark_inode_dirty(inode);
+       return 0;
  cifs_setattr_exit:
        kfree(full_path);
        FreeXid(xid);
diff --combined fs/compat.c
index 5976bad85f65f818bf9894e96fcc9ec8d0174182,fc6c2adf2f6b5f990a3de5f812cda7fbd211617d..3e57e8162a394a1085ed53d6d508ede0b4006bac
@@@ -8,14 -8,13 +8,14 @@@
   *  Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
   *  Copyright (C) 1998       Eddie C. Dost  (ecd@skynet.be)
   *  Copyright (C) 2001,2002  Andi Kleen, SuSE Labs 
 - *  Copyright (C) 2003       Pavel Machek (pavel@suse.cz)
 + *  Copyright (C) 2003       Pavel Machek (pavel@ucw.cz)
   *
   *  This program is free software; you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License version 2 as
   *  published by the Free Software Foundation.
   */
  
 +#include <linux/stddef.h>
  #include <linux/kernel.h>
  #include <linux/linkage.h>
  #include <linux/compat.h>
@@@ -267,7 -266,7 +267,7 @@@ asmlinkage long compat_sys_statfs(cons
        error = user_path(pathname, &path);
        if (!error) {
                struct kstatfs tmp;
-               error = vfs_statfs(path.dentry, &tmp);
+               error = vfs_statfs(&path, &tmp);
                if (!error)
                        error = put_compat_statfs(buf, &tmp);
                path_put(&path);
@@@ -285,7 -284,7 +285,7 @@@ asmlinkage long compat_sys_fstatfs(unsi
        file = fget(fd);
        if (!file)
                goto out;
-       error = vfs_statfs(file->f_path.dentry, &tmp);
+       error = vfs_statfs(&file->f_path, &tmp);
        if (!error)
                error = put_compat_statfs(buf, &tmp);
        fput(file);
@@@ -335,7 -334,7 +335,7 @@@ asmlinkage long compat_sys_statfs64(con
        error = user_path(pathname, &path);
        if (!error) {
                struct kstatfs tmp;
-               error = vfs_statfs(path.dentry, &tmp);
+               error = vfs_statfs(&path, &tmp);
                if (!error)
                        error = put_compat_statfs64(buf, &tmp);
                path_put(&path);
@@@ -356,7 -355,7 +356,7 @@@ asmlinkage long compat_sys_fstatfs64(un
        file = fget(fd);
        if (!file)
                goto out;
-       error = vfs_statfs(file->f_path.dentry, &tmp);
+       error = vfs_statfs(&file->f_path, &tmp);
        if (!error)
                error = put_compat_statfs64(buf, &tmp);
        fput(file);
@@@ -379,7 -378,7 +379,7 @@@ asmlinkage long compat_sys_ustat(unsign
        sb = user_get_super(new_decode_dev(dev));
        if (!sb)
                return -EINVAL;
-       err = vfs_statfs(sb->s_root, &sbuf);
+       err = statfs_by_dentry(sb->s_root, &sbuf);
        drop_super(sb);
        if (err)
                return err;
@@@ -892,6 -891,8 +892,6 @@@ asmlinkage long compat_sys_mount(char _
        return retval;
  }
  
 -#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))
 -
  struct compat_old_linux_dirent {
        compat_ulong_t  d_ino;
        compat_ulong_t  d_offset;
@@@ -980,8 -981,7 +980,8 @@@ static int compat_filldir(void *__buf, 
        struct compat_linux_dirent __user * dirent;
        struct compat_getdents_callback *buf = __buf;
        compat_ulong_t d_ino;
 -      int reclen = ALIGN(NAME_OFFSET(dirent) + namlen + 2, sizeof(compat_long_t));
 +      int reclen = ALIGN(offsetof(struct compat_linux_dirent, d_name) +
 +              namlen + 2, sizeof(compat_long_t));
  
        buf->error = -EINVAL;   /* only used if we fail.. */
        if (reclen > buf->count)
@@@ -1068,8 -1068,8 +1068,8 @@@ static int compat_filldir64(void * __bu
  {
        struct linux_dirent64 __user *dirent;
        struct compat_getdents_callback64 *buf = __buf;
 -      int jj = NAME_OFFSET(dirent);
 -      int reclen = ALIGN(jj + namlen + 1, sizeof(u64));
 +      int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1,
 +              sizeof(u64));
        u64 off;
  
        buf->error = -EINVAL;   /* only used if we fail.. */
diff --combined fs/ext3/inode.c
index 001eb0e2d48e2e051936e57eba6c3e173e19dff9,cc55cecf9fbc9f7034572cc5b92d8735dfbbbeea..5e0faf4cda797800713a335f3c6d3d5d64fcd2c2
@@@ -190,18 -190,28 +190,28 @@@ static int truncate_restart_transaction
  }
  
  /*
-  * Called at the last iput() if i_nlink is zero.
+  * Called at inode eviction from icache
   */
- void ext3_delete_inode (struct inode * inode)
+ void ext3_evict_inode (struct inode *inode)
  {
+       struct ext3_block_alloc_info *rsv;
        handle_t *handle;
+       int want_delete = 0;
  
-       if (!is_bad_inode(inode))
+       if (!inode->i_nlink && !is_bad_inode(inode)) {
                dquot_initialize(inode);
+               want_delete = 1;
+       }
  
        truncate_inode_pages(&inode->i_data, 0);
  
-       if (is_bad_inode(inode))
+       ext3_discard_reservation(inode);
+       rsv = EXT3_I(inode)->i_block_alloc_info;
+       EXT3_I(inode)->i_block_alloc_info = NULL;
+       if (unlikely(rsv))
+               kfree(rsv);
+       if (!want_delete)
                goto no_delete;
  
        handle = start_transaction(inode);
         * having errors), but we can't free the inode if the mark_dirty
         * fails.
         */
-       if (ext3_mark_inode_dirty(handle, inode))
-               /* If that failed, just do the required in-core inode clear. */
-               clear_inode(inode);
-       else
+       if (ext3_mark_inode_dirty(handle, inode)) {
+               /* If that failed, just dquot_drop() and be done with that */
+               dquot_drop(inode);
+               end_writeback(inode);
+       } else {
+               ext3_xattr_delete_inode(handle, inode);
+               dquot_free_inode(inode);
+               dquot_drop(inode);
+               end_writeback(inode);
                ext3_free_inode(handle, inode);
+       }
        ext3_journal_stop(handle);
        return;
  no_delete:
-       clear_inode(inode);     /* We must guarantee clearing of inode... */
+       end_writeback(inode);
+       dquot_drop(inode);
  }
  
  typedef struct {
@@@ -1149,25 -1166,9 +1166,25 @@@ static int walk_page_buffers( handle_t 
  static int do_journal_get_write_access(handle_t *handle,
                                        struct buffer_head *bh)
  {
 +      int dirty = buffer_dirty(bh);
 +      int ret;
 +
        if (!buffer_mapped(bh) || buffer_freed(bh))
                return 0;
 -      return ext3_journal_get_write_access(handle, bh);
 +      /*
 +       * __block_prepare_write() could have dirtied some buffers. Clean
 +       * the dirty bit as jbd2_journal_get_write_access() could complain
 +       * otherwise about fs integrity issues. Setting of the dirty bit
 +       * by __block_prepare_write() isn't a real problem here as we clear
 +       * the bit before releasing a page lock and thus writeback cannot
 +       * ever write the buffer.
 +       */
 +      if (dirty)
 +              clear_buffer_dirty(bh);
 +      ret = ext3_journal_get_write_access(handle, bh);
 +      if (!ret && dirty)
 +              ret = ext3_journal_dirty_metadata(handle, bh);
 +      return ret;
  }
  
  /*
@@@ -1212,8 -1213,7 +1229,7 @@@ retry
                ret = PTR_ERR(handle);
                goto out;
        }
-       ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
-                                                       ext3_get_block);
+       ret = __block_write_begin(page, pos, len, ext3_get_block);
        if (ret)
                goto write_begin_failed;
  
@@@ -1641,7 -1641,10 +1657,7 @@@ static int ext3_writeback_writepage(str
                goto out_fail;
        }
  
 -      if (test_opt(inode->i_sb, NOBH) && ext3_should_writeback_data(inode))
 -              ret = nobh_writepage(page, ext3_get_block, wbc);
 -      else
 -              ret = block_write_full_page(page, ext3_get_block, wbc);
 +      ret = block_write_full_page(page, ext3_get_block, wbc);
  
        err = ext3_journal_stop(handle);
        if (!ret)
@@@ -1798,6 -1801,17 +1814,17 @@@ retry
        ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
                                 offset, nr_segs,
                                 ext3_get_block, NULL);
+       /*
+        * In case of error extending write may have instantiated a few
+        * blocks outside i_size. Trim these off again.
+        */
+       if (unlikely((rw & WRITE) && ret < 0)) {
+               loff_t isize = i_size_read(inode);
+               loff_t end = offset + iov_length(iov, nr_segs);
+               if (end > isize)
+                       vmtruncate(inode, isize);
+       }
        if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries))
                goto retry;
  
@@@ -1935,6 -1949,17 +1962,6 @@@ static int ext3_block_truncate_page(han
        length = blocksize - (offset & (blocksize - 1));
        iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
  
 -      /*
 -       * For "nobh" option,  we can only work if we don't need to
 -       * read-in the page - otherwise we create buffers to do the IO.
 -       */
 -      if (!page_has_buffers(page) && test_opt(inode->i_sb, NOBH) &&
 -           ext3_should_writeback_data(inode) && PageUptodate(page)) {
 -              zero_user(page, offset, length);
 -              set_page_dirty(page);
 -              goto unlock;
 -      }
 -
        if (!page_has_buffers(page))
                create_empty_buffers(page, blocksize, 0);
  
@@@ -2285,6 -2310,27 +2312,6 @@@ static void ext3_free_branches(handle_
                                           (__le32*)bh->b_data + addr_per_block,
                                           depth);
  
 -                      /*
 -                       * We've probably journalled the indirect block several
 -                       * times during the truncate.  But it's no longer
 -                       * needed and we now drop it from the transaction via
 -                       * journal_revoke().
 -                       *
 -                       * That's easy if it's exclusively part of this
 -                       * transaction.  But if it's part of the committing
 -                       * transaction then journal_forget() will simply
 -                       * brelse() it.  That means that if the underlying
 -                       * block is reallocated in ext3_get_block(),
 -                       * unmap_underlying_metadata() will find this block
 -                       * and will try to get rid of it.  damn, damn.
 -                       *
 -                       * If this block has already been committed to the
 -                       * journal, a revoke record will be written.  And
 -                       * revoke records must be emitted *before* clearing
 -                       * this block's bit in the bitmaps.
 -                       */
 -                      ext3_forget(handle, 1, inode, bh, bh->b_blocknr);
 -
                        /*
                         * Everything below this this pointer has been
                         * released.  Now let this top-of-subtree go.
                                truncate_restart_transaction(handle, inode);
                        }
  
 +                      /*
 +                       * We've probably journalled the indirect block several
 +                       * times during the truncate.  But it's no longer
 +                       * needed and we now drop it from the transaction via
 +                       * journal_revoke().
 +                       *
 +                       * That's easy if it's exclusively part of this
 +                       * transaction.  But if it's part of the committing
 +                       * transaction then journal_forget() will simply
 +                       * brelse() it.  That means that if the underlying
 +                       * block is reallocated in ext3_get_block(),
 +                       * unmap_underlying_metadata() will find this block
 +                       * and will try to get rid of it.  damn, damn. Thus
 +                       * we don't allow a block to be reallocated until
 +                       * a transaction freeing it has fully committed.
 +                       *
 +                       * We also have to make sure journal replay after a
 +                       * crash does not overwrite non-journaled data blocks
 +                       * with old metadata when the block got reallocated for
 +                       * data.  Thus we have to store a revoke record for a
 +                       * block in the same transaction in which we free the
 +                       * block.
 +                       */
 +                      ext3_forget(handle, 1, inode, bh, bh->b_blocknr);
 +
                        ext3_free_blocks(handle, inode, nr, 1);
  
                        if (parent_bh) {
@@@ -2560,7 -2581,7 +2587,7 @@@ out_stop
         * If this was a simple ftruncate(), and the file will remain alive
         * then we need to clear up the orphan record which we created above.
         * However, if this was a real unlink then we were called by
-        * ext3_delete_inode(), and we allow that function to clean up the
+        * ext3_evict_inode(), and we allow that function to clean up the
         * orphan info for us.
         */
        if (inode->i_nlink)
@@@ -3204,9 -3225,17 +3231,17 @@@ int ext3_setattr(struct dentry *dentry
                ext3_journal_stop(handle);
        }
  
-       rc = inode_setattr(inode, attr);
+       if ((attr->ia_valid & ATTR_SIZE) &&
+           attr->ia_size != i_size_read(inode)) {
+               rc = vmtruncate(inode, attr->ia_size);
+               if (rc)
+                       goto err_out;
+       }
+       setattr_copy(inode, attr);
+       mark_inode_dirty(inode);
  
-       if (!rc && (ia_valid & ATTR_MODE))
+       if (ia_valid & ATTR_MODE)
                rc = ext3_acl_chmod(inode);
  
  err_out:
diff --combined fs/ext3/super.c
index 9650a956fd0e31ec0c104db1165efa9c565be8db,a951fd5c081c9799183e83b12dc00df05c2f693b..5dbf4dba03c4d99240edd76de5e9a0a2bba4bd04
@@@ -527,17 -527,6 +527,6 @@@ static void destroy_inodecache(void
        kmem_cache_destroy(ext3_inode_cachep);
  }
  
- static void ext3_clear_inode(struct inode *inode)
- {
-       struct ext3_block_alloc_info *rsv = EXT3_I(inode)->i_block_alloc_info;
-       dquot_drop(inode);
-       ext3_discard_reservation(inode);
-       EXT3_I(inode)->i_block_alloc_info = NULL;
-       if (unlikely(rsv))
-               kfree(rsv);
- }
  static inline void ext3_show_quota_options(struct seq_file *seq, struct super_block *sb)
  {
  #if defined(CONFIG_QUOTA)
@@@ -661,6 -650,9 +650,6 @@@ static int ext3_show_options(struct seq
         */
        seq_puts(seq, ",barrier=");
        seq_puts(seq, test_opt(sb, BARRIER) ? "1" : "0");
 -      if (test_opt(sb, NOBH))
 -              seq_puts(seq, ",nobh");
 -
        seq_printf(seq, ",data=%s", data_mode_string(test_opt(sb, DATA_FLAGS)));
        if (test_opt(sb, DATA_ERR_ABORT))
                seq_puts(seq, ",data_err=abort");
@@@ -780,14 -772,13 +769,13 @@@ static const struct super_operations ex
        .destroy_inode  = ext3_destroy_inode,
        .write_inode    = ext3_write_inode,
        .dirty_inode    = ext3_dirty_inode,
-       .delete_inode   = ext3_delete_inode,
+       .evict_inode    = ext3_evict_inode,
        .put_super      = ext3_put_super,
        .sync_fs        = ext3_sync_fs,
        .freeze_fs      = ext3_freeze,
        .unfreeze_fs    = ext3_unfreeze,
        .statfs         = ext3_statfs,
        .remount_fs     = ext3_remount,
-       .clear_inode    = ext3_clear_inode,
        .show_options   = ext3_show_options,
  #ifdef CONFIG_QUOTA
        .quota_read     = ext3_quota_read,
@@@ -1252,12 -1243,10 +1240,12 @@@ set_qf_format
                        *n_blocks_count = option;
                        break;
                case Opt_nobh:
 -                      set_opt(sbi->s_mount_opt, NOBH);
 +                      ext3_msg(sb, KERN_WARNING,
 +                              "warning: ignoring deprecated nobh option");
                        break;
                case Opt_bh:
 -                      clear_opt(sbi->s_mount_opt, NOBH);
 +                      ext3_msg(sb, KERN_WARNING,
 +                              "warning: ignoring deprecated bh option");
                        break;
                default:
                        ext3_msg(sb, KERN_ERR,
@@@ -2000,6 -1989,14 +1988,6 @@@ static int ext3_fill_super (struct supe
                break;
        }
  
 -      if (test_opt(sb, NOBH)) {
 -              if (!(test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA)) {
 -                      ext3_msg(sb, KERN_WARNING,
 -                              "warning: ignoring nobh option - "
 -                              "it is supported only with writeback mode");
 -                      clear_opt(sbi->s_mount_opt, NOBH);
 -              }
 -      }
        /*
         * The journal_load will have done any necessary log recovery,
         * so we can safely mount the rest of the filesystem now.
diff --combined fs/ext4/ext4.h
index e03841d9f30b2254f41572d6bceaf4945afa7cf3,6a0d52ca14341b4cec5abfc2d55d67f7e4ca3778..889ec9d5e6adfe5b62acf19b29fd37a7faf69f08
  #endif
  
  #define EXT4_ERROR_INODE(inode, fmt, a...) \
 -      ext4_error_inode(__func__, (inode), (fmt), ## a)
 +      ext4_error_inode((inode), __func__, __LINE__, 0, (fmt), ## a)
 +
 +#define EXT4_ERROR_INODE_BLOCK(inode, block, fmt, a...)                       \
 +      ext4_error_inode((inode), __func__, __LINE__, (block), (fmt), ## a)
  
  #define EXT4_ERROR_FILE(file, fmt, a...)      \
 -      ext4_error_file(__func__, (file), (fmt), ## a)
 +      ext4_error_file(__func__, __LINE__, (file), (fmt), ## a)
  
  /* data type for block offset of block group */
  typedef int ext4_grpblk_t;
@@@ -170,15 -167,13 +170,15 @@@ struct mpage_da_data 
  };
  #define       EXT4_IO_UNWRITTEN       0x1
  typedef struct ext4_io_end {
 -      struct list_head        list;           /* per-file finished AIO list */
 +      struct list_head        list;           /* per-file finished IO list */
        struct inode            *inode;         /* file being written to */
        unsigned int            flag;           /* unwritten or not */
        struct page             *page;          /* page struct for buffer write */
        loff_t                  offset;         /* offset in the file */
        ssize_t                 size;           /* size of the extent */
        struct work_struct      work;           /* data work queue */
 +      struct kiocb            *iocb;          /* iocb struct for AIO */
 +      int                     result;         /* error value for AIO */
  } ext4_io_end_t;
  
  /*
@@@ -465,7 -460,7 +465,7 @@@ struct ext4_new_group_data 
  };
  
  /*
 - * Flags used by ext4_get_blocks()
 + * Flags used by ext4_map_blocks()
   */
        /* Allocate any needed blocks and/or convert an unitialized
           extent to be an initialized ext4 */
@@@ -878,6 -873,7 +878,6 @@@ struct ext4_inode_info 
  #define EXT4_MOUNT_POSIX_ACL          0x08000 /* POSIX Access Control Lists */
  #define EXT4_MOUNT_NO_AUTO_DA_ALLOC   0x10000 /* No auto delalloc mapping */
  #define EXT4_MOUNT_BARRIER            0x20000 /* Use block barriers */
 -#define EXT4_MOUNT_NOBH                       0x40000 /* No bufferheads */
  #define EXT4_MOUNT_QUOTA              0x80000 /* Some quota option set */
  #define EXT4_MOUNT_USRQUOTA           0x100000 /* "old" user quota */
  #define EXT4_MOUNT_GRPQUOTA           0x200000 /* "old" group quota */
@@@ -986,7 -982,7 +986,7 @@@ struct ext4_super_block 
        __le32  s_last_orphan;          /* start of list of inodes to delete */
        __le32  s_hash_seed[4];         /* HTREE hash seed */
        __u8    s_def_hash_version;     /* Default hash version to use */
 -      __u8    s_reserved_char_pad;
 +      __u8    s_jnl_backup_type;
        __le16  s_desc_size;            /* size of group descriptor */
  /*100*/       __le32  s_default_mount_opts;
        __le32  s_first_meta_bg;        /* First metablock block group */
        __le64  s_mmp_block;            /* Block for multi-mount protection */
        __le32  s_raid_stripe_width;    /* blocks on all data disks (N*stride)*/
        __u8    s_log_groups_per_flex;  /* FLEX_BG group size */
 -      __u8    s_reserved_char_pad2;
 +      __u8    s_reserved_char_pad;
        __le16  s_reserved_pad;
        __le64  s_kbytes_written;       /* nr of lifetime kilobytes written */
 -      __u32   s_reserved[160];        /* Padding to the end of the block */
 +      __le32  s_snapshot_inum;        /* Inode number of active snapshot */
 +      __le32  s_snapshot_id;          /* sequential ID of active snapshot */
 +      __le64  s_snapshot_r_blocks_count; /* reserved blocks for active
 +                                            snapshot's future use */
 +      __le32  s_snapshot_list;        /* inode number of the head of the
 +                                         on-disk snapshot list */
 +#define EXT4_S_ERR_START offsetof(struct ext4_super_block, s_error_count)
 +      __le32  s_error_count;          /* number of fs errors */
 +      __le32  s_first_error_time;     /* first time an error happened */
 +      __le32  s_first_error_ino;      /* inode involved in first error */
 +      __le64  s_first_error_block;    /* block involved of first error */
 +      __u8    s_first_error_func[32]; /* function where the error happened */
 +      __le32  s_first_error_line;     /* line number where error happened */
 +      __le32  s_last_error_time;      /* most recent time of an error */
 +      __le32  s_last_error_ino;       /* inode involved in last error */
 +      __le32  s_last_error_line;      /* line number where error happened */
 +      __le64  s_last_error_block;     /* block involved of last error */
 +      __u8    s_last_error_func[32];  /* function where the error happened */
 +#define EXT4_S_ERR_END offsetof(struct ext4_super_block, s_mount_opts)
 +      __u8    s_mount_opts[64];
 +      __le32  s_reserved[112];        /* Padding to the end of the block */
  };
  
 +#define EXT4_S_ERR_LEN (EXT4_S_ERR_END - EXT4_S_ERR_START)
 +
  #ifdef __KERNEL__
  
  /*
@@@ -1169,9 -1143,6 +1169,9 @@@ struct ext4_sb_info 
  
        /* workqueue for dio unwritten */
        struct workqueue_struct *dio_unwritten_wq;
 +
 +      /* timer for periodic error stats printing */
 +      struct timer_list s_err_report;
  };
  
  static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb)
@@@ -1342,10 -1313,6 +1342,10 @@@ EXT4_INODE_BIT_FNS(state, state_flags
  #define EXT4_DEFM_JMODE_DATA  0x0020
  #define EXT4_DEFM_JMODE_ORDERED       0x0040
  #define EXT4_DEFM_JMODE_WBACK 0x0060
 +#define EXT4_DEFM_NOBARRIER   0x0100
 +#define EXT4_DEFM_BLOCK_VALIDITY 0x0200
 +#define EXT4_DEFM_DISCARD     0x0400
 +#define EXT4_DEFM_NODELALLOC  0x0800
  
  /*
   * Default journal batch times
@@@ -1411,43 -1378,6 +1411,43 @@@ struct ext4_dir_entry_2 
                                         ~EXT4_DIR_ROUND)
  #define EXT4_MAX_REC_LEN              ((1<<16)-1)
  
 +/*
 + * If we ever get support for fs block sizes > page_size, we'll need
 + * to remove the #if statements in the next two functions...
 + */
 +static inline unsigned int
 +ext4_rec_len_from_disk(__le16 dlen, unsigned blocksize)
 +{
 +      unsigned len = le16_to_cpu(dlen);
 +
 +#if (PAGE_CACHE_SIZE >= 65536)
 +      if (len == EXT4_MAX_REC_LEN || len == 0)
 +              return blocksize;
 +      return (len & 65532) | ((len & 3) << 16);
 +#else
 +      return len;
 +#endif
 +}
 +
 +static inline __le16 ext4_rec_len_to_disk(unsigned len, unsigned blocksize)
 +{
 +      if ((len > blocksize) || (blocksize > (1 << 18)) || (len & 3))
 +              BUG();
 +#if (PAGE_CACHE_SIZE >= 65536)
 +      if (len < 65536)
 +              return cpu_to_le16(len);
 +      if (len == blocksize) {
 +              if (blocksize == 65536)
 +                      return cpu_to_le16(EXT4_MAX_REC_LEN);
 +              else
 +                      return cpu_to_le16(0);
 +      }
 +      return cpu_to_le16((len & 65532) | ((len >> 16) & 3));
 +#else
 +      return cpu_to_le16(len);
 +#endif
 +}
 +
  /*
   * Hash Tree Directory indexing
   * (c) Daniel Phillips, 2001
@@@ -1580,11 -1510,9 +1580,11 @@@ extern unsigned ext4_init_block_bitmap(
                ext4_init_block_bitmap(sb, NULL, group, desc)
  
  /* dir.c */
 -extern int ext4_check_dir_entry(const char *, struct inode *,
 -                              struct ext4_dir_entry_2 *,
 -                              struct buffer_head *, unsigned int);
 +extern int __ext4_check_dir_entry(const char *, unsigned int, struct inode *,
 +                                struct ext4_dir_entry_2 *,
 +                                struct buffer_head *, unsigned int);
 +#define ext4_check_dir_entry(dir, de, bh, offset) \
 +      __ext4_check_dir_entry(__func__, __LINE__, (dir), (de), (bh), (offset))
  extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
                                    __u32 minor_hash,
                                    struct ext4_dir_entry_2 *dirent);
@@@ -1643,7 -1571,8 +1643,8 @@@ extern int  ext4_write_inode(struct ino
  extern int  ext4_setattr(struct dentry *, struct iattr *);
  extern int  ext4_getattr(struct vfsmount *mnt, struct dentry *dentry,
                                struct kstat *stat);
- extern void ext4_delete_inode(struct inode *);
+ extern void ext4_evict_inode(struct inode *);
+ extern void ext4_clear_inode(struct inode *);
  extern int  ext4_sync_inode(handle_t *, struct inode *);
  extern void ext4_dirty_inode(struct inode *);
  extern int ext4_change_inode_journal_flag(struct inode *, int);
@@@ -1673,6 -1602,8 +1674,6 @@@ extern long ext4_compat_ioctl(struct fi
  extern int ext4_ext_migrate(struct inode *);
  
  /* namei.c */
 -extern unsigned int ext4_rec_len_from_disk(__le16 dlen, unsigned blocksize);
 -extern __le16 ext4_rec_len_to_disk(unsigned len, unsigned blocksize);
  extern int ext4_orphan_add(handle_t *, struct inode *);
  extern int ext4_orphan_del(handle_t *, struct inode *);
  extern int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
@@@ -1686,38 -1617,25 +1687,38 @@@ extern int ext4_group_extend(struct sup
                                ext4_fsblk_t n_blocks_count);
  
  /* super.c */
 -extern void __ext4_error(struct super_block *, const char *, const char *, ...)
 -      __attribute__ ((format (printf, 3, 4)));
 -#define ext4_error(sb, message...)    __ext4_error(sb, __func__, ## message)
 -extern void ext4_error_inode(const char *, struct inode *, const char *, ...)
 -      __attribute__ ((format (printf, 3, 4)));
 -extern void ext4_error_file(const char *, struct file *, const char *, ...)
 -      __attribute__ ((format (printf, 3, 4)));
 -extern void __ext4_std_error(struct super_block *, const char *, int);
 -extern void ext4_abort(struct super_block *, const char *, const char *, ...)
 -      __attribute__ ((format (printf, 3, 4)));
 -extern void __ext4_warning(struct super_block *, const char *,
 +extern void __ext4_error(struct super_block *, const char *, unsigned int,
 +                       const char *, ...)
 +      __attribute__ ((format (printf, 4, 5)));
 +#define ext4_error(sb, message...)    __ext4_error(sb, __func__,      \
 +                                                   __LINE__, ## message)
 +extern void ext4_error_inode(struct inode *, const char *, unsigned int,
 +                           ext4_fsblk_t, const char *, ...)
 +      __attribute__ ((format (printf, 5, 6)));
 +extern void ext4_error_file(struct file *, const char *, unsigned int,
 +                          const char *, ...)
 +      __attribute__ ((format (printf, 4, 5)));
 +extern void __ext4_std_error(struct super_block *, const char *,
 +                           unsigned int, int);
 +extern void __ext4_abort(struct super_block *, const char *, unsigned int,
 +                     const char *, ...)
 +      __attribute__ ((format (printf, 4, 5)));
 +#define ext4_abort(sb, message...)    __ext4_abort(sb, __func__, \
 +                                                     __LINE__, ## message)
 +extern void __ext4_warning(struct super_block *, const char *, unsigned int,
                          const char *, ...)
 -      __attribute__ ((format (printf, 3, 4)));
 -#define ext4_warning(sb, message...)  __ext4_warning(sb, __func__, ## message)
 +      __attribute__ ((format (printf, 4, 5)));
 +#define ext4_warning(sb, message...)  __ext4_warning(sb, __func__, \
 +                                                     __LINE__, ## message)
  extern void ext4_msg(struct super_block *, const char *, const char *, ...)
        __attribute__ ((format (printf, 3, 4)));
 -extern void ext4_grp_locked_error(struct super_block *, ext4_group_t,
 -                              const char *, const char *, ...)
 -      __attribute__ ((format (printf, 4, 5)));
 +extern void __ext4_grp_locked_error(const char *, unsigned int, \
 +                                  struct super_block *, ext4_group_t, \
 +                                  unsigned long, ext4_fsblk_t, \
 +                                  const char *, ...)
 +      __attribute__ ((format (printf, 7, 8)));
 +#define ext4_grp_locked_error(sb, grp, message...) \
 +      __ext4_grp_locked_error(__func__, __LINE__, (sb), (grp), ## message)
  extern void ext4_update_dynamic_rev(struct super_block *sb);
  extern int ext4_update_compat_feature(handle_t *handle, struct super_block *sb,
                                        __u32 compat);
@@@ -1851,7 -1769,7 +1852,7 @@@ static inline unsigned int ext4_flex_bg
  #define ext4_std_error(sb, errno)                             \
  do {                                                          \
        if ((errno))                                            \
 -              __ext4_std_error((sb), __func__, (errno));      \
 +              __ext4_std_error((sb), __func__, __LINE__, (errno));    \
  } while (0)
  
  #ifdef CONFIG_SMP
@@@ -1943,12 -1861,6 +1944,12 @@@ static inline void ext4_unlock_group(st
        spin_unlock(ext4_group_lock_ptr(sb, group));
  }
  
 +static inline void ext4_mark_super_dirty(struct super_block *sb)
 +{
 +      if (EXT4_SB(sb)->s_journal == NULL)
 +              sb->s_dirt =1;
 +}
 +
  /*
   * Inodes and files operations
   */
@@@ -1994,6 -1906,9 +1995,6 @@@ extern int ext4_convert_unwritten_exten
                          ssize_t len);
  extern int ext4_map_blocks(handle_t *handle, struct inode *inode,
                           struct ext4_map_blocks *map, int flags);
 -extern int ext4_get_blocks(handle_t *handle, struct inode *inode,
 -                         sector_t block, unsigned int max_blocks,
 -                         struct buffer_head *bh, int flags);
  extern int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                        __u64 start, __u64 len);
  /* move_extent.c */
diff --combined fs/ext4/ialloc.c
index ac377505ed57a2aa4b319cd868ffcd90db29dc5d,07e791a856da3a9075437e99c43644280c5b6d8d..45853e0d1f218a673809fb23522b7bdc5966d9e0
@@@ -222,7 -222,7 +222,7 @@@ void ext4_free_inode(handle_t *handle, 
        is_directory = S_ISDIR(inode->i_mode);
  
        /* Do this BEFORE marking the inode not in use or returning an error */
-       clear_inode(inode);
+       ext4_clear_inode(inode);
  
        es = EXT4_SB(sb)->s_es;
        if (ino < EXT4_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) {
@@@ -279,7 -279,7 +279,7 @@@ out
                err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh);
                if (!fatal)
                        fatal = err;
 -              sb->s_dirt = 1;
 +              ext4_mark_super_dirty(sb);
        } else
                ext4_error(sb, "bit already cleared for inode %lu", ino);
  
@@@ -965,7 -965,7 +965,7 @@@ got
        percpu_counter_dec(&sbi->s_freeinodes_counter);
        if (S_ISDIR(mode))
                percpu_counter_inc(&sbi->s_dirs_counter);
 -      sb->s_dirt = 1;
 +      ext4_mark_super_dirty(sb);
  
        if (sbi->s_log_groups_per_flex) {
                flex_group = ext4_flex_group(sbi, group);
diff --combined fs/ext4/inode.c
index a0ab3754d0d61a26aa366a68b9e5704b292b8924,c6d365f9c663bf52b0d0b7f59331f8718d6e9bfc..4b8debeb39652fa0e10bcf36d397d6125c750d1a
@@@ -167,11 -167,16 +167,16 @@@ int ext4_truncate_restart_trans(handle_
  /*
   * Called at the last iput() if i_nlink is zero.
   */
- void ext4_delete_inode(struct inode *inode)
+ void ext4_evict_inode(struct inode *inode)
  {
        handle_t *handle;
        int err;
  
+       if (inode->i_nlink) {
+               truncate_inode_pages(&inode->i_data, 0);
+               goto no_delete;
+       }
        if (!is_bad_inode(inode))
                dquot_initialize(inode);
  
                                     "couldn't extend journal (err %d)", err);
                stop_handle:
                        ext4_journal_stop(handle);
 +                      ext4_orphan_del(NULL, inode);
                        goto no_delete;
                }
        }
         */
        if (ext4_mark_inode_dirty(handle, inode))
                /* If that failed, just do the required in-core inode clear. */
-               clear_inode(inode);
+               ext4_clear_inode(inode);
        else
                ext4_free_inode(handle, inode);
        ext4_journal_stop(handle);
        return;
  no_delete:
-       clear_inode(inode);     /* We must guarantee clearing of inode... */
+       ext4_clear_inode(inode);        /* We must guarantee clearing of inode... */
  }
  
  typedef struct {
@@@ -338,11 -342,9 +343,11 @@@ static int ext4_block_to_path(struct in
        return n;
  }
  
 -static int __ext4_check_blockref(const char *function, struct inode *inode,
 +static int __ext4_check_blockref(const char *function, unsigned int line,
 +                               struct inode *inode,
                                 __le32 *p, unsigned int max)
  {
 +      struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
        __le32 *bref = p;
        unsigned int blk;
  
                if (blk &&
                    unlikely(!ext4_data_block_valid(EXT4_SB(inode->i_sb),
                                                    blk, 1))) {
 -                      ext4_error_inode(function, inode,
 -                                       "invalid block reference %u", blk);
 +                      es->s_last_error_block = cpu_to_le64(blk);
 +                      ext4_error_inode(inode, function, line, blk,
 +                                       "invalid block");
                        return -EIO;
                }
        }
  
  
  #define ext4_check_indirect_blockref(inode, bh)                         \
 -      __ext4_check_blockref(__func__, inode, (__le32 *)(bh)->b_data,  \
 +      __ext4_check_blockref(__func__, __LINE__, inode,                \
 +                            (__le32 *)(bh)->b_data,                   \
                              EXT4_ADDR_PER_BLOCK((inode)->i_sb))
  
  #define ext4_check_inode_blockref(inode)                                \
 -      __ext4_check_blockref(__func__, inode, EXT4_I(inode)->i_data,   \
 +      __ext4_check_blockref(__func__, __LINE__, inode,                \
 +                            EXT4_I(inode)->i_data,                    \
                              EXT4_NDIR_BLOCKS)
  
  /**
@@@ -1134,24 -1133,20 +1139,24 @@@ void ext4_da_update_reserve_space(struc
                ext4_discard_preallocations(inode);
  }
  
 -static int check_block_validity(struct inode *inode, const char *func,
 +static int __check_block_validity(struct inode *inode, const char *func,
 +                              unsigned int line,
                                struct ext4_map_blocks *map)
  {
        if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), map->m_pblk,
                                   map->m_len)) {
 -              ext4_error_inode(func, inode,
 -                         "lblock %lu mapped to illegal pblock %llu "
 -                         "(length %d)", (unsigned long) map->m_lblk,
 -                               map->m_pblk, map->m_len);
 +              ext4_error_inode(inode, func, line, map->m_pblk,
 +                               "lblock %lu mapped to illegal pblock "
 +                               "(length %d)", (unsigned long) map->m_lblk,
 +                               map->m_len);
                return -EIO;
        }
        return 0;
  }
  
 +#define check_block_validity(inode, map)      \
 +      __check_block_validity((inode), __func__, __LINE__, (map))
 +
  /*
   * Return the number of contiguous dirty pages in a given inode
   * starting at page frame idx.
@@@ -1254,7 -1249,7 +1259,7 @@@ int ext4_map_blocks(handle_t *handle, s
        up_read((&EXT4_I(inode)->i_data_sem));
  
        if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) {
 -              int ret = check_block_validity(inode, __func__, map);
 +              int ret = check_block_validity(inode, map);
                if (ret != 0)
                        return ret;
        }
  
        up_write((&EXT4_I(inode)->i_data_sem));
        if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) {
 -              int ret = check_block_validity(inode,
 -                                             "ext4_map_blocks_after_alloc",
 -                                             map);
 +              int ret = check_block_validity(inode, map);
                if (ret != 0)
                        return ret;
        }
@@@ -1527,25 -1524,9 +1532,25 @@@ static int walk_page_buffers(handle_t *
  static int do_journal_get_write_access(handle_t *handle,
                                       struct buffer_head *bh)
  {
 +      int dirty = buffer_dirty(bh);
 +      int ret;
 +
        if (!buffer_mapped(bh) || buffer_freed(bh))
                return 0;
 -      return ext4_journal_get_write_access(handle, bh);
 +      /*
 +       * __block_prepare_write() could have dirtied some buffers. Clean
 +       * the dirty bit as jbd2_journal_get_write_access() could complain
 +       * otherwise about fs integrity issues. Setting of the dirty bit
 +       * by __block_prepare_write() isn't a real problem here as we clear
 +       * the bit before releasing a page lock and thus writeback cannot
 +       * ever write the buffer.
 +       */
 +      if (dirty)
 +              clear_buffer_dirty(bh);
 +      ret = ext4_journal_get_write_access(handle, bh);
 +      if (!ret && dirty)
 +              ret = ext4_handle_dirty_metadata(handle, NULL, bh);
 +      return ret;
  }
  
  /*
@@@ -1602,11 -1583,9 +1607,9 @@@ retry
        *pagep = page;
  
        if (ext4_should_dioread_nolock(inode))
-               ret = block_write_begin(file, mapping, pos, len, flags, pagep,
-                               fsdata, ext4_get_block_write);
+               ret = __block_write_begin(page, pos, len, ext4_get_block_write);
        else
-               ret = block_write_begin(file, mapping, pos, len, flags, pagep,
-                               fsdata, ext4_get_block);
+               ret = __block_write_begin(page, pos, len, ext4_get_block);
  
        if (!ret && ext4_should_journal_data(inode)) {
                ret = walk_page_buffers(handle, page_buffers(page),
                unlock_page(page);
                page_cache_release(page);
                /*
-                * block_write_begin may have instantiated a few blocks
+                * __block_write_begin may have instantiated a few blocks
                 * outside i_size.  Trim these off again. Don't need
                 * i_size_read because we hold i_mutex.
                 *
@@@ -2218,7 -2197,7 +2221,7 @@@ static int mpage_da_map_blocks(struct m
        BUG_ON(!handle);
  
        /*
 -       * Call ext4_get_blocks() to allocate any delayed allocation
 +       * Call ext4_map_blocks() to allocate any delayed allocation
         * blocks, or to convert an uninitialized extent to be
         * initialized (in the case where we have written into
         * one or more preallocated blocks).
         * indicate that we are on the delayed allocation path.  This
         * affects functions in many different parts of the allocation
         * call path.  This flag exists primarily because we don't
 -       * want to change *many* call functions, so ext4_get_blocks()
 +       * want to change *many* call functions, so ext4_map_blocks()
         * will set the magic i_delalloc_reserved_flag once the
         * inode's allocation semaphore is taken.
         *
  
        blks = ext4_map_blocks(handle, mpd->inode, &map, get_blocks_flags);
        if (blks < 0) {
 +              struct super_block *sb = mpd->inode->i_sb;
 +
                err = blks;
                /*
                 * If get block returns with error we simply
                        return 0;
  
                if (err == -ENOSPC &&
 -                  ext4_count_free_blocks(mpd->inode->i_sb)) {
 +                  ext4_count_free_blocks(sb)) {
                        mpd->retval = err;
                        return 0;
                }
                 * writepage and writepages will again try to write
                 * the same.
                 */
 -              ext4_msg(mpd->inode->i_sb, KERN_CRIT,
 -                       "delayed block allocation failed for inode %lu at "
 -                       "logical offset %llu with max blocks %zd with "
 -                       "error %d", mpd->inode->i_ino,
 -                       (unsigned long long) next,
 -                       mpd->b_size >> mpd->inode->i_blkbits, err);
 -              printk(KERN_CRIT "This should not happen!!  "
 -                     "Data will be lost\n");
 -              if (err == -ENOSPC) {
 -                      ext4_print_free_blocks(mpd->inode);
 +              if (!(EXT4_SB(sb)->s_mount_flags & EXT4_MF_FS_ABORTED)) {
 +                      ext4_msg(sb, KERN_CRIT,
 +                               "delayed block allocation failed for inode %lu "
 +                               "at logical offset %llu with max blocks %zd "
 +                               "with error %d", mpd->inode->i_ino,
 +                               (unsigned long long) next,
 +                               mpd->b_size >> mpd->inode->i_blkbits, err);
 +                      ext4_msg(sb, KERN_CRIT,
 +                              "This should not happen!! Data will be lost\n");
 +                      if (err == -ENOSPC)
 +                              ext4_print_free_blocks(mpd->inode);
                }
                /* invalidate all the pages */
                ext4_da_block_invalidatepages(mpd, next,
@@@ -2347,7 -2323,7 +2350,7 @@@ static void mpage_add_bh_to_extent(stru
         * XXX Don't go larger than mballoc is willing to allocate
         * This is a stopgap solution.  We eventually need to fold
         * mpage_da_submit_io() into this function and then call
 -       * ext4_get_blocks() multiple times in a loop
 +       * ext4_map_blocks() multiple times in a loop
         */
        if (nrblocks >= 8*1024*1024/mpd->inode->i_sb->s_blocksize)
                goto flush_it;
@@@ -2580,16 -2556,18 +2583,16 @@@ static int ext4_da_get_block_prep(struc
  /*
   * This function is used as a standard get_block_t calback function
   * when there is no desire to allocate any blocks.  It is used as a
 - * callback function for block_prepare_write(), nobh_writepage(), and
 - * block_write_full_page().  These functions should only try to map a
 - * single block at a time.
 + * callback function for block_prepare_write() and block_write_full_page().
 + * These functions should only try to map a single block at a time.
   *
   * Since this function doesn't do block allocations even if the caller
   * requests it by passing in create=1, it is critically important that
   * any caller checks to make sure that any buffer heads are returned
   * by this function are either all already mapped or marked for
 - * delayed allocation before calling nobh_writepage() or
 - * block_write_full_page().  Otherwise, b_blocknr could be left
 - * unitialized, and the page write functions will be taken by
 - * surprise.
 + * delayed allocation before calling  block_write_full_page().  Otherwise,
 + * b_blocknr could be left unitialized, and the page write functions will
 + * be taken by surprise.
   */
  static int noalloc_get_block_write(struct inode *inode, sector_t iblock,
                                   struct buffer_head *bh_result, int create)
@@@ -2774,7 -2752,9 +2777,7 @@@ static int ext4_writepage(struct page *
                return __ext4_journalled_writepage(page, len);
        }
  
 -      if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode))
 -              ret = nobh_writepage(page, noalloc_get_block_write, wbc);
 -      else if (page_bufs && buffer_uninit(page_bufs)) {
 +      if (page_bufs && buffer_uninit(page_bufs)) {
                ext4_set_bh_endio(page_bufs, inode);
                ret = block_write_full_page_endio(page, noalloc_get_block_write,
                                            wbc, ext4_end_io_buffer_write);
@@@ -3169,10 -3149,13 +3172,10 @@@ static int ext4_da_write_begin(struct f
        int ret, retries = 0;
        struct page *page;
        pgoff_t index;
 -      unsigned from, to;
        struct inode *inode = mapping->host;
        handle_t *handle;
  
        index = pos >> PAGE_CACHE_SHIFT;
 -      from = pos & (PAGE_CACHE_SIZE - 1);
 -      to = from + len;
  
        if (ext4_nonda_switch(inode->i_sb)) {
                *fsdata = (void *)FALL_BACK_TO_NONDELALLOC;
@@@ -3205,8 -3188,7 +3208,7 @@@ retry
        }
        *pagep = page;
  
-       ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
-                               ext4_da_get_block_prep);
+       ret = __block_write_begin(page, pos, len, ext4_da_get_block_prep);
        if (ret < 0) {
                unlock_page(page);
                ext4_journal_stop(handle);
@@@ -3565,15 -3547,24 +3567,24 @@@ static ssize_t ext4_ind_direct_IO(int r
  
  retry:
        if (rw == READ && ext4_should_dioread_nolock(inode))
-               ret = blockdev_direct_IO_no_locking(rw, iocb, inode,
+               ret = __blockdev_direct_IO(rw, iocb, inode,
                                 inode->i_sb->s_bdev, iov,
                                 offset, nr_segs,
-                                ext4_get_block, NULL);
-       else
+                                ext4_get_block, NULL, NULL, 0);
+       else {
                ret = blockdev_direct_IO(rw, iocb, inode,
                                 inode->i_sb->s_bdev, iov,
                                 offset, nr_segs,
                                 ext4_get_block, NULL);
+               if (unlikely((rw & WRITE) && ret < 0)) {
+                       loff_t isize = i_size_read(inode);
+                       loff_t end = offset + iov_length(iov, nr_segs);
+                       if (end > isize)
+                               vmtruncate(inode, isize);
+               }
+       }
        if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
                goto retry;
  
@@@ -3688,8 -3679,6 +3699,8 @@@ static int ext4_end_io_nolock(ext4_io_e
                return ret;
        }
  
 +      if (io->iocb)
 +              aio_complete(io->iocb, io->result, 0);
        /* clear the DIO AIO unwritten flag */
        io->flag = 0;
        return ret;
@@@ -3789,8 -3778,6 +3800,8 @@@ static ext4_io_end_t *ext4_init_io_end 
                io->offset = 0;
                io->size = 0;
                io->page = NULL;
 +              io->iocb = NULL;
 +              io->result = 0;
                INIT_WORK(&io->work, ext4_end_io_work);
                INIT_LIST_HEAD(&io->list);
        }
@@@ -3820,18 -3807,12 +3831,18 @@@ static void ext4_end_io_dio(struct kioc
        if (io_end->flag != EXT4_IO_UNWRITTEN){
                ext4_free_io_end(io_end);
                iocb->private = NULL;
 -              goto out;
 +out:
 +              if (is_async)
 +                      aio_complete(iocb, ret, 0);
 +              return;
        }
  
        io_end->offset = offset;
        io_end->size = size;
 -      io_end->flag = EXT4_IO_UNWRITTEN;
 +      if (is_async) {
 +              io_end->iocb = iocb;
 +              io_end->result = ret;
 +      }
        wq = EXT4_SB(io_end->inode->i_sb)->dio_unwritten_wq;
  
        /* queue the work to convert unwritten extents to written */
        list_add_tail(&io_end->list, &ei->i_completed_io_list);
        spin_unlock_irqrestore(&ei->i_completed_io_lock, flags);
        iocb->private = NULL;
 -out:
 -      if (is_async)
 -              aio_complete(iocb, ret, 0);
  }
  
  static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate)
@@@ -3968,7 -3952,7 +3979,7 @@@ static ssize_t ext4_ext_direct_IO(int r
                                return -ENOMEM;
                        /*
                         * we save the io structure for current async
 -                       * direct IO, so that later ext4_get_blocks()
 +                       * direct IO, so that later ext4_map_blocks()
                         * could flag the io structure whether there
                         * is a unwritten extents needs to be converted
                         * when IO is completed.
@@@ -4159,6 -4143,17 +4170,6 @@@ int ext4_block_truncate_page(handle_t *
        length = blocksize - (offset & (blocksize - 1));
        iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
  
 -      /*
 -       * For "nobh" option,  we can only work if we don't need to
 -       * read-in the page - otherwise we create buffers to do the IO.
 -       */
 -      if (!page_has_buffers(page) && test_opt(inode->i_sb, NOBH) &&
 -           ext4_should_writeback_data(inode) && PageUptodate(page)) {
 -              zero_user(page, offset, length);
 -              set_page_dirty(page);
 -              goto unlock;
 -      }
 -
        if (!page_has_buffers(page))
                create_empty_buffers(page, blocksize, 0);
  
@@@ -4508,8 -4503,9 +4519,8 @@@ static void ext4_free_branches(handle_
                         * (should be rare).
                         */
                        if (!bh) {
 -                              EXT4_ERROR_INODE(inode,
 -                                               "Read failure block=%llu",
 -                                               (unsigned long long) nr);
 +                              EXT4_ERROR_INODE_BLOCK(inode, nr,
 +                                                     "Read failure");
                                continue;
                        }
  
                                        (__le32 *) bh->b_data + addr_per_block,
                                        depth);
  
 -                      /*
 -                       * We've probably journalled the indirect block several
 -                       * times during the truncate.  But it's no longer
 -                       * needed and we now drop it from the transaction via
 -                       * jbd2_journal_revoke().
 -                       *
 -                       * That's easy if it's exclusively part of this
 -                       * transaction.  But if it's part of the committing
 -                       * transaction then jbd2_journal_forget() will simply
 -                       * brelse() it.  That means that if the underlying
 -                       * block is reallocated in ext4_get_block(),
 -                       * unmap_underlying_metadata() will find this block
 -                       * and will try to get rid of it.  damn, damn.
 -                       *
 -                       * If this block has already been committed to the
 -                       * journal, a revoke record will be written.  And
 -                       * revoke records must be emitted *before* clearing
 -                       * this block's bit in the bitmaps.
 -                       */
 -                      ext4_forget(handle, 1, inode, bh, bh->b_blocknr);
 -
                        /*
                         * Everything below this this pointer has been
                         * released.  Now let this top-of-subtree go.
                                            blocks_for_truncate(inode));
                        }
  
 +                      /*
 +                       * The forget flag here is critical because if
 +                       * we are journaling (and not doing data
 +                       * journaling), we have to make sure a revoke
 +                       * record is written to prevent the journal
 +                       * replay from overwriting the (former)
 +                       * indirect block if it gets reallocated as a
 +                       * data block.  This must happen in the same
 +                       * transaction where the data blocks are
 +                       * actually freed.
 +                       */
                        ext4_free_blocks(handle, inode, 0, nr, 1,
 -                                       EXT4_FREE_BLOCKS_METADATA);
 +                                       EXT4_FREE_BLOCKS_METADATA|
 +                                       EXT4_FREE_BLOCKS_FORGET);
  
                        if (parent_bh) {
                                /*
@@@ -4815,8 -4820,8 +4826,8 @@@ static int __ext4_get_inode_loc(struct 
  
        bh = sb_getblk(sb, block);
        if (!bh) {
 -              EXT4_ERROR_INODE(inode, "unable to read inode block - "
 -                               "block %llu", block);
 +              EXT4_ERROR_INODE_BLOCK(inode, block,
 +                                     "unable to read itable block");
                return -EIO;
        }
        if (!buffer_uptodate(bh)) {
@@@ -4914,8 -4919,8 +4925,8 @@@ make_io
                submit_bh(READ_META, bh);
                wait_on_buffer(bh);
                if (!buffer_uptodate(bh)) {
 -                      EXT4_ERROR_INODE(inode, "unable to read inode "
 -                                       "block %llu", block);
 +                      EXT4_ERROR_INODE_BLOCK(inode, block,
 +                                             "unable to read itable block");
                        brelse(bh);
                        return -EIO;
                }
@@@ -4986,7 -4991,7 +4997,7 @@@ static blkcnt_t ext4_inode_blocks(struc
                /* we are using combined 48 bit field */
                i_blocks = ((u64)le16_to_cpu(raw_inode->i_blocks_high)) << 32 |
                                        le32_to_cpu(raw_inode->i_blocks_lo);
 -              if (ei->i_flags & EXT4_HUGE_FILE_FL) {
 +              if (ext4_test_inode_flag(inode, EXT4_INODE_HUGE_FILE)) {
                        /* i_blocks represent file system block size */
                        return i_blocks  << (inode->i_blkbits - 9);
                } else {
@@@ -5082,7 -5087,7 +5093,7 @@@ struct inode *ext4_iget(struct super_bl
                transaction_t *transaction;
                tid_t tid;
  
 -              spin_lock(&journal->j_state_lock);
 +              read_lock(&journal->j_state_lock);
                if (journal->j_running_transaction)
                        transaction = journal->j_running_transaction;
                else
                        tid = transaction->t_tid;
                else
                        tid = journal->j_commit_sequence;
 -              spin_unlock(&journal->j_state_lock);
 +              read_unlock(&journal->j_state_lock);
                ei->i_sync_tid = tid;
                ei->i_datasync_tid = tid;
        }
                                 ei->i_file_acl);
                ret = -EIO;
                goto bad_inode;
 -      } else if (ei->i_flags & EXT4_EXTENTS_FL) {
 +      } else if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
                if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
                    (S_ISLNK(inode->i_mode) &&
                     !ext4_inode_is_fast_symlink(inode)))
@@@ -5416,8 -5421,9 +5427,8 @@@ int ext4_write_inode(struct inode *inod
                if (wbc->sync_mode == WB_SYNC_ALL)
                        sync_dirty_buffer(iloc.bh);
                if (buffer_req(iloc.bh) && !buffer_uptodate(iloc.bh)) {
 -                      EXT4_ERROR_INODE(inode,
 -                              "IO error syncing inode (block=%llu)",
 -                              (unsigned long long) iloc.bh->b_blocknr);
 +                      EXT4_ERROR_INODE_BLOCK(inode, iloc.bh->b_blocknr,
 +                                       "IO error syncing inode");
                        err = -EIO;
                }
                brelse(iloc.bh);
@@@ -5492,8 -5498,10 +5503,8 @@@ int ext4_setattr(struct dentry *dentry
                if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) {
                        struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
  
 -                      if (attr->ia_size > sbi->s_bitmap_maxbytes) {
 -                              error = -EFBIG;
 -                              goto err_out;
 -                      }
 +                      if (attr->ia_size > sbi->s_bitmap_maxbytes)
 +                              return -EFBIG;
                }
        }
  
                        ext4_truncate(inode);
        }
  
-       rc = inode_setattr(inode, attr);
+       if ((attr->ia_valid & ATTR_SIZE) &&
+           attr->ia_size != i_size_read(inode))
+               rc = vmtruncate(inode, attr->ia_size);
  
-       /* If inode_setattr's call to ext4_truncate failed to get a
-        * transaction handle at all, we need to clean up the in-core
-        * orphan list manually. */
+       if (!rc) {
+               setattr_copy(inode, attr);
+               mark_inode_dirty(inode);
+       }
+       /*
+        * If the call to ext4_truncate failed to get a transaction handle at
+        * all, we need to clean up the in-core orphan list manually.
+        */
        if (inode->i_nlink)
                ext4_orphan_del(NULL, inode);
  
@@@ -5695,7 -5711,7 +5714,7 @@@ int ext4_writepage_trans_blocks(struct 
   * Calculate the journal credits for a chunk of data modification.
   *
   * This is called from DIO, fallocate or whoever calling
 - * ext4_get_blocks() to map/allocate a chunk of contiguous disk blocks.
 + * ext4_map_blocks() to map/allocate a chunk of contiguous disk blocks.
   *
   * journal buffers for data blocks are not included here, as DIO
   * and fallocate do no need to journal data buffers.
@@@ -5761,6 -5777,7 +5780,6 @@@ static int ext4_expand_extra_isize(stru
  {
        struct ext4_inode *raw_inode;
        struct ext4_xattr_ibody_header *header;
 -      struct ext4_xattr_entry *entry;
  
        if (EXT4_I(inode)->i_extra_isize >= new_extra_isize)
                return 0;
        raw_inode = ext4_raw_inode(&iloc);
  
        header = IHDR(inode, raw_inode);
 -      entry = IFIRST(header);
  
        /* No extended attributes present */
        if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR) ||
diff --combined fs/ext4/super.c
index 8d65575f8c8c38a32c3ab358a1cb9a49a2760dc6,f627a6a4c3176270672d6a41907de1930feaa0fc..26147746c272c2112b7067aa6415800434586b50
@@@ -241,14 -241,14 +241,14 @@@ handle_t *ext4_journal_start_sb(struct 
        if (sb->s_flags & MS_RDONLY)
                return ERR_PTR(-EROFS);
  
 -      vfs_check_frozen(sb, SB_FREEZE_WRITE);
 +      vfs_check_frozen(sb, SB_FREEZE_TRANS);
        /* Special case here: if the journal has aborted behind our
         * backs (eg. EIO in the commit thread), then we still need to
         * take the FS itself readonly cleanly. */
        journal = EXT4_SB(sb)->s_journal;
        if (journal) {
                if (is_journal_aborted(journal)) {
 -                      ext4_abort(sb, __func__, "Detected aborted journal");
 +                      ext4_abort(sb, "Detected aborted journal");
                        return ERR_PTR(-EROFS);
                }
                return jbd2_journal_start(journal, nblocks);
   * that sync() will call the filesystem's write_super callback if
   * appropriate.
   */
 -int __ext4_journal_stop(const char *where, handle_t *handle)
 +int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle)
  {
        struct super_block *sb;
        int err;
        if (!err)
                err = rc;
        if (err)
 -              __ext4_std_error(sb, where, err);
 +              __ext4_std_error(sb, where, line, err);
        return err;
  }
  
 -void ext4_journal_abort_handle(const char *caller, const char *err_fn,
 -              struct buffer_head *bh, handle_t *handle, int err)
 +void ext4_journal_abort_handle(const char *caller, unsigned int line,
 +                             const char *err_fn, struct buffer_head *bh,
 +                             handle_t *handle, int err)
  {
        char nbuf[16];
        const char *errstr = ext4_decode_error(NULL, err, nbuf);
        if (is_handle_aborted(handle))
                return;
  
 -      printk(KERN_ERR "%s: aborting transaction: %s in %s\n",
 -             caller, errstr, err_fn);
 +      printk(KERN_ERR "%s:%d: aborting transaction: %s in %s\n",
 +             caller, line, errstr, err_fn);
  
        jbd2_journal_abort_handle(handle);
  }
  
 +static void __save_error_info(struct super_block *sb, const char *func,
 +                          unsigned int line)
 +{
 +      struct ext4_super_block *es = EXT4_SB(sb)->s_es;
 +
 +      EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
 +      es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
 +      es->s_last_error_time = cpu_to_le32(get_seconds());
 +      strncpy(es->s_last_error_func, func, sizeof(es->s_last_error_func));
 +      es->s_last_error_line = cpu_to_le32(line);
 +      if (!es->s_first_error_time) {
 +              es->s_first_error_time = es->s_last_error_time;
 +              strncpy(es->s_first_error_func, func,
 +                      sizeof(es->s_first_error_func));
 +              es->s_first_error_line = cpu_to_le32(line);
 +              es->s_first_error_ino = es->s_last_error_ino;
 +              es->s_first_error_block = es->s_last_error_block;
 +      }
 +      /*
 +       * Start the daily error reporting function if it hasn't been
 +       * started already
 +       */
 +      if (!es->s_error_count)
 +              mod_timer(&EXT4_SB(sb)->s_err_report, jiffies + 24*60*60*HZ);
 +      es->s_error_count = cpu_to_le32(le32_to_cpu(es->s_error_count) + 1);
 +}
 +
 +static void save_error_info(struct super_block *sb, const char *func,
 +                          unsigned int line)
 +{
 +      __save_error_info(sb, func, line);
 +      ext4_commit_super(sb, 1);
 +}
 +
 +
  /* Deal with the reporting of failure conditions on a filesystem such as
   * inconsistencies detected or read IO failures.
   *
  
  static void ext4_handle_error(struct super_block *sb)
  {
 -      struct ext4_super_block *es = EXT4_SB(sb)->s_es;
 -
 -      EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
 -      es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
 -
        if (sb->s_flags & MS_RDONLY)
                return;
  
                ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
                sb->s_flags |= MS_RDONLY;
        }
 -      ext4_commit_super(sb, 1);
        if (test_opt(sb, ERRORS_PANIC))
                panic("EXT4-fs (device %s): panic forced after error\n",
                        sb->s_id);
  }
  
  void __ext4_error(struct super_block *sb, const char *function,
 -              const char *fmt, ...)
 +                unsigned int line, const char *fmt, ...)
  {
        va_list args;
  
        va_start(args, fmt);
 -      printk(KERN_CRIT "EXT4-fs error (device %s): %s: ", sb->s_id, function);
 +      printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: comm %s: ",
 +             sb->s_id, function, line, current->comm);
        vprintk(fmt, args);
        printk("\n");
        va_end(args);
        ext4_handle_error(sb);
  }
  
 -void ext4_error_inode(const char *function, struct inode *inode,
 +void ext4_error_inode(struct inode *inode, const char *function,
 +                    unsigned int line, ext4_fsblk_t block,
                      const char *fmt, ...)
  {
        va_list args;
 +      struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
  
 +      es->s_last_error_ino = cpu_to_le32(inode->i_ino);
 +      es->s_last_error_block = cpu_to_le64(block);
 +      save_error_info(inode->i_sb, function, line);
        va_start(args, fmt);
 -      printk(KERN_CRIT "EXT4-fs error (device %s): %s: inode #%lu: (comm %s) ",
 -             inode->i_sb->s_id, function, inode->i_ino, current->comm);
 +      printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: inode #%lu: ",
 +             inode->i_sb->s_id, function, line, inode->i_ino);
 +      if (block)
 +              printk("block %llu: ", block);
 +      printk("comm %s: ", current->comm);
        vprintk(fmt, args);
        printk("\n");
        va_end(args);
        ext4_handle_error(inode->i_sb);
  }
  
 -void ext4_error_file(const char *function, struct file *file,
 -                   const char *fmt, ...)
 +void ext4_error_file(struct file *file, const char *function,
 +                   unsigned int line, const char *fmt, ...)
  {
        va_list args;
 +      struct ext4_super_block *es;
        struct inode *inode = file->f_dentry->d_inode;
        char pathname[80], *path;
  
 +      es = EXT4_SB(inode->i_sb)->s_es;
 +      es->s_last_error_ino = cpu_to_le32(inode->i_ino);
 +      save_error_info(inode->i_sb, function, line);
        va_start(args, fmt);
        path = d_path(&(file->f_path), pathname, sizeof(pathname));
        if (!path)
                path = "(unknown)";
        printk(KERN_CRIT
 -             "EXT4-fs error (device %s): %s: inode #%lu (comm %s path %s): ",
 -             inode->i_sb->s_id, function, inode->i_ino, current->comm, path);
 +             "EXT4-fs error (device %s): %s:%d: inode #%lu "
 +             "(comm %s path %s): ",
 +             inode->i_sb->s_id, function, line, inode->i_ino,
 +             current->comm, path);
        vprintk(fmt, args);
        printk("\n");
        va_end(args);
@@@ -480,8 -435,7 +480,8 @@@ static const char *ext4_decode_error(st
  /* __ext4_std_error decodes expected errors from journaling functions
   * automatically and invokes the appropriate error response.  */
  
 -void __ext4_std_error(struct super_block *sb, const char *function, int errno)
 +void __ext4_std_error(struct super_block *sb, const char *function,
 +                    unsigned int line, int errno)
  {
        char nbuf[16];
        const char *errstr;
                return;
  
        errstr = ext4_decode_error(sb, errno, nbuf);
 -      printk(KERN_CRIT "EXT4-fs error (device %s) in %s: %s\n",
 -             sb->s_id, function, errstr);
 +      printk(KERN_CRIT "EXT4-fs error (device %s) in %s:%d: %s\n",
 +             sb->s_id, function, line, errstr);
 +      save_error_info(sb, function, line);
  
        ext4_handle_error(sb);
  }
   * case we take the easy way out and panic immediately.
   */
  
 -void ext4_abort(struct super_block *sb, const char *function,
 -              const char *fmt, ...)
 +void __ext4_abort(struct super_block *sb, const char *function,
 +              unsigned int line, const char *fmt, ...)
  {
        va_list args;
  
 +      save_error_info(sb, function, line);
        va_start(args, fmt);
 -      printk(KERN_CRIT "EXT4-fs error (device %s): %s: ", sb->s_id, function);
 +      printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: ", sb->s_id,
 +             function, line);
        vprintk(fmt, args);
        printk("\n");
        va_end(args);
  
 +      if ((sb->s_flags & MS_RDONLY) == 0) {
 +              ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
 +              sb->s_flags |= MS_RDONLY;
 +              EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FS_ABORTED;
 +              if (EXT4_SB(sb)->s_journal)
 +                      jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO);
 +              save_error_info(sb, function, line);
 +      }
        if (test_opt(sb, ERRORS_PANIC))
                panic("EXT4-fs panic from previous error\n");
 -
 -      if (sb->s_flags & MS_RDONLY)
 -              return;
 -
 -      ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
 -      EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
 -      sb->s_flags |= MS_RDONLY;
 -      EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FS_ABORTED;
 -      if (EXT4_SB(sb)->s_journal)
 -              jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO);
  }
  
  void ext4_msg (struct super_block * sb, const char *prefix,
  }
  
  void __ext4_warning(struct super_block *sb, const char *function,
 -                const char *fmt, ...)
 +                  unsigned int line, const char *fmt, ...)
  {
        va_list args;
  
        va_start(args, fmt);
 -      printk(KERN_WARNING "EXT4-fs warning (device %s): %s: ",
 -             sb->s_id, function);
 +      printk(KERN_WARNING "EXT4-fs warning (device %s): %s:%d: ",
 +             sb->s_id, function, line);
        vprintk(fmt, args);
        printk("\n");
        va_end(args);
  }
  
 -void ext4_grp_locked_error(struct super_block *sb, ext4_group_t grp,
 -                         const char *function, const char *fmt, ...)
 +void __ext4_grp_locked_error(const char *function, unsigned int line,
 +                           struct super_block *sb, ext4_group_t grp,
 +                           unsigned long ino, ext4_fsblk_t block,
 +                           const char *fmt, ...)
  __releases(bitlock)
  __acquires(bitlock)
  {
        va_list args;
        struct ext4_super_block *es = EXT4_SB(sb)->s_es;
  
 +      es->s_last_error_ino = cpu_to_le32(ino);
 +      es->s_last_error_block = cpu_to_le64(block);
 +      __save_error_info(sb, function, line);
        va_start(args, fmt);
 -      printk(KERN_CRIT "EXT4-fs error (device %s): %s: ", sb->s_id, function);
 +      printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: group %u",
 +             sb->s_id, function, line, grp);
 +      if (ino)
 +              printk("inode %lu: ", ino);
 +      if (block)
 +              printk("block %llu:", (unsigned long long) block);
        vprintk(fmt, args);
        printk("\n");
        va_end(args);
  
        if (test_opt(sb, ERRORS_CONT)) {
 -              EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
 -              es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
                ext4_commit_super(sb, 0);
                return;
        }
 +
        ext4_unlock_group(sb, grp);
        ext4_handle_error(sb);
        /*
@@@ -716,7 -660,8 +716,7 @@@ static void ext4_put_super(struct super
                err = jbd2_journal_destroy(sbi->s_journal);
                sbi->s_journal = NULL;
                if (err < 0)
 -                      ext4_abort(sb, __func__,
 -                                 "Couldn't clean up the journal");
 +                      ext4_abort(sb, "Couldn't clean up the journal");
        }
  
        ext4_release_system_zone(sb);
@@@ -868,8 -813,10 +868,10 @@@ static void destroy_inodecache(void
        kmem_cache_destroy(ext4_inode_cachep);
  }
  
static void ext4_clear_inode(struct inode *inode)
+ void ext4_clear_inode(struct inode *inode)
  {
+       invalidate_inode_buffers(inode);
+       end_writeback(inode);
        dquot_drop(inode);
        ext4_discard_preallocations(inode);
        if (EXT4_JOURNAL(inode))
@@@ -1001,12 -948,14 +1003,12 @@@ static int ext4_show_options(struct seq
                seq_puts(seq, ",journal_async_commit");
        else if (test_opt(sb, JOURNAL_CHECKSUM))
                seq_puts(seq, ",journal_checksum");
 -      if (test_opt(sb, NOBH))
 -              seq_puts(seq, ",nobh");
        if (test_opt(sb, I_VERSION))
                seq_puts(seq, ",i_version");
 -      if (!test_opt(sb, DELALLOC))
 +      if (!test_opt(sb, DELALLOC) &&
 +          !(def_mount_opts & EXT4_DEFM_NODELALLOC))
                seq_puts(seq, ",nodelalloc");
  
 -
        if (sbi->s_stripe)
                seq_printf(seq, ",stripe=%lu", sbi->s_stripe);
        /*
        if (test_opt(sb, NO_AUTO_DA_ALLOC))
                seq_puts(seq, ",noauto_da_alloc");
  
 -      if (test_opt(sb, DISCARD))
 +      if (test_opt(sb, DISCARD) && !(def_mount_opts & EXT4_DEFM_DISCARD))
                seq_puts(seq, ",discard");
  
        if (test_opt(sb, NOLOAD))
        if (test_opt(sb, DIOREAD_NOLOCK))
                seq_puts(seq, ",dioread_nolock");
  
 +      if (test_opt(sb, BLOCK_VALIDITY) &&
 +          !(def_mount_opts & EXT4_DEFM_BLOCK_VALIDITY))
 +              seq_puts(seq, ",block_validity");
 +
        ext4_show_quota_options(seq, sb);
  
        return 0;
@@@ -1122,7 -1067,6 +1124,7 @@@ static int ext4_mark_dquot_dirty(struc
  static int ext4_write_info(struct super_block *sb, int type);
  static int ext4_quota_on(struct super_block *sb, int type, int format_id,
                                char *path);
 +static int ext4_quota_off(struct super_block *sb, int type);
  static int ext4_quota_on_mount(struct super_block *sb, int type);
  static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data,
                               size_t len, loff_t off);
@@@ -1144,7 -1088,7 +1146,7 @@@ static const struct dquot_operations ex
  
  static const struct quotactl_ops ext4_qctl_operations = {
        .quota_on       = ext4_quota_on,
 -      .quota_off      = dquot_quota_off,
 +      .quota_off      = ext4_quota_off,
        .quota_sync     = dquot_quota_sync,
        .get_info       = dquot_get_dqinfo,
        .set_info       = dquot_set_dqinfo,
@@@ -1158,14 -1102,13 +1160,13 @@@ static const struct super_operations ex
        .destroy_inode  = ext4_destroy_inode,
        .write_inode    = ext4_write_inode,
        .dirty_inode    = ext4_dirty_inode,
-       .delete_inode   = ext4_delete_inode,
+       .evict_inode    = ext4_evict_inode,
        .put_super      = ext4_put_super,
        .sync_fs        = ext4_sync_fs,
        .freeze_fs      = ext4_freeze,
        .unfreeze_fs    = ext4_unfreeze,
        .statfs         = ext4_statfs,
        .remount_fs     = ext4_remount,
-       .clear_inode    = ext4_clear_inode,
        .show_options   = ext4_show_options,
  #ifdef CONFIG_QUOTA
        .quota_read     = ext4_quota_read,
@@@ -1179,12 -1122,11 +1180,11 @@@ static const struct super_operations ex
        .destroy_inode  = ext4_destroy_inode,
        .write_inode    = ext4_write_inode,
        .dirty_inode    = ext4_dirty_inode,
-       .delete_inode   = ext4_delete_inode,
+       .evict_inode    = ext4_evict_inode,
        .write_super    = ext4_write_super,
        .put_super      = ext4_put_super,
        .statfs         = ext4_statfs,
        .remount_fs     = ext4_remount,
-       .clear_inode    = ext4_clear_inode,
        .show_options   = ext4_show_options,
  #ifdef CONFIG_QUOTA
        .quota_read     = ext4_quota_read,
@@@ -1682,12 -1624,10 +1682,12 @@@ set_qf_format
                        *n_blocks_count = option;
                        break;
                case Opt_nobh:
 -                      set_opt(sbi->s_mount_opt, NOBH);
 +                      ext4_msg(sb, KERN_WARNING,
 +                               "Ignoring deprecated nobh option");
                        break;
                case Opt_bh:
 -                      clear_opt(sbi->s_mount_opt, NOBH);
 +                      ext4_msg(sb, KERN_WARNING,
 +                               "Ignoring deprecated bh option");
                        break;
                case Opt_i_version:
                        set_opt(sbi->s_mount_opt, I_VERSION);
@@@ -2309,8 -2249,6 +2309,8 @@@ static ssize_t session_write_kbytes_sho
  {
        struct super_block *sb = sbi->s_buddy_cache->i_sb;
  
 +      if (!sb->s_bdev->bd_part)
 +              return snprintf(buf, PAGE_SIZE, "0\n");
        return snprintf(buf, PAGE_SIZE, "%lu\n",
                        (part_stat_read(sb->s_bdev->bd_part, sectors[1]) -
                         sbi->s_sectors_written_start) >> 1);
@@@ -2321,8 -2259,6 +2321,8 @@@ static ssize_t lifetime_write_kbytes_sh
  {
        struct super_block *sb = sbi->s_buddy_cache->i_sb;
  
 +      if (!sb->s_bdev->bd_part)
 +              return snprintf(buf, PAGE_SIZE, "0\n");
        return snprintf(buf, PAGE_SIZE, "%llu\n",
                        (unsigned long long)(sbi->s_kbytes_written +
                        ((part_stat_read(sb->s_bdev->bd_part, sectors[1]) -
@@@ -2495,53 -2431,6 +2495,53 @@@ static int ext4_feature_set_ok(struct s
        return 1;
  }
  
 +/*
 + * This function is called once a day if we have errors logged
 + * on the file system
 + */
 +static void print_daily_error_info(unsigned long arg)
 +{
 +      struct super_block *sb = (struct super_block *) arg;
 +      struct ext4_sb_info *sbi;
 +      struct ext4_super_block *es;
 +
 +      sbi = EXT4_SB(sb);
 +      es = sbi->s_es;
 +
 +      if (es->s_error_count)
 +              ext4_msg(sb, KERN_NOTICE, "error count: %u",
 +                       le32_to_cpu(es->s_error_count));
 +      if (es->s_first_error_time) {
 +              printk(KERN_NOTICE "EXT4-fs (%s): initial error at %u: %.*s:%d",
 +                     sb->s_id, le32_to_cpu(es->s_first_error_time),
 +                     (int) sizeof(es->s_first_error_func),
 +                     es->s_first_error_func,
 +                     le32_to_cpu(es->s_first_error_line));
 +              if (es->s_first_error_ino)
 +                      printk(": inode %u",
 +                             le32_to_cpu(es->s_first_error_ino));
 +              if (es->s_first_error_block)
 +                      printk(": block %llu", (unsigned long long)
 +                             le64_to_cpu(es->s_first_error_block));
 +              printk("\n");
 +      }
 +      if (es->s_last_error_time) {
 +              printk(KERN_NOTICE "EXT4-fs (%s): last error at %u: %.*s:%d",
 +                     sb->s_id, le32_to_cpu(es->s_last_error_time),
 +                     (int) sizeof(es->s_last_error_func),
 +                     es->s_last_error_func,
 +                     le32_to_cpu(es->s_last_error_line));
 +              if (es->s_last_error_ino)
 +                      printk(": inode %u",
 +                             le32_to_cpu(es->s_last_error_ino));
 +              if (es->s_last_error_block)
 +                      printk(": block %llu", (unsigned long long)
 +                             le64_to_cpu(es->s_last_error_block));
 +              printk("\n");
 +      }
 +      mod_timer(&sbi->s_err_report, jiffies + 24*60*60*HZ);  /* Once a day */
 +}
 +
  static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                                __releases(kernel_lock)
                                __acquires(kernel_lock)
        struct inode *root;
        char *cp;
        const char *descr;
 -      int ret = -EINVAL;
 +      int ret = -ENOMEM;
        int blocksize;
        unsigned int db_count;
        unsigned int i;
  
        sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
        if (!sbi)
 -              return -ENOMEM;
 +              goto out_free_orig;
  
        sbi->s_blockgroup_lock =
                kzalloc(sizeof(struct blockgroup_lock), GFP_KERNEL);
        if (!sbi->s_blockgroup_lock) {
                kfree(sbi);
 -              return -ENOMEM;
 +              goto out_free_orig;
        }
        sb->s_fs_info = sbi;
        sbi->s_mount_opt = 0;
        sbi->s_resgid = EXT4_DEF_RESGID;
        sbi->s_inode_readahead_blks = EXT4_DEF_INODE_READAHEAD_BLKS;
        sbi->s_sb_block = sb_block;
 -      sbi->s_sectors_written_start = part_stat_read(sb->s_bdev->bd_part,
 -                                                    sectors[1]);
 +      if (sb->s_bdev->bd_part)
 +              sbi->s_sectors_written_start =
 +                      part_stat_read(sb->s_bdev->bd_part, sectors[1]);
  
        unlock_kernel();
  
        for (cp = sb->s_id; (cp = strchr(cp, '/'));)
                *cp = '!';
  
 +      ret = -EINVAL;
        blocksize = sb_min_blocksize(sb, EXT4_MIN_BLOCK_SIZE);
        if (!blocksize) {
                ext4_msg(sb, KERN_ERR, "unable to set blocksize");
                set_opt(sbi->s_mount_opt, ERRORS_CONT);
        else
                set_opt(sbi->s_mount_opt, ERRORS_RO);
 +      if (def_mount_opts & EXT4_DEFM_BLOCK_VALIDITY)
 +              set_opt(sbi->s_mount_opt, BLOCK_VALIDITY);
 +      if (def_mount_opts & EXT4_DEFM_DISCARD)
 +              set_opt(sbi->s_mount_opt, DISCARD);
  
        sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
        sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
        sbi->s_min_batch_time = EXT4_DEF_MIN_BATCH_TIME;
        sbi->s_max_batch_time = EXT4_DEF_MAX_BATCH_TIME;
  
 -      set_opt(sbi->s_mount_opt, BARRIER);
 +      if ((def_mount_opts & EXT4_DEFM_NOBARRIER) == 0)
 +              set_opt(sbi->s_mount_opt, BARRIER);
  
        /*
         * enable delayed allocation by default
         * Use -o nodelalloc to turn it off
         */
 -      if (!IS_EXT3_SB(sb))
 +      if (!IS_EXT3_SB(sb) &&
 +          ((def_mount_opts & EXT4_DEFM_NODELALLOC) == 0))
                set_opt(sbi->s_mount_opt, DELALLOC);
  
 +      if (!parse_options((char *) sbi->s_es->s_mount_opts, sb,
 +                         &journal_devnum, &journal_ioprio, NULL, 0)) {
 +              ext4_msg(sb, KERN_WARNING,
 +                       "failed to parse options in superblock: %s",
 +                       sbi->s_es->s_mount_opts);
 +      }
        if (!parse_options((char *) data, sb, &journal_devnum,
                           &journal_ioprio, NULL, 0))
                goto failed_mount;
@@@ -3037,7 -2912,18 +3037,7 @@@ no_journal
                ext4_msg(sb, KERN_ERR, "insufficient memory");
                goto failed_mount_wq;
        }
 -      if (test_opt(sb, NOBH)) {
 -              if (!(test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)) {
 -                      ext4_msg(sb, KERN_WARNING, "Ignoring nobh option - "
 -                              "its supported only with writeback mode");
 -                      clear_opt(sbi->s_mount_opt, NOBH);
 -              }
 -              if (test_opt(sb, DIOREAD_NOLOCK)) {
 -                      ext4_msg(sb, KERN_WARNING, "dioread_nolock option is "
 -                              "not supported with nobh mode");
 -                      goto failed_mount_wq;
 -              }
 -      }
 +
        EXT4_SB(sb)->dio_unwritten_wq = create_workqueue("ext4-dio-unwritten");
        if (!EXT4_SB(sb)->dio_unwritten_wq) {
                printk(KERN_ERR "EXT4-fs: failed to create DIO workqueue\n");
        ext4_ext_init(sb);
        err = ext4_mb_init(sb, needs_recovery);
        if (err) {
 -              ext4_msg(sb, KERN_ERR, "failed to initalize mballoc (%d)",
 +              ext4_msg(sb, KERN_ERR, "failed to initialize mballoc (%d)",
                         err);
                goto failed_mount4;
        }
                descr = "out journal";
  
        ext4_msg(sb, KERN_INFO, "mounted filesystem with%s. "
 -              "Opts: %s", descr, orig_data);
 +               "Opts: %s%s%s", descr, sbi->s_es->s_mount_opts,
 +               *sbi->s_es->s_mount_opts ? "; " : "", orig_data);
 +
 +      init_timer(&sbi->s_err_report);
 +      sbi->s_err_report.function = print_daily_error_info;
 +      sbi->s_err_report.data = (unsigned long) sb;
 +      if (es->s_error_count)
 +              mod_timer(&sbi->s_err_report, jiffies + 300*HZ); /* 5 minutes */
  
        lock_kernel();
        kfree(orig_data);
@@@ -3214,7 -3093,6 +3214,7 @@@ out_fail
        kfree(sbi->s_blockgroup_lock);
        kfree(sbi);
        lock_kernel();
 +out_free_orig:
        kfree(orig_data);
        return ret;
  }
@@@ -3232,7 -3110,7 +3232,7 @@@ static void ext4_init_journal_params(st
        journal->j_min_batch_time = sbi->s_min_batch_time;
        journal->j_max_batch_time = sbi->s_max_batch_time;
  
 -      spin_lock(&journal->j_state_lock);
 +      write_lock(&journal->j_state_lock);
        if (test_opt(sb, BARRIER))
                journal->j_flags |= JBD2_BARRIER;
        else
                journal->j_flags |= JBD2_ABORT_ON_SYNCDATA_ERR;
        else
                journal->j_flags &= ~JBD2_ABORT_ON_SYNCDATA_ERR;
 -      spin_unlock(&journal->j_state_lock);
 +      write_unlock(&journal->j_state_lock);
  }
  
  static journal_t *ext4_get_journal(struct super_block *sb,
@@@ -3449,17 -3327,8 +3449,17 @@@ static int ext4_load_journal(struct sup
  
        if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER))
                err = jbd2_journal_wipe(journal, !really_read_only);
 -      if (!err)
 +      if (!err) {
 +              char *save = kmalloc(EXT4_S_ERR_LEN, GFP_KERNEL);
 +              if (save)
 +                      memcpy(save, ((char *) es) +
 +                             EXT4_S_ERR_START, EXT4_S_ERR_LEN);
                err = jbd2_journal_load(journal);
 +              if (save)
 +                      memcpy(((char *) es) + EXT4_S_ERR_START,
 +                             save, EXT4_S_ERR_LEN);
 +              kfree(save);
 +      }
  
        if (err) {
                ext4_msg(sb, KERN_ERR, "error loading journal");
@@@ -3515,14 -3384,10 +3515,14 @@@ static int ext4_commit_super(struct sup
         */
        if (!(sb->s_flags & MS_RDONLY))
                es->s_wtime = cpu_to_le32(get_seconds());
 -      es->s_kbytes_written =
 -              cpu_to_le64(EXT4_SB(sb)->s_kbytes_written +
 +      if (sb->s_bdev->bd_part)
 +              es->s_kbytes_written =
 +                      cpu_to_le64(EXT4_SB(sb)->s_kbytes_written +
                            ((part_stat_read(sb->s_bdev->bd_part, sectors[1]) -
                              EXT4_SB(sb)->s_sectors_written_start) >> 1));
 +      else
 +              es->s_kbytes_written =
 +                      cpu_to_le64(EXT4_SB(sb)->s_kbytes_written);
        ext4_free_blocks_count_set(es, percpu_counter_sum_positive(
                                        &EXT4_SB(sb)->s_freeblocks_counter));
        es->s_free_inodes_count = cpu_to_le32(percpu_counter_sum_positive(
@@@ -3626,7 -3491,7 +3626,7 @@@ int ext4_force_commit(struct super_bloc
  
        journal = EXT4_SB(sb)->s_journal;
        if (journal) {
 -              vfs_check_frozen(sb, SB_FREEZE_WRITE);
 +              vfs_check_frozen(sb, SB_FREEZE_TRANS);
                ret = ext4_journal_force_commit(journal);
        }
  
@@@ -3751,7 -3616,7 +3751,7 @@@ static int ext4_remount(struct super_bl
        }
  
        if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED)
 -              ext4_abort(sb, __func__, "Abort forced by user");
 +              ext4_abort(sb, "Abort forced by user");
  
        sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
                (test_opt(sb, POSIX_ACL) ? MS_POSIXACL : 0);
@@@ -4116,18 -3981,6 +4116,18 @@@ static int ext4_quota_on(struct super_b
        return err;
  }
  
 +static int ext4_quota_off(struct super_block *sb, int type)
 +{
 +      /* Force all delayed allocation blocks to be allocated */
 +      if (test_opt(sb, DELALLOC)) {
 +              down_read(&sb->s_umount);
 +              sync_filesystem(sb);
 +              up_read(&sb->s_umount);
 +      }
 +
 +      return dquot_quota_off(sb, type);
 +}
 +
  /* Read data from quotafile - avoid pagecache and such because we cannot afford
   * acquiring the locks... As quota files are never truncated and quota code
   * itself serializes the operations (and noone else should touch the files)
@@@ -4177,6 -4030,7 +4177,6 @@@ static ssize_t ext4_quota_write(struct 
        ext4_lblk_t blk = off >> EXT4_BLOCK_SIZE_BITS(sb);
        int err = 0;
        int offset = off & (sb->s_blocksize - 1);
 -      int journal_quota = EXT4_SB(sb)->s_qf_names[type] != NULL;
        struct buffer_head *bh;
        handle_t *handle = journal_current_handle();
  
        bh = ext4_bread(handle, inode, blk, 1, &err);
        if (!bh)
                goto out;
 -      if (journal_quota) {
 -              err = ext4_journal_get_write_access(handle, bh);
 -              if (err) {
 -                      brelse(bh);
 -                      goto out;
 -              }
 +      err = ext4_journal_get_write_access(handle, bh);
 +      if (err) {
 +              brelse(bh);
 +              goto out;
        }
        lock_buffer(bh);
        memcpy(bh->b_data+offset, data, len);
        flush_dcache_page(bh->b_page);
        unlock_buffer(bh);
 -      if (journal_quota)
 -              err = ext4_handle_dirty_metadata(handle, NULL, bh);
 -      else {
 -              /* Always do at least ordered writes for quotas */
 -              err = ext4_jbd2_file_inode(handle, inode);
 -              mark_buffer_dirty(bh);
 -      }
 +      err = ext4_handle_dirty_metadata(handle, NULL, bh);
        brelse(bh);
  out:
        if (err) {
diff --combined fs/ext4/xattr.c
index a6f314249574d1605337aa3cb4844f1cc188e0a0,1c93198353e762c5817fc87526dde55085e58090..3a8cd8dff1ad7ab6aa2cff90fa9916f5141cf4f5
@@@ -458,7 -458,8 +458,7 @@@ static void ext4_xattr_update_super_blo
  
        if (ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh) == 0) {
                EXT4_SET_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_EXT_ATTR);
 -              sb->s_dirt = 1;
 -              ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh);
 +              ext4_handle_dirty_super(handle, sb);
        }
  }
  
@@@ -1417,7 -1418,7 +1417,7 @@@ ext4_xattr_cache_insert(struct buffer_h
                ea_bdebug(bh, "out of memory");
                return;
        }
-       error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, &hash);
+       error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, hash);
        if (error) {
                mb_cache_entry_free(ce);
                if (error == -EBUSY) {
@@@ -1489,8 -1490,8 +1489,8 @@@ ext4_xattr_cache_find(struct inode *ino
                return NULL;  /* never share */
        ea_idebug(inode, "looking for cached blocks [%x]", (int)hash);
  again:
-       ce = mb_cache_entry_find_first(ext4_xattr_cache, 0,
-                                      inode->i_sb->s_bdev, hash);
+       ce = mb_cache_entry_find_first(ext4_xattr_cache, inode->i_sb->s_bdev,
+                                      hash);
        while (ce) {
                struct buffer_head *bh;
  
                        return bh;
                }
                brelse(bh);
-               ce = mb_cache_entry_find_next(ce, 0, inode->i_sb->s_bdev, hash);
+               ce = mb_cache_entry_find_next(ce, inode->i_sb->s_bdev, hash);
        }
        return NULL;
  }
@@@ -1590,9 -1591,7 +1590,7 @@@ static void ext4_xattr_rehash(struct ex
  int __init
  init_ext4_xattr(void)
  {
-       ext4_xattr_cache = mb_cache_create("ext4_xattr", NULL,
-               sizeof(struct mb_cache_entry) +
-               sizeof(((struct mb_cache_entry *) 0)->e_indexes[0]), 1, 6);
+       ext4_xattr_cache = mb_cache_create("ext4_xattr", 6);
        if (!ext4_xattr_cache)
                return -ENOMEM;
        return 0;
diff --combined fs/freevxfs/vxfs_super.c
index 5132c99b1ca2385f844a297b8268b0f91904a01d,1f3ffd93b3579ac52966010c536d06523547ebe7..dc0c041e85cbcd5c14b04c0e5b09eda611605aef
@@@ -61,7 -61,7 +61,7 @@@ static int            vxfs_statfs(struct dentry *
  static int            vxfs_remount(struct super_block *, int *, char *);
  
  static const struct super_operations vxfs_super_ops = {
-       .clear_inode =          vxfs_clear_inode,
+       .evict_inode =          vxfs_evict_inode,
        .put_super =            vxfs_put_super,
        .statfs =               vxfs_statfs,
        .remount_fs =           vxfs_remount,
@@@ -135,7 -135,7 +135,7 @@@ static int vxfs_remount(struct super_bl
  }
  
  /**
 - * vxfs_read_super - read superblock into memory and initalize filesystem
 + * vxfs_read_super - read superblock into memory and initialize filesystem
   * @sbp:              VFS superblock (to fill)
   * @dp:                       fs private mount data
   * @silent:           do not complain loudly when sth is wrong
diff --combined fs/fs-writeback.c
index 30ac305e8293a3facc9a88e751cfcf88e1c5d9af,7608880b5c586f8cc6e0da664355eaa0471b1e86..b7c7586caea1d531dfb78d794c739a890f76acff
@@@ -352,7 -352,7 +352,7 @@@ writeback_single_inode(struct inode *in
  
        spin_lock(&inode_lock);
        inode->i_state &= ~I_SYNC;
-       if (!(inode->i_state & (I_FREEING | I_CLEAR))) {
+       if (!(inode->i_state & I_FREEING)) {
                if ((inode->i_state & I_DIRTY_PAGES) && wbc->for_kupdate) {
                        /*
                         * More pages get dirtied by a fast dirtier.
@@@ -499,7 -499,7 +499,7 @@@ static int writeback_sb_inodes(struct s
                if (inode_dirtied_after(inode, wbc->wb_start))
                        return 1;
  
-               BUG_ON(inode->i_state & (I_FREEING | I_CLEAR));
+               BUG_ON(inode->i_state & I_FREEING);
                __iget(inode);
                pages_skipped = wbc->pages_skipped;
                writeback_single_inode(inode, wbc);
@@@ -530,8 -530,7 +530,8 @@@ void writeback_inodes_wb(struct bdi_wri
  {
        int ret = 0;
  
 -      wbc->wb_start = jiffies; /* livelock avoidance */
 +      if (!wbc->wb_start)
 +              wbc->wb_start = jiffies; /* livelock avoidance */
        spin_lock(&inode_lock);
        if (!wbc->for_kupdate || list_empty(&wb->b_io))
                queue_io(wb, wbc->older_than_this);
@@@ -560,6 -559,7 +560,6 @@@ static void __writeback_inodes_sb(struc
  {
        WARN_ON(!rwsem_is_locked(&sb->s_umount));
  
 -      wbc->wb_start = jiffies; /* livelock avoidance */
        spin_lock(&inode_lock);
        if (!wbc->for_kupdate || list_empty(&wb->b_io))
                queue_io(wb, wbc->older_than_this);
@@@ -625,7 -625,6 +625,7 @@@ static long wb_writeback(struct bdi_wri
                wbc.range_end = LLONG_MAX;
        }
  
 +      wbc.wb_start = jiffies; /* livelock avoidance */
        for (;;) {
                /*
                 * Stop writeback when nr_pages has been consumed
@@@ -936,7 -935,7 +936,7 @@@ void __mark_inode_dirty(struct inode *i
                        if (hlist_unhashed(&inode->i_hash))
                                goto out;
                }
-               if (inode->i_state & (I_FREEING|I_CLEAR))
+               if (inode->i_state & I_FREEING)
                        goto out;
  
                /*
@@@ -1002,7 -1001,7 +1002,7 @@@ static void wait_sb_inodes(struct super
        list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
                struct address_space *mapping;
  
-               if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW))
+               if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW))
                        continue;
                mapping = inode->i_mapping;
                if (mapping->nrpages == 0)
diff --combined fs/fuse/dir.c
index 431be0795b6bdf27c43ca34a093c52ca127a77af,3978a42d4f047dfee35875721339d9abb1e1ecea..c9627c95482d1f316102272e7aee88e1f2f31fe0
@@@ -1016,7 -1016,7 +1016,7 @@@ static int fuse_permission(struct inod
                   exist.  So if permissions are revoked this won't be
                   noticed immediately, only after the attribute
                   timeout has expired */
 -      } else if (mask & MAY_ACCESS) {
 +      } else if (mask & (MAY_ACCESS | MAY_CHDIR)) {
                err = fuse_access(inode, mask);
        } else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) {
                if (!(inode->i_mode & S_IXUGO)) {
@@@ -1270,21 -1270,18 +1270,18 @@@ static int fuse_do_setattr(struct dentr
        if (!fuse_allow_task(fc, current))
                return -EACCES;
  
-       if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
-               err = inode_change_ok(inode, attr);
-               if (err)
-                       return err;
-       }
+       if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS))
+               attr->ia_valid |= ATTR_FORCE;
+       err = inode_change_ok(inode, attr);
+       if (err)
+               return err;
  
        if ((attr->ia_valid & ATTR_OPEN) && fc->atomic_o_trunc)
                return 0;
  
-       if (attr->ia_valid & ATTR_SIZE) {
-               err = inode_newsize_ok(inode, attr->ia_size);
-               if (err)
-                       return err;
+       if (attr->ia_valid & ATTR_SIZE)
                is_truncate = true;
-       }
  
        req = fuse_get_req(fc);
        if (IS_ERR(req))
diff --combined fs/gfs2/aops.c
index 5e96cbd8a454a532c058a0880fec8a6b38571ddf,54fe087bf54c8ac4e64ccea9de6666552ebae31d..194fe16d8418a332a274a74769b15277ff2d6858
@@@ -136,7 -136,10 +136,7 @@@ static int gfs2_writeback_writepage(str
        if (ret <= 0)
                return ret;
  
 -      ret = mpage_writepage(page, gfs2_get_block_noalloc, wbc);
 -      if (ret == -EAGAIN)
 -              ret = block_write_full_page(page, gfs2_get_block_noalloc, wbc);
 -      return ret;
 +      return nobh_writepage(page, gfs2_get_block_noalloc, wbc);
  }
  
  /**
@@@ -634,7 -637,9 +634,7 @@@ static int gfs2_write_begin(struct fil
                }
        }
  
 -      error = gfs2_write_alloc_required(ip, pos, len, &alloc_required);
 -      if (error)
 -              goto out_unlock;
 +      alloc_required = gfs2_write_alloc_required(ip, pos, len);
  
        if (alloc_required || gfs2_is_jdata(ip))
                gfs2_write_calc_reserv(ip, len, &data_blocks, &ind_blocks);
@@@ -697,12 -702,12 +697,12 @@@ out
        page_cache_release(page);
  
        /*
-        * XXX(hch): the call below should probably be replaced with
+        * XXX(truncate): the call below should probably be replaced with
         * a call to the gfs2-specific truncate blocks helper to actually
         * release disk blocks..
         */
        if (pos + len > ip->i_inode.i_size)
-               simple_setsize(&ip->i_inode, ip->i_inode.i_size);
+               truncate_setsize(&ip->i_inode, ip->i_inode.i_size);
  out_endtrans:
        gfs2_trans_end(sdp);
  out_trans_fail:
@@@ -1042,9 -1047,9 +1042,9 @@@ static ssize_t gfs2_direct_IO(int rw, s
        if (rv != 1)
                goto out; /* dio not valid, fall back to buffered i/o */
  
-       rv = blockdev_direct_IO_no_locking(rw, iocb, inode, inode->i_sb->s_bdev,
-                                          iov, offset, nr_segs,
-                                          gfs2_get_block_direct, NULL);
+       rv = __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
+                                 offset, nr_segs, gfs2_get_block_direct,
+                                 NULL, NULL, 0);
  out:
        gfs2_glock_dq_m(1, &gh);
        gfs2_holder_uninit(&gh);
diff --combined fs/gfs2/super.c
index 4140811a921cb7dc622a05bfa23b10e245f81daa,fa865ab37f12dc1e59a7c920285019f69e13c1b2..77cb9f830ee47eb51520bd8581ebc700b426455e
@@@ -342,6 -342,8 +342,6 @@@ int gfs2_jdesc_check(struct gfs2_jdesc 
  {
        struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
        struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
 -      int ar;
 -      int error;
  
        if (ip->i_disksize < (8 << 20) || ip->i_disksize > (1 << 30) ||
            (ip->i_disksize & (sdp->sd_sb.sb_bsize - 1))) {
        }
        jd->jd_blocks = ip->i_disksize >> sdp->sd_sb.sb_bsize_shift;
  
 -      error = gfs2_write_alloc_required(ip, 0, ip->i_disksize, &ar);
 -      if (!error && ar) {
 +      if (gfs2_write_alloc_required(ip, 0, ip->i_disksize)) {
                gfs2_consist_inode(ip);
 -              error = -EIO;
 +              return -EIO;
        }
  
 -      return error;
 +      return 0;
  }
  
  /**
@@@ -1188,7 -1191,7 +1188,7 @@@ static int gfs2_remount_fs(struct super
   * node for later deallocation.
   */
  
- static void gfs2_drop_inode(struct inode *inode)
+ static int gfs2_drop_inode(struct inode *inode)
  {
        struct gfs2_inode *ip = GFS2_I(inode);
  
                if (gl && test_bit(GLF_DEMOTE, &gl->gl_flags))
                        clear_nlink(inode);
        }
-       generic_drop_inode(inode);
- }
- /**
-  * gfs2_clear_inode - Deallocate an inode when VFS is done with it
-  * @inode: The VFS inode
-  *
-  */
- static void gfs2_clear_inode(struct inode *inode)
- {
-       struct gfs2_inode *ip = GFS2_I(inode);
-       ip->i_gl->gl_object = NULL;
-       gfs2_glock_put(ip->i_gl);
-       ip->i_gl = NULL;
-       if (ip->i_iopen_gh.gh_gl) {
-               ip->i_iopen_gh.gh_gl->gl_object = NULL;
-               gfs2_glock_dq_uninit(&ip->i_iopen_gh);
-       }
+       return generic_drop_inode(inode);
  }
  
  static int is_ancestor(const struct dentry *d1, const struct dentry *d2)
@@@ -1344,13 -1328,16 +1325,16 @@@ static int gfs2_show_options(struct seq
   * is safe, just less efficient.
   */
  
- static void gfs2_delete_inode(struct inode *inode)
+ static void gfs2_evict_inode(struct inode *inode)
  {
        struct gfs2_sbd *sdp = inode->i_sb->s_fs_info;
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_holder gh;
        int error;
  
+       if (inode->i_nlink)
+               goto out;
        error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
        if (unlikely(error)) {
                gfs2_glock_dq_uninit(&ip->i_iopen_gh);
@@@ -1404,10 -1391,18 +1388,18 @@@ out_unlock
        gfs2_holder_uninit(&ip->i_iopen_gh);
        gfs2_glock_dq_uninit(&gh);
        if (error && error != GLR_TRYFAILED && error != -EROFS)
-               fs_warn(sdp, "gfs2_delete_inode: %d\n", error);
+               fs_warn(sdp, "gfs2_evict_inode: %d\n", error);
  out:
        truncate_inode_pages(&inode->i_data, 0);
-       clear_inode(inode);
+       end_writeback(inode);
+       ip->i_gl->gl_object = NULL;
+       gfs2_glock_put(ip->i_gl);
+       ip->i_gl = NULL;
+       if (ip->i_iopen_gh.gh_gl) {
+               ip->i_iopen_gh.gh_gl->gl_object = NULL;
+               gfs2_glock_dq_uninit(&ip->i_iopen_gh);
+       }
  }
  
  static struct inode *gfs2_alloc_inode(struct super_block *sb)
@@@ -1431,14 -1426,13 +1423,13 @@@ const struct super_operations gfs2_supe
        .alloc_inode            = gfs2_alloc_inode,
        .destroy_inode          = gfs2_destroy_inode,
        .write_inode            = gfs2_write_inode,
-       .delete_inode           = gfs2_delete_inode,
+       .evict_inode            = gfs2_evict_inode,
        .put_super              = gfs2_put_super,
        .sync_fs                = gfs2_sync_fs,
        .freeze_fs              = gfs2_freeze,
        .unfreeze_fs            = gfs2_unfreeze,
        .statfs                 = gfs2_statfs,
        .remount_fs             = gfs2_remount_fs,
-       .clear_inode            = gfs2_clear_inode,
        .drop_inode             = gfs2_drop_inode,
        .show_options           = gfs2_show_options,
  };
diff --combined fs/ncpfs/inode.c
index 1e634deff941c462177f7b0e5e7535b34774fde2,c0434313f92096815f1eda1b52c17db0e70e1a50..b4de38cf49f5f3a802a112cbd99226e12d49cf38
@@@ -43,7 -43,7 +43,7 @@@
  #define NCP_DEFAULT_TIME_OUT 10
  #define NCP_DEFAULT_RETRY_COUNT 20
  
- static void ncp_delete_inode(struct inode *);
+ static void ncp_evict_inode(struct inode *);
  static void ncp_put_super(struct super_block *);
  static int  ncp_statfs(struct dentry *, struct kstatfs *);
  static int  ncp_show_options(struct seq_file *, struct vfsmount *);
@@@ -100,7 -100,7 +100,7 @@@ static const struct super_operations nc
        .alloc_inode    = ncp_alloc_inode,
        .destroy_inode  = ncp_destroy_inode,
        .drop_inode     = generic_delete_inode,
-       .delete_inode   = ncp_delete_inode,
+       .evict_inode    = ncp_evict_inode,
        .put_super      = ncp_put_super,
        .statfs         = ncp_statfs,
        .remount_fs     = ncp_remount,
@@@ -282,19 -282,19 +282,19 @@@ ncp_iget(struct super_block *sb, struc
  }
  
  static void
- ncp_delete_inode(struct inode *inode)
+ ncp_evict_inode(struct inode *inode)
  {
        truncate_inode_pages(&inode->i_data, 0);
+       end_writeback(inode);
  
        if (S_ISDIR(inode->i_mode)) {
-               DDPRINTK("ncp_delete_inode: put directory %ld\n", inode->i_ino);
+               DDPRINTK("ncp_evict_inode: put directory %ld\n", inode->i_ino);
        }
  
        if (ncp_make_closed(inode) != 0) {
                /* We can't do anything but complain. */
-               printk(KERN_ERR "ncp_delete_inode: could not close\n");
+               printk(KERN_ERR "ncp_evict_inode: could not close\n");
        }
-       clear_inode(inode);
  }
  
  static void ncp_stop_tasks(struct ncp_server *server) {
@@@ -728,8 -728,8 +728,8 @@@ out_fput
  out_bdi:
        /* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
         * 
 -       * The previously used put_filp(ncp_filp); was bogous, since
 -       * it doesn't proper unlocking.
 +       * The previously used put_filp(ncp_filp); was bogus, since
 +       * it doesn't perform proper unlocking.
         */
        fput(ncp_filp);
  out:
@@@ -924,9 -924,8 +924,8 @@@ int ncp_notify_change(struct dentry *de
                                tmpattr.ia_valid = ATTR_MODE;
                                tmpattr.ia_mode = attr->ia_mode;
  
-                               result = inode_setattr(inode, &tmpattr);
-                               if (result)
-                                       goto out;
+                               setattr_copy(inode, &tmpattr);
+                               mark_inode_dirty(inode);
                        }
                }
  #endif
                result = ncp_make_closed(inode);
                if (result)
                        goto out;
-               {
-                       struct iattr tmpattr;
-                       
-                       tmpattr.ia_valid = ATTR_SIZE;
-                       tmpattr.ia_size = attr->ia_size;
-                       
-                       result = inode_setattr(inode, &tmpattr);
+               if (attr->ia_size != i_size_read(inode)) {
+                       result = vmtruncate(inode, attr->ia_size);
                        if (result)
                                goto out;
+                       mark_inode_dirty(inode);
                }
        }
        if ((attr->ia_valid & ATTR_CTIME) != 0) {
                        NCP_FINFO(inode)->nwattr = info.attributes;
  #endif
        }
-       if (!result)
-               result = inode_setattr(inode, attr);
+       if (result)
+               goto out;
+       setattr_copy(inode, attr);
+       mark_inode_dirty(inode);
  out:
        unlock_kernel();
        return result;
diff --combined fs/nfs/inode.c
index 581d8f081e682da19c4cd622bf47227ddb68aceb,c211b8168e5bfe2b86ac2a6adff2ee611a709c9f..7d2d6c72aa780f8f68c8b919d98963d4ba8a31fb
@@@ -98,7 -98,7 +98,7 @@@ u64 nfs_compat_user_ino64(u64 fileid
        return ino;
  }
  
- void nfs_clear_inode(struct inode *inode)
static void nfs_clear_inode(struct inode *inode)
  {
        /*
         * The following should never happen...
        nfs_fscache_release_inode_cookie(inode);
  }
  
+ void nfs_evict_inode(struct inode *inode)
+ {
+       truncate_inode_pages(&inode->i_data, 0);
+       end_writeback(inode);
+       nfs_clear_inode(inode);
+ }
  /**
   * nfs_sync_mapping - helper to flush all mmapped dirty data to disk
   */
@@@ -413,8 -420,10 +420,8 @@@ nfs_setattr(struct dentry *dentry, stru
                return 0;
  
        /* Write all dirty data */
 -      if (S_ISREG(inode->i_mode)) {
 -              filemap_write_and_wait(inode->i_mapping);
 +      if (S_ISREG(inode->i_mode))
                nfs_wb_all(inode);
 -      }
  
        fattr = nfs_alloc_fattr();
        if (fattr == NULL)
@@@ -528,68 -537,6 +535,68 @@@ out
        return err;
  }
  
 +static void nfs_init_lock_context(struct nfs_lock_context *l_ctx)
 +{
 +      atomic_set(&l_ctx->count, 1);
 +      l_ctx->lockowner = current->files;
 +      l_ctx->pid = current->tgid;
 +      INIT_LIST_HEAD(&l_ctx->list);
 +}
 +
 +static struct nfs_lock_context *__nfs_find_lock_context(struct nfs_open_context *ctx)
 +{
 +      struct nfs_lock_context *pos;
 +
 +      list_for_each_entry(pos, &ctx->lock_context.list, list) {
 +              if (pos->lockowner != current->files)
 +                      continue;
 +              if (pos->pid != current->tgid)
 +                      continue;
 +              atomic_inc(&pos->count);
 +              return pos;
 +      }
 +      return NULL;
 +}
 +
 +struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx)
 +{
 +      struct nfs_lock_context *res, *new = NULL;
 +      struct inode *inode = ctx->path.dentry->d_inode;
 +
 +      spin_lock(&inode->i_lock);
 +      res = __nfs_find_lock_context(ctx);
 +      if (res == NULL) {
 +              spin_unlock(&inode->i_lock);
 +              new = kmalloc(sizeof(*new), GFP_KERNEL);
 +              if (new == NULL)
 +                      return NULL;
 +              nfs_init_lock_context(new);
 +              spin_lock(&inode->i_lock);
 +              res = __nfs_find_lock_context(ctx);
 +              if (res == NULL) {
 +                      list_add_tail(&new->list, &ctx->lock_context.list);
 +                      new->open_context = ctx;
 +                      res = new;
 +                      new = NULL;
 +              }
 +      }
 +      spin_unlock(&inode->i_lock);
 +      kfree(new);
 +      return res;
 +}
 +
 +void nfs_put_lock_context(struct nfs_lock_context *l_ctx)
 +{
 +      struct nfs_open_context *ctx = l_ctx->open_context;
 +      struct inode *inode = ctx->path.dentry->d_inode;
 +
 +      if (!atomic_dec_and_lock(&l_ctx->count, &inode->i_lock))
 +              return;
 +      list_del(&l_ctx->list);
 +      spin_unlock(&inode->i_lock);
 +      kfree(l_ctx);
 +}
 +
  /**
   * nfs_close_context - Common close_context() routine NFSv2/v3
   * @ctx: pointer to context
@@@ -626,11 -573,11 +633,11 @@@ static struct nfs_open_context *alloc_n
                path_get(&ctx->path);
                ctx->cred = get_rpccred(cred);
                ctx->state = NULL;
 -              ctx->lockowner = current->files;
                ctx->flags = 0;
                ctx->error = 0;
                ctx->dir_cookie = 0;
 -              atomic_set(&ctx->count, 1);
 +              nfs_init_lock_context(&ctx->lock_context);
 +              ctx->lock_context.open_context = ctx;
        }
        return ctx;
  }
  struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx)
  {
        if (ctx != NULL)
 -              atomic_inc(&ctx->count);
 +              atomic_inc(&ctx->lock_context.count);
        return ctx;
  }
  
@@@ -646,7 -593,7 +653,7 @@@ static void __put_nfs_open_context(stru
  {
        struct inode *inode = ctx->path.dentry->d_inode;
  
 -      if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock))
 +      if (!atomic_dec_and_lock(&ctx->lock_context.count, &inode->i_lock))
                return;
        list_del(&ctx->list);
        spin_unlock(&inode->i_lock);
@@@ -1398,8 -1345,10 +1405,10 @@@ static int nfs_update_inode(struct inod
   * to open() calls that passed nfs_atomic_lookup, but failed to call
   * nfs_open().
   */
- void nfs4_clear_inode(struct inode *inode)
+ void nfs4_evict_inode(struct inode *inode)
  {
+       truncate_inode_pages(&inode->i_data, 0);
+       end_writeback(inode);
        /* If we are holding a delegation, return it! */
        nfs_inode_return_delegation_noreclaim(inode);
        /* First call standard NFS clear_inode() code */
diff --combined fs/nfs/internal.h
index 4c2150d867147fefd1d9239e1fa46931f2a70285,f168ebdf7c6d7de615340a181f94f785f8290558..c961bc92c107d077b9d9df947ad215cb3071dbbe
@@@ -213,9 -213,9 +213,9 @@@ extern struct workqueue_struct *nfsiod_
  extern struct inode *nfs_alloc_inode(struct super_block *sb);
  extern void nfs_destroy_inode(struct inode *);
  extern int nfs_write_inode(struct inode *, struct writeback_control *);
- extern void nfs_clear_inode(struct inode *);
+ extern void nfs_evict_inode(struct inode *);
  #ifdef CONFIG_NFS_V4
- extern void nfs4_clear_inode(struct inode *);
+ extern void nfs4_evict_inode(struct inode *);
  #endif
  void nfs_zap_acl_cache(struct inode *inode);
  extern int nfs_wait_bit_killable(void *word);
@@@ -370,9 -370,10 +370,9 @@@ unsigned int nfs_page_array_len(unsigne
   * Helper for restarting RPC calls in the possible presence of NFSv4.1
   * sessions.
   */
 -static inline void nfs_restart_rpc(struct rpc_task *task, const struct nfs_client *clp)
 +static inline int nfs_restart_rpc(struct rpc_task *task, const struct nfs_client *clp)
  {
        if (nfs4_has_session(clp))
 -              rpc_restart_call_prepare(task);
 -      else
 -              rpc_restart_call(task);
 +              return rpc_restart_call_prepare(task);
 +      return rpc_restart_call(task);
  }
diff --combined fs/nfs/super.c
index f1ae39f6cb023a187edc8bba9b87707457734e07,ef2b7e468a7e0e6070b69637992bfe757a27cf1b..ee26316ad1f44eaf276299740c2a579635682fac
@@@ -270,7 -270,7 +270,7 @@@ static const struct super_operations nf
        .write_inode    = nfs_write_inode,
        .put_super      = nfs_put_super,
        .statfs         = nfs_statfs,
-       .clear_inode    = nfs_clear_inode,
+       .evict_inode    = nfs_evict_inode,
        .umount_begin   = nfs_umount_begin,
        .show_options   = nfs_show_options,
        .show_stats     = nfs_show_stats,
@@@ -340,7 -340,7 +340,7 @@@ static const struct super_operations nf
        .write_inode    = nfs_write_inode,
        .put_super      = nfs_put_super,
        .statfs         = nfs_statfs,
-       .clear_inode    = nfs4_clear_inode,
+       .evict_inode    = nfs4_evict_inode,
        .umount_begin   = nfs_umount_begin,
        .show_options   = nfs_show_options,
        .show_stats     = nfs_show_stats,
@@@ -546,9 -546,6 +546,9 @@@ static void nfs_show_mountd_options(str
  {
        struct sockaddr *sap = (struct sockaddr *)&nfss->mountd_address;
  
 +      if (nfss->flags & NFS_MOUNT_LEGACY_INTERFACE)
 +              return;
 +
        switch (sap->sa_family) {
        case AF_INET: {
                struct sockaddr_in *sin = (struct sockaddr_in *)sap;
@@@ -1783,7 -1780,6 +1783,7 @@@ static int nfs_validate_mount_data(voi
                 * can deal with.
                 */
                args->flags             = data->flags & NFS_MOUNT_FLAGMASK;
 +              args->flags             |= NFS_MOUNT_LEGACY_INTERFACE;
                args->rsize             = data->rsize;
                args->wsize             = data->wsize;
                args->timeo             = data->timeo;
diff --combined fs/nfsd/nfs4xdr.c
index f8931acb05f39586035e5bccfb906769d9334564,4d6154f66e04c676c8fe3dc6743caae6fa65098e..1a468bbd330f48410f62a74272c1f4c431755169
@@@ -1756,6 -1756,10 +1756,10 @@@ nfsd4_encode_fattr(struct svc_fh *fhp, 
        struct nfs4_acl *acl = NULL;
        struct nfsd4_compoundres *resp = rqstp->rq_resp;
        u32 minorversion = resp->cstate.minorversion;
+       struct path path = {
+               .mnt    = exp->ex_path.mnt,
+               .dentry = dentry,
+       };
  
        BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1);
        BUG_ON(bmval0 & ~nfsd_suppattrs0(minorversion));
                        FATTR4_WORD0_MAXNAME)) ||
            (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE |
                       FATTR4_WORD1_SPACE_TOTAL))) {
-               err = vfs_statfs(dentry, &statfs);
+               err = vfs_statfs(&path, &statfs);
                if (err)
                        goto out_nfserr;
        }
@@@ -2630,7 -2634,7 +2634,7 @@@ nfsd4_encode_read(struct nfsd4_compound
        }
        read->rd_vlen = v;
  
 -      nfserr = nfsd_read(read->rd_rqstp, read->rd_fhp, read->rd_filp,
 +      nfserr = nfsd_read_file(read->rd_rqstp, read->rd_fhp, read->rd_filp,
                        read->rd_offset, resp->rqstp->rq_vec, read->rd_vlen,
                        &maxcount);
  
@@@ -3325,7 -3329,6 +3329,7 @@@ nfs4svc_encode_compoundres(struct svc_r
                }
                /* Renew the clientid on success and on replay */
                release_session_client(cs->session);
 +              nfsd4_put_session(cs->session);
        }
        return 1;
  }
diff --combined fs/nfsd/vfs.c
index 9df85a13af28b03fadc9fa47ae61aeffb4dc911c,f6f1a718642fa18a47288b854e5a6ed7de8473c8..8812f6b9396955c67c9767b0d96fe43daf1f6911
@@@ -604,7 -604,7 +604,7 @@@ nfsd4_get_nfs4_acl(struct svc_rqst *rqs
        return error;
  }
  
 -#endif /* defined(CONFIG_NFS_V4) */
 +#endif /* defined(CONFIG_NFSD_V4) */
  
  #ifdef CONFIG_NFSD_V3
  /*
@@@ -903,6 -903,7 +903,6 @@@ nfsd_vfs_read(struct svc_rqst *rqstp, s
                loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
  {
        struct inode *inode;
 -      struct raparms  *ra;
        mm_segment_t    oldfs;
        __be32          err;
        int             host_err;
        if (svc_msnfs(fhp) && !lock_may_read(inode, offset, *count))
                goto out;
  
 -      /* Get readahead parameters */
 -      ra = nfsd_get_raparms(inode->i_sb->s_dev, inode->i_ino);
 -
 -      if (ra && ra->p_set)
 -              file->f_ra = ra->p_ra;
 -
        if (file->f_op->splice_read && rqstp->rq_splice_ok) {
                struct splice_desc sd = {
                        .len            = 0,
                set_fs(oldfs);
        }
  
 -      /* Write back readahead params */
 -      if (ra) {
 -              struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex];
 -              spin_lock(&rab->pb_lock);
 -              ra->p_ra = file->f_ra;
 -              ra->p_set = 1;
 -              ra->p_count--;
 -              spin_unlock(&rab->pb_lock);
 -      }
 -
        if (host_err >= 0) {
                nfsdstats.io_read += host_err;
                *count = host_err;
   * on entry. On return, *count contains the number of bytes actually read.
   * N.B. After this call fhp needs an fh_put
   */
 +__be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
 +      loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
 +{
 +      struct file *file;
 +      struct inode *inode;
 +      struct raparms  *ra;
 +      __be32 err;
 +
 +      err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file);
 +      if (err)
 +              return err;
 +
 +      inode = file->f_path.dentry->d_inode;
 +
 +      /* Get readahead parameters */
 +      ra = nfsd_get_raparms(inode->i_sb->s_dev, inode->i_ino);
 +
 +      if (ra && ra->p_set)
 +              file->f_ra = ra->p_ra;
 +
 +      err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count);
 +
 +      /* Write back readahead params */
 +      if (ra) {
 +              struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex];
 +              spin_lock(&rab->pb_lock);
 +              ra->p_ra = file->f_ra;
 +              ra->p_set = 1;
 +              ra->p_count--;
 +              spin_unlock(&rab->pb_lock);
 +      }
 +
 +      nfsd_close(file);
 +      return err;
 +}
 +
 +/* As above, but use the provided file descriptor. */
  __be32
 -nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
 +nfsd_read_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
                loff_t offset, struct kvec *vec, int vlen,
                unsigned long *count)
  {
                if (err)
                        goto out;
                err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count);
 -      } else {
 -              err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file);
 -              if (err)
 -                      goto out;
 -              err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count);
 -              nfsd_close(file);
 -      }
 +      } else /* Note file may still be NULL in NFSv4 special stateid case: */
 +              err = nfsd_read(rqstp, fhp, offset, vec, vlen, count);
  out:
        return err;
  }
@@@ -1646,7 -1631,7 +1646,7 @@@ nfsd_link(struct svc_rqst *rqstp, struc
                                char *name, int len, struct svc_fh *tfhp)
  {
        struct dentry   *ddir, *dnew, *dold;
 -      struct inode    *dirp, *dest;
 +      struct inode    *dirp;
        __be32          err;
        int             host_err;
  
                goto out_nfserr;
  
        dold = tfhp->fh_dentry;
 -      dest = dold->d_inode;
  
        host_err = mnt_want_write(tfhp->fh_export->ex_path.mnt);
        if (host_err) {
  __be32
  nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat, int access)
  {
-       __be32 err = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP | access);
-       if (!err && vfs_statfs(fhp->fh_dentry,stat))
+       struct path path = {
+               .mnt    = fhp->fh_export->ex_path.mnt,
+               .dentry = fhp->fh_dentry,
+       };
+       __be32 err;
+       err = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP | access);
+       if (!err && vfs_statfs(&path, stat))
                err = nfserr_io;
        return err;
  }
@@@ -2052,6 -2044,7 +2058,6 @@@ nfsd_permission(struct svc_rqst *rqstp
                                        struct dentry *dentry, int acc)
  {
        struct inode    *inode = dentry->d_inode;
 -      struct path     path;
        int             err;
  
        if (acc == NFSD_MAY_NOP)
        if (err == -EACCES && S_ISREG(inode->i_mode) &&
            acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE))
                err = inode_permission(inode, MAY_EXEC);
 -      if (err)
 -              goto nfsd_out;
  
 -      /* Do integrity (permission) checking now, but defer incrementing
 -       * IMA counts to the actual file open.
 -       */
 -      path.mnt = exp->ex_path.mnt;
 -      path.dentry = dentry;
 -nfsd_out:
        return err? nfserrno(err) : 0;
  }
  
diff --combined fs/nilfs2/dir.c
index b60277b4446871dcc10f36a2ede58a47694df311,d14e3b94d81fb4f58376dfa0a08b09f769fa136d..cb003c8ee1f6d9f839bd78f2a3c182086d629645
@@@ -80,23 -80,10 +80,10 @@@ static unsigned nilfs_last_byte(struct 
        return last_byte;
  }
  
- static int nilfs_prepare_chunk_uninterruptible(struct page *page,
-                                              struct address_space *mapping,
-                                              unsigned from, unsigned to)
+ static int nilfs_prepare_chunk(struct page *page, unsigned from, unsigned to)
  {
        loff_t pos = page_offset(page) + from;
-       return block_write_begin(NULL, mapping, pos, to - from,
-                                AOP_FLAG_UNINTERRUPTIBLE, &page,
-                                NULL, nilfs_get_block);
- }
- static int nilfs_prepare_chunk(struct page *page,
-                              struct address_space *mapping,
-                              unsigned from, unsigned to)
- {
-       loff_t pos = page_offset(page) + from;
-       return block_write_begin(NULL, mapping, pos, to - from, 0, &page,
-                                NULL, nilfs_get_block);
+       return __block_write_begin(page, pos, to - from, nilfs_get_block);
  }
  
  static void nilfs_commit_chunk(struct page *page,
@@@ -141,7 -128,7 +128,7 @@@ static void nilfs_check_page(struct pag
        }
        for (offs = 0; offs <= limit - NILFS_DIR_REC_LEN(1); offs += rec_len) {
                p = (struct nilfs_dir_entry *)(kaddr + offs);
 -              rec_len = le16_to_cpu(p->rec_len);
 +              rec_len = nilfs_rec_len_from_disk(p->rec_len);
  
                if (rec_len < NILFS_DIR_REC_LEN(1))
                        goto Eshort;
@@@ -199,10 -186,13 +186,10 @@@ fail
  static struct page *nilfs_get_page(struct inode *dir, unsigned long n)
  {
        struct address_space *mapping = dir->i_mapping;
 -      struct page *page = read_cache_page(mapping, n,
 -                              (filler_t *)mapping->a_ops->readpage, NULL);
 +      struct page *page = read_mapping_page(mapping, n, NULL);
 +
        if (!IS_ERR(page)) {
 -              wait_on_page_locked(page);
                kmap(page);
 -              if (!PageUptodate(page))
 -                      goto fail;
                if (!PageChecked(page))
                        nilfs_check_page(page);
                if (PageError(page))
@@@ -235,8 -225,7 +222,8 @@@ nilfs_match(int len, const unsigned cha
   */
  static struct nilfs_dir_entry *nilfs_next_entry(struct nilfs_dir_entry *p)
  {
 -      return (struct nilfs_dir_entry *)((char *)p + le16_to_cpu(p->rec_len));
 +      return (struct nilfs_dir_entry *)((char *)p +
 +                                        nilfs_rec_len_from_disk(p->rec_len));
  }
  
  static unsigned char
@@@ -327,7 -316,7 +314,7 @@@ static int nilfs_readdir(struct file *f
                                        goto success;
                                }
                        }
 -                      filp->f_pos += le16_to_cpu(de->rec_len);
 +                      filp->f_pos += nilfs_rec_len_from_disk(de->rec_len);
                }
                nilfs_put_page(page);
        }
@@@ -442,12 -431,12 +429,12 @@@ void nilfs_set_link(struct inode *dir, 
                    struct page *page, struct inode *inode)
  {
        unsigned from = (char *) de - (char *) page_address(page);
 -      unsigned to = from + le16_to_cpu(de->rec_len);
 +      unsigned to = from + nilfs_rec_len_from_disk(de->rec_len);
        struct address_space *mapping = page->mapping;
        int err;
  
        lock_page(page);
-       err = nilfs_prepare_chunk_uninterruptible(page, mapping, from, to);
+       err = nilfs_prepare_chunk(page, from, to);
        BUG_ON(err);
        de->inode = cpu_to_le64(inode->i_ino);
        nilfs_set_de_type(de, inode);
@@@ -498,7 -487,7 +485,7 @@@ int nilfs_add_link(struct dentry *dentr
                                /* We hit i_size */
                                name_len = 0;
                                rec_len = chunk_size;
 -                              de->rec_len = cpu_to_le16(chunk_size);
 +                              de->rec_len = nilfs_rec_len_to_disk(chunk_size);
                                de->inode = 0;
                                goto got_it;
                        }
                        if (nilfs_match(namelen, name, de))
                                goto out_unlock;
                        name_len = NILFS_DIR_REC_LEN(de->name_len);
 -                      rec_len = le16_to_cpu(de->rec_len);
 +                      rec_len = nilfs_rec_len_from_disk(de->rec_len);
                        if (!de->inode && rec_len >= reclen)
                                goto got_it;
                        if (rec_len >= name_len + reclen)
  got_it:
        from = (char *)de - (char *)page_address(page);
        to = from + rec_len;
-       err = nilfs_prepare_chunk(page, page->mapping, from, to);
+       err = nilfs_prepare_chunk(page, from, to);
        if (err)
                goto out_unlock;
        if (de->inode) {
                struct nilfs_dir_entry *de1;
  
                de1 = (struct nilfs_dir_entry *)((char *)de + name_len);
 -              de1->rec_len = cpu_to_le16(rec_len - name_len);
 -              de->rec_len = cpu_to_le16(name_len);
 +              de1->rec_len = nilfs_rec_len_to_disk(rec_len - name_len);
 +              de->rec_len = nilfs_rec_len_to_disk(name_len);
                de = de1;
        }
        de->name_len = namelen;
@@@ -567,8 -556,7 +554,8 @@@ int nilfs_delete_entry(struct nilfs_dir
        struct inode *inode = mapping->host;
        char *kaddr = page_address(page);
        unsigned from = ((char *)dir - kaddr) & ~(nilfs_chunk_size(inode) - 1);
 -      unsigned to = ((char *)dir - kaddr) + le16_to_cpu(dir->rec_len);
 +      unsigned to = ((char *)dir - kaddr) +
 +              nilfs_rec_len_from_disk(dir->rec_len);
        struct nilfs_dir_entry *pde = NULL;
        struct nilfs_dir_entry *de = (struct nilfs_dir_entry *)(kaddr + from);
        int err;
        if (pde)
                from = (char *)pde - (char *)page_address(page);
        lock_page(page);
-       err = nilfs_prepare_chunk(page, mapping, from, to);
+       err = nilfs_prepare_chunk(page, from, to);
        BUG_ON(err);
        if (pde)
 -              pde->rec_len = cpu_to_le16(to - from);
 +              pde->rec_len = nilfs_rec_len_to_disk(to - from);
        dir->inode = 0;
        nilfs_commit_chunk(page, mapping, from, to);
        inode->i_ctime = inode->i_mtime = CURRENT_TIME;
@@@ -614,7 -602,7 +601,7 @@@ int nilfs_make_empty(struct inode *inod
        if (!page)
                return -ENOMEM;
  
-       err = nilfs_prepare_chunk(page, mapping, 0, chunk_size);
+       err = nilfs_prepare_chunk(page, 0, chunk_size);
        if (unlikely(err)) {
                unlock_page(page);
                goto fail;
        memset(kaddr, 0, chunk_size);
        de = (struct nilfs_dir_entry *)kaddr;
        de->name_len = 1;
 -      de->rec_len = cpu_to_le16(NILFS_DIR_REC_LEN(1));
 +      de->rec_len = nilfs_rec_len_to_disk(NILFS_DIR_REC_LEN(1));
        memcpy(de->name, ".\0\0", 4);
        de->inode = cpu_to_le64(inode->i_ino);
        nilfs_set_de_type(de, inode);
  
        de = (struct nilfs_dir_entry *)(kaddr + NILFS_DIR_REC_LEN(1));
        de->name_len = 2;
 -      de->rec_len = cpu_to_le16(chunk_size - NILFS_DIR_REC_LEN(1));
 +      de->rec_len = nilfs_rec_len_to_disk(chunk_size - NILFS_DIR_REC_LEN(1));
        de->inode = cpu_to_le64(parent->i_ino);
        memcpy(de->name, "..\0", 4);
        nilfs_set_de_type(de, inode);
diff --combined fs/nilfs2/nilfs.h
index 0842d775b3e09393abf21676fbfb61171baf9e14,f03279748099d9f95d8425b8bda997edeb58b052..d3d54046e5f88d371f82675ff33501f4a832522c
@@@ -32,6 -32,7 +32,6 @@@
  #include "the_nilfs.h"
  #include "sb.h"
  #include "bmap.h"
 -#include "bmap_union.h"
  
  /*
   * nilfs inode data in memory
@@@ -40,7 -41,7 +40,7 @@@ struct nilfs_inode_info 
        __u32 i_flags;
        unsigned long  i_state;         /* Dynamic state flags */
        struct nilfs_bmap *i_bmap;
 -      union nilfs_bmap_union i_bmap_union;
 +      struct nilfs_bmap i_bmap_data;
        __u64 i_xattr;  /* sector_t ??? */
        __u32 i_dir_start_lookup;
        __u64 i_cno;            /* check point number for GC inode */
@@@ -70,7 -71,9 +70,7 @@@ static inline struct nilfs_inode_info *
  static inline struct nilfs_inode_info *
  NILFS_BMAP_I(const struct nilfs_bmap *bmap)
  {
 -      return container_of((union nilfs_bmap_union *)bmap,
 -                          struct nilfs_inode_info,
 -                          i_bmap_union);
 +      return container_of(bmap, struct nilfs_inode_info, i_bmap_data);
  }
  
  static inline struct inode *NILFS_BTNC_I(struct address_space *btnc)
@@@ -103,14 -106,6 +103,14 @@@ enum 
        NILFS_I_GCDAT,                  /* shadow DAT, on memory only */
  };
  
 +/*
 + * commit flags for nilfs_commit_super and nilfs_sync_super
 + */
 +enum {
 +      NILFS_SB_COMMIT = 0,    /* Commit a super block alternately */
 +      NILFS_SB_COMMIT_ALL     /* Commit both super blocks */
 +};
 +
  /*
   * Macros to check inode numbers
   */
@@@ -250,7 -245,7 +250,7 @@@ extern void nilfs_write_inode_common(st
  extern struct inode *nilfs_iget(struct super_block *, unsigned long);
  extern void nilfs_update_inode(struct inode *, struct buffer_head *);
  extern void nilfs_truncate(struct inode *);
- extern void nilfs_delete_inode(struct inode *);
+ extern void nilfs_evict_inode(struct inode *);
  extern int nilfs_setattr(struct dentry *, struct iattr *);
  extern int nilfs_load_inode_block(struct nilfs_sb_info *, struct inode *,
                                  struct buffer_head **);
@@@ -275,14 -270,7 +275,14 @@@ extern struct nilfs_super_block 
  nilfs_read_super_block(struct super_block *, u64, int, struct buffer_head **);
  extern int nilfs_store_magic_and_option(struct super_block *,
                                        struct nilfs_super_block *, char *);
 +extern int nilfs_check_feature_compatibility(struct super_block *,
 +                                           struct nilfs_super_block *);
 +extern void nilfs_set_log_cursor(struct nilfs_super_block *,
 +                               struct the_nilfs *);
 +extern struct nilfs_super_block **nilfs_prepare_super(struct nilfs_sb_info *,
 +                                                    int flip);
  extern int nilfs_commit_super(struct nilfs_sb_info *, int);
 +extern int nilfs_cleanup_super(struct nilfs_sb_info *);
  extern int nilfs_attach_checkpoint(struct nilfs_sb_info *, __u64);
  extern void nilfs_detach_checkpoint(struct nilfs_sb_info *);
  
diff --combined fs/nilfs2/recovery.c
index 83e3d8c61a01c8244d8bb01d8f10de0ad909792a,2f11f0868d877e4898bbd3e7e0a93ec73e5926e2..d0c35ef39f6adf7bf04acfce6754739b60421d61
@@@ -91,9 -91,27 +91,9 @@@ static int nilfs_warn_segment_error(in
        return -EINVAL;
  }
  
 -static void store_segsum_info(struct nilfs_segsum_info *ssi,
 -                            struct nilfs_segment_summary *sum,
 -                            unsigned int blocksize)
 -{
 -      ssi->flags = le16_to_cpu(sum->ss_flags);
 -      ssi->seg_seq = le64_to_cpu(sum->ss_seq);
 -      ssi->ctime = le64_to_cpu(sum->ss_create);
 -      ssi->next = le64_to_cpu(sum->ss_next);
 -      ssi->nblocks = le32_to_cpu(sum->ss_nblocks);
 -      ssi->nfinfo = le32_to_cpu(sum->ss_nfinfo);
 -      ssi->sumbytes = le32_to_cpu(sum->ss_sumbytes);
 -
 -      ssi->nsumblk = DIV_ROUND_UP(ssi->sumbytes, blocksize);
 -      ssi->nfileblk = ssi->nblocks - ssi->nsumblk - !!NILFS_SEG_HAS_SR(ssi);
 -
 -      /* need to verify ->ss_bytes field if read ->ss_cno */
 -}
 -
  /**
 - * calc_crc_cont - check CRC of blocks continuously
 - * @sbi: nilfs_sb_info
 + * nilfs_compute_checksum - compute checksum of blocks continuously
 + * @nilfs: nilfs object
   * @bhs: buffer head of start block
   * @sum: place to store result
   * @offset: offset bytes in the first block
   * @start: DBN of start block
   * @nblock: number of blocks to be checked
   */
 -static int calc_crc_cont(struct nilfs_sb_info *sbi, struct buffer_head *bhs,
 -                       u32 *sum, unsigned long offset, u64 check_bytes,
 -                       sector_t start, unsigned long nblock)
 +static int nilfs_compute_checksum(struct the_nilfs *nilfs,
 +                                struct buffer_head *bhs, u32 *sum,
 +                                unsigned long offset, u64 check_bytes,
 +                                sector_t start, unsigned long nblock)
  {
 -      unsigned long blocksize = sbi->s_super->s_blocksize;
 +      unsigned int blocksize = nilfs->ns_blocksize;
        unsigned long size;
        u32 crc;
  
        BUG_ON(offset >= blocksize);
        check_bytes -= offset;
        size = min_t(u64, check_bytes, blocksize - offset);
 -      crc = crc32_le(sbi->s_nilfs->ns_crc_seed,
 +      crc = crc32_le(nilfs->ns_crc_seed,
                       (unsigned char *)bhs->b_data + offset, size);
        if (--nblock > 0) {
                do {
 -                      struct buffer_head *bh
 -                              = sb_bread(sbi->s_super, ++start);
 +                      struct buffer_head *bh;
 +
 +                      bh = __bread(nilfs->ns_bdev, ++start, blocksize);
                        if (!bh)
                                return -EIO;
                        check_bytes -= size;
  
  /**
   * nilfs_read_super_root_block - read super root block
 - * @sb: super_block
 + * @nilfs: nilfs object
   * @sr_block: disk block number of the super root block
   * @pbh: address of a buffer_head pointer to return super root buffer
   * @check: CRC check flag
   */
 -int nilfs_read_super_root_block(struct super_block *sb, sector_t sr_block,
 +int nilfs_read_super_root_block(struct the_nilfs *nilfs, sector_t sr_block,
                                struct buffer_head **pbh, int check)
  {
        struct buffer_head *bh_sr;
        int ret;
  
        *pbh = NULL;
 -      bh_sr = sb_bread(sb, sr_block);
 +      bh_sr = __bread(nilfs->ns_bdev, sr_block, nilfs->ns_blocksize);
        if (unlikely(!bh_sr)) {
                ret = NILFS_SEG_FAIL_IO;
                goto failed;
        if (check) {
                unsigned bytes = le16_to_cpu(sr->sr_bytes);
  
 -              if (bytes == 0 || bytes > sb->s_blocksize) {
 +              if (bytes == 0 || bytes > nilfs->ns_blocksize) {
                        ret = NILFS_SEG_FAIL_CHECKSUM_SUPER_ROOT;
                        goto failed_bh;
                }
 -              if (calc_crc_cont(NILFS_SB(sb), bh_sr, &crc,
 -                                sizeof(sr->sr_sum), bytes, sr_block, 1)) {
 +              if (nilfs_compute_checksum(
 +                          nilfs, bh_sr, &crc, sizeof(sr->sr_sum), bytes,
 +                          sr_block, 1)) {
                        ret = NILFS_SEG_FAIL_IO;
                        goto failed_bh;
                }
  }
  
  /**
 - * load_segment_summary - read segment summary of the specified partial segment
 - * @sbi: nilfs_sb_info
 - * @pseg_start: start disk block number of partial segment
 - * @seg_seq: sequence number requested
 - * @ssi: pointer to nilfs_segsum_info struct to store information
 + * nilfs_read_log_header - read summary header of the specified log
 + * @nilfs: nilfs object
 + * @start_blocknr: start block number of the log
 + * @sum: pointer to return segment summary structure
   */
 -static int
 -load_segment_summary(struct nilfs_sb_info *sbi, sector_t pseg_start,
 -                   u64 seg_seq, struct nilfs_segsum_info *ssi)
 +static struct buffer_head *
 +nilfs_read_log_header(struct the_nilfs *nilfs, sector_t start_blocknr,
 +                    struct nilfs_segment_summary **sum)
  {
        struct buffer_head *bh_sum;
 -      struct nilfs_segment_summary *sum;
 +
 +      bh_sum = __bread(nilfs->ns_bdev, start_blocknr, nilfs->ns_blocksize);
 +      if (bh_sum)
 +              *sum = (struct nilfs_segment_summary *)bh_sum->b_data;
 +      return bh_sum;
 +}
 +
 +/**
 + * nilfs_validate_log - verify consistency of log
 + * @nilfs: nilfs object
 + * @seg_seq: sequence number of segment
 + * @bh_sum: buffer head of summary block
 + * @sum: segment summary struct
 + */
 +static int nilfs_validate_log(struct the_nilfs *nilfs, u64 seg_seq,
 +                            struct buffer_head *bh_sum,
 +                            struct nilfs_segment_summary *sum)
 +{
        unsigned long nblock;
        u32 crc;
 -      int ret = NILFS_SEG_FAIL_IO;
 +      int ret;
  
 -      bh_sum = sb_bread(sbi->s_super, pseg_start);
 -      if (!bh_sum)
 +      ret = NILFS_SEG_FAIL_MAGIC;
 +      if (le32_to_cpu(sum->ss_magic) != NILFS_SEGSUM_MAGIC)
                goto out;
  
 -      sum = (struct nilfs_segment_summary *)bh_sum->b_data;
 -
 -      /* Check consistency of segment summary */
 -      if (le32_to_cpu(sum->ss_magic) != NILFS_SEGSUM_MAGIC) {
 -              ret = NILFS_SEG_FAIL_MAGIC;
 -              goto failed;
 -      }
 -      store_segsum_info(ssi, sum, sbi->s_super->s_blocksize);
 -      if (seg_seq != ssi->seg_seq) {
 -              ret = NILFS_SEG_FAIL_SEQ;
 -              goto failed;
 -      }
 +      ret = NILFS_SEG_FAIL_SEQ;
 +      if (le64_to_cpu(sum->ss_seq) != seg_seq)
 +              goto out;
  
 -      nblock = ssi->nblocks;
 -      if (unlikely(nblock == 0 ||
 -                   nblock > sbi->s_nilfs->ns_blocks_per_segment)) {
 +      nblock = le32_to_cpu(sum->ss_nblocks);
 +      ret = NILFS_SEG_FAIL_CONSISTENCY;
 +      if (unlikely(nblock == 0 || nblock > nilfs->ns_blocks_per_segment))
                /* This limits the number of blocks read in the CRC check */
 -              ret = NILFS_SEG_FAIL_CONSISTENCY;
 -              goto failed;
 -      }
 -      if (calc_crc_cont(sbi, bh_sum, &crc, sizeof(sum->ss_datasum),
 -                        ((u64)nblock << sbi->s_super->s_blocksize_bits),
 -                        pseg_start, nblock)) {
 -              ret = NILFS_SEG_FAIL_IO;
 -              goto failed;
 -      }
 -      if (crc == le32_to_cpu(sum->ss_datasum))
 -              ret = 0;
 -      else
 -              ret = NILFS_SEG_FAIL_CHECKSUM_FULL;
 - failed:
 -      brelse(bh_sum);
 - out:
 +              goto out;
 +
 +      ret = NILFS_SEG_FAIL_IO;
 +      if (nilfs_compute_checksum(nilfs, bh_sum, &crc, sizeof(sum->ss_datasum),
 +                                 ((u64)nblock << nilfs->ns_blocksize_bits),
 +                                 bh_sum->b_blocknr, nblock))
 +              goto out;
 +
 +      ret = NILFS_SEG_FAIL_CHECKSUM_FULL;
 +      if (crc != le32_to_cpu(sum->ss_datasum))
 +              goto out;
 +      ret = 0;
 +out:
        return ret;
  }
  
 -static void *segsum_get(struct super_block *sb, struct buffer_head **pbh,
 -                      unsigned int *offset, unsigned int bytes)
 +/**
 + * nilfs_read_summary_info - read an item on summary blocks of a log
 + * @nilfs: nilfs object
 + * @pbh: the current buffer head on summary blocks [in, out]
 + * @offset: the current byte offset on summary blocks [in, out]
 + * @bytes: byte size of the item to be read
 + */
 +static void *nilfs_read_summary_info(struct the_nilfs *nilfs,
 +                                   struct buffer_head **pbh,
 +                                   unsigned int *offset, unsigned int bytes)
  {
        void *ptr;
        sector_t blocknr;
        if (bytes > (*pbh)->b_size - *offset) {
                blocknr = (*pbh)->b_blocknr;
                brelse(*pbh);
 -              *pbh = sb_bread(sb, blocknr + 1);
 +              *pbh = __bread(nilfs->ns_bdev, blocknr + 1,
 +                             nilfs->ns_blocksize);
                if (unlikely(!*pbh))
                        return NULL;
                *offset = 0;
        return ptr;
  }
  
 -static void segsum_skip(struct super_block *sb, struct buffer_head **pbh,
 -                      unsigned int *offset, unsigned int bytes,
 -                      unsigned long count)
 +/**
 + * nilfs_skip_summary_info - skip items on summary blocks of a log
 + * @nilfs: nilfs object
 + * @pbh: the current buffer head on summary blocks [in, out]
 + * @offset: the current byte offset on summary blocks [in, out]
 + * @bytes: byte size of the item to be skipped
 + * @count: number of items to be skipped
 + */
 +static void nilfs_skip_summary_info(struct the_nilfs *nilfs,
 +                                  struct buffer_head **pbh,
 +                                  unsigned int *offset, unsigned int bytes,
 +                                  unsigned long count)
  {
        unsigned int rest_item_in_current_block
                = ((*pbh)->b_size - *offset) / bytes;
                *offset = bytes * (count - (bcnt - 1) * nitem_per_block);
  
                brelse(*pbh);
 -              *pbh = sb_bread(sb, blocknr + bcnt);
 +              *pbh = __bread(nilfs->ns_bdev, blocknr + bcnt,
 +                             nilfs->ns_blocksize);
        }
  }
  
 -static int
 -collect_blocks_from_segsum(struct nilfs_sb_info *sbi, sector_t sum_blocknr,
 -                         struct nilfs_segsum_info *ssi,
 -                         struct list_head *head)
 +/**
 + * nilfs_scan_dsync_log - get block information of a log written for data sync
 + * @nilfs: nilfs object
 + * @start_blocknr: start block number of the log
 + * @sum: log summary information
 + * @head: list head to add nilfs_recovery_block struct
 + */
 +static int nilfs_scan_dsync_log(struct the_nilfs *nilfs, sector_t start_blocknr,
 +                              struct nilfs_segment_summary *sum,
 +                              struct list_head *head)
  {
        struct buffer_head *bh;
        unsigned int offset;
 -      unsigned long nfinfo = ssi->nfinfo;
 -      sector_t blocknr = sum_blocknr + ssi->nsumblk;
 +      u32 nfinfo, sumbytes;
 +      sector_t blocknr;
        ino_t ino;
        int err = -EIO;
  
 +      nfinfo = le32_to_cpu(sum->ss_nfinfo);
        if (!nfinfo)
                return 0;
  
 -      bh = sb_bread(sbi->s_super, sum_blocknr);
 +      sumbytes = le32_to_cpu(sum->ss_sumbytes);
 +      blocknr = start_blocknr + DIV_ROUND_UP(sumbytes, nilfs->ns_blocksize);
 +      bh = __bread(nilfs->ns_bdev, start_blocknr, nilfs->ns_blocksize);
        if (unlikely(!bh))
                goto out;
  
 -      offset = le16_to_cpu(
 -              ((struct nilfs_segment_summary *)bh->b_data)->ss_bytes);
 +      offset = le16_to_cpu(sum->ss_bytes);
        for (;;) {
                unsigned long nblocks, ndatablk, nnodeblk;
                struct nilfs_finfo *finfo;
  
 -              finfo = segsum_get(sbi->s_super, &bh, &offset, sizeof(*finfo));
 +              finfo = nilfs_read_summary_info(nilfs, &bh, &offset,
 +                                              sizeof(*finfo));
                if (unlikely(!finfo))
                        goto out;
  
                        struct nilfs_recovery_block *rb;
                        struct nilfs_binfo_v *binfo;
  
 -                      binfo = segsum_get(sbi->s_super, &bh, &offset,
 -                                         sizeof(*binfo));
 +                      binfo = nilfs_read_summary_info(nilfs, &bh, &offset,
 +                                                      sizeof(*binfo));
                        if (unlikely(!binfo))
                                goto out;
  
                }
                if (--nfinfo == 0)
                        break;
 -              blocknr += nnodeblk; /* always 0 for the data sync segments */
 -              segsum_skip(sbi->s_super, &bh, &offset, sizeof(__le64),
 -                          nnodeblk);
 +              blocknr += nnodeblk; /* always 0 for data sync logs */
 +              nilfs_skip_summary_info(nilfs, &bh, &offset, sizeof(__le64),
 +                                      nnodeblk);
                if (unlikely(!bh))
                        goto out;
        }
@@@ -484,14 -467,14 +484,14 @@@ static int nilfs_prepare_segment_for_re
        return err;
  }
  
 -static int nilfs_recovery_copy_block(struct nilfs_sb_info *sbi,
 +static int nilfs_recovery_copy_block(struct the_nilfs *nilfs,
                                     struct nilfs_recovery_block *rb,
                                     struct page *page)
  {
        struct buffer_head *bh_org;
        void *kaddr;
  
 -      bh_org = sb_bread(sbi->s_super, rb->blocknr);
 +      bh_org = __bread(nilfs->ns_bdev, rb->blocknr, nilfs->ns_blocksize);
        if (unlikely(!bh_org))
                return -EIO;
  
        return 0;
  }
  
 -static int recover_dsync_blocks(struct nilfs_sb_info *sbi,
 -                              struct list_head *head,
 -                              unsigned long *nr_salvaged_blocks)
 +static int nilfs_recover_dsync_blocks(struct the_nilfs *nilfs,
 +                                    struct nilfs_sb_info *sbi,
 +                                    struct list_head *head,
 +                                    unsigned long *nr_salvaged_blocks)
  {
        struct inode *inode;
        struct nilfs_recovery_block *rb, *n;
 -      unsigned blocksize = sbi->s_super->s_blocksize;
 +      unsigned blocksize = nilfs->ns_blocksize;
        struct page *page;
        loff_t pos;
        int err = 0, err2 = 0;
                }
  
                pos = rb->blkoff << inode->i_blkbits;
-               page = NULL;
-               err = block_write_begin(NULL, inode->i_mapping, pos, blocksize,
-                                       0, &page, NULL, nilfs_get_block);
-               if (unlikely(err))
+               err = block_write_begin(inode->i_mapping, pos, blocksize,
+                                       0, &page, nilfs_get_block);
+               if (unlikely(err)) {
+                       loff_t isize = inode->i_size;
+                       if (pos + blocksize > isize)
+                               vmtruncate(inode, isize);
                        goto failed_inode;
+               }
  
 -              err = nilfs_recovery_copy_block(sbi, rb, page);
 +              err = nilfs_recovery_copy_block(nilfs, rb, page);
                if (unlikely(err))
                        goto failed_page;
  
  /**
   * nilfs_do_roll_forward - salvage logical segments newer than the latest
   * checkpoint
 + * @nilfs: nilfs object
   * @sbi: nilfs_sb_info
 - * @nilfs: the_nilfs
   * @ri: pointer to a nilfs_recovery_info
   */
  static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
                                 struct nilfs_sb_info *sbi,
                                 struct nilfs_recovery_info *ri)
  {
 -      struct nilfs_segsum_info ssi;
 +      struct buffer_head *bh_sum = NULL;
 +      struct nilfs_segment_summary *sum;
        sector_t pseg_start;
        sector_t seg_start, seg_end;  /* Starting/ending DBN of full segment */
        unsigned long nsalvaged_blocks = 0;
 +      unsigned int flags;
        u64 seg_seq;
        __u64 segnum, nextnum = 0;
        int empty_seg = 0;
        nilfs_get_segment_range(nilfs, segnum, &seg_start, &seg_end);
  
        while (segnum != ri->ri_segnum || pseg_start <= ri->ri_pseg_start) {
 +              brelse(bh_sum);
 +              bh_sum = nilfs_read_log_header(nilfs, pseg_start, &sum);
 +              if (!bh_sum) {
 +                      err = -EIO;
 +                      goto failed;
 +              }
  
 -              ret = load_segment_summary(sbi, pseg_start, seg_seq, &ssi);
 +              ret = nilfs_validate_log(nilfs, seg_seq, bh_sum, sum);
                if (ret) {
                        if (ret == NILFS_SEG_FAIL_IO) {
                                err = -EIO;
                        }
                        goto strayed;
                }
 -              if (unlikely(NILFS_SEG_HAS_SR(&ssi)))
 +
 +              flags = le16_to_cpu(sum->ss_flags);
 +              if (flags & NILFS_SS_SR)
                        goto confused;
  
                /* Found a valid partial segment; do recovery actions */
 -              nextnum = nilfs_get_segnum_of_block(nilfs, ssi.next);
 +              nextnum = nilfs_get_segnum_of_block(nilfs,
 +                                                  le64_to_cpu(sum->ss_next));
                empty_seg = 0;
 -              nilfs->ns_ctime = ssi.ctime;
 -              if (!(ssi.flags & NILFS_SS_GC))
 -                      nilfs->ns_nongc_ctime = ssi.ctime;
 +              nilfs->ns_ctime = le64_to_cpu(sum->ss_create);
 +              if (!(flags & NILFS_SS_GC))
 +                      nilfs->ns_nongc_ctime = nilfs->ns_ctime;
  
                switch (state) {
                case RF_INIT_ST:
 -                      if (!NILFS_SEG_LOGBGN(&ssi) || !NILFS_SEG_DSYNC(&ssi))
 +                      if (!(flags & NILFS_SS_LOGBGN) ||
 +                          !(flags & NILFS_SS_SYNDT))
                                goto try_next_pseg;
                        state = RF_DSYNC_ST;
                        /* Fall through */
                case RF_DSYNC_ST:
 -                      if (!NILFS_SEG_DSYNC(&ssi))
 +                      if (!(flags & NILFS_SS_SYNDT))
                                goto confused;
  
 -                      err = collect_blocks_from_segsum(
 -                              sbi, pseg_start, &ssi, &dsync_blocks);
 +                      err = nilfs_scan_dsync_log(nilfs, pseg_start, sum,
 +                                                 &dsync_blocks);
                        if (unlikely(err))
                                goto failed;
 -                      if (NILFS_SEG_LOGEND(&ssi)) {
 -                              err = recover_dsync_blocks(
 -                                      sbi, &dsync_blocks, &nsalvaged_blocks);
 +                      if (flags & NILFS_SS_LOGEND) {
 +                              err = nilfs_recover_dsync_blocks(
 +                                      nilfs, sbi, &dsync_blocks,
 +                                      &nsalvaged_blocks);
                                if (unlikely(err))
                                        goto failed;
                                state = RF_INIT_ST;
   try_next_pseg:
                if (pseg_start == ri->ri_lsegs_end)
                        break;
 -              pseg_start += ssi.nblocks;
 +              pseg_start += le32_to_cpu(sum->ss_nblocks);
                if (pseg_start < seg_end)
                        continue;
                goto feed_segment;
                ri->ri_need_recovery = NILFS_RECOVERY_ROLLFORWARD_DONE;
        }
   out:
 +      brelse(bh_sum);
        dispose_recovery_list(&dsync_blocks);
 -      nilfs_detach_writer(sbi->s_nilfs, sbi);
 +      nilfs_detach_writer(nilfs, sbi);
        return err;
  
   confused:
  }
  
  static void nilfs_finish_roll_forward(struct the_nilfs *nilfs,
 -                                    struct nilfs_sb_info *sbi,
                                      struct nilfs_recovery_info *ri)
  {
        struct buffer_head *bh;
            nilfs_get_segnum_of_block(nilfs, ri->ri_super_root))
                return;
  
 -      bh = sb_getblk(sbi->s_super, ri->ri_lsegs_start);
 +      bh = __getblk(nilfs->ns_bdev, ri->ri_lsegs_start, nilfs->ns_blocksize);
        BUG_ON(!bh);
        memset(bh->b_data, 0, bh->b_size);
        set_buffer_dirty(bh);
  }
  
  /**
 - * nilfs_recover_logical_segments - salvage logical segments written after
 - * the latest super root
 - * @nilfs: the_nilfs
 + * nilfs_salvage_orphan_logs - salvage logs written after the latest checkpoint
 + * @nilfs: nilfs object
   * @sbi: nilfs_sb_info
   * @ri: pointer to a nilfs_recovery_info struct to store search results.
   *
   *
   * %-ENOMEM - Insufficient memory available.
   */
 -int nilfs_recover_logical_segments(struct the_nilfs *nilfs,
 -                                 struct nilfs_sb_info *sbi,
 -                                 struct nilfs_recovery_info *ri)
 +int nilfs_salvage_orphan_logs(struct the_nilfs *nilfs,
 +                            struct nilfs_sb_info *sbi,
 +                            struct nilfs_recovery_info *ri)
  {
        int err;
  
                        goto failed;
                }
  
 -              nilfs_finish_roll_forward(nilfs, sbi, ri);
 +              nilfs_finish_roll_forward(nilfs, ri);
        }
  
   failed:
  /**
   * nilfs_search_super_root - search the latest valid super root
   * @nilfs: the_nilfs
 - * @sbi: nilfs_sb_info
   * @ri: pointer to a nilfs_recovery_info struct to store search results.
   *
   * nilfs_search_super_root() looks for the latest super-root from a partial
   * %-EINVAL - No valid segment found
   *
   * %-EIO - I/O error
 + *
 + * %-ENOMEM - Insufficient memory available.
   */
 -int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
 +int nilfs_search_super_root(struct the_nilfs *nilfs,
                            struct nilfs_recovery_info *ri)
  {
 -      struct nilfs_segsum_info ssi;
 +      struct buffer_head *bh_sum = NULL;
 +      struct nilfs_segment_summary *sum;
        sector_t pseg_start, pseg_end, sr_pseg_start = 0;
        sector_t seg_start, seg_end; /* range of full segment (block number) */
        sector_t b, end;
 +      unsigned long nblocks;
 +      unsigned int flags;
        u64 seg_seq;
        __u64 segnum, nextnum = 0;
        __u64 cno;
        /* Read ahead segment */
        b = seg_start;
        while (b <= seg_end)
 -              sb_breadahead(sbi->s_super, b++);
 +              __breadahead(nilfs->ns_bdev, b++, nilfs->ns_blocksize);
  
        for (;;) {
 -              /* Load segment summary */
 -              ret = load_segment_summary(sbi, pseg_start, seg_seq, &ssi);
 +              brelse(bh_sum);
 +              ret = NILFS_SEG_FAIL_IO;
 +              bh_sum = nilfs_read_log_header(nilfs, pseg_start, &sum);
 +              if (!bh_sum)
 +                      goto failed;
 +
 +              ret = nilfs_validate_log(nilfs, seg_seq, bh_sum, sum);
                if (ret) {
                        if (ret == NILFS_SEG_FAIL_IO)
                                goto failed;
                        goto strayed;
                }
 -              pseg_end = pseg_start + ssi.nblocks - 1;
 +
 +              nblocks = le32_to_cpu(sum->ss_nblocks);
 +              pseg_end = pseg_start + nblocks - 1;
                if (unlikely(pseg_end > seg_end)) {
                        ret = NILFS_SEG_FAIL_CONSISTENCY;
                        goto strayed;
                ri->ri_pseg_start = pseg_start;
                ri->ri_seq = seg_seq;
                ri->ri_segnum = segnum;
 -              nextnum = nilfs_get_segnum_of_block(nilfs, ssi.next);
 +              nextnum = nilfs_get_segnum_of_block(nilfs,
 +                                                  le64_to_cpu(sum->ss_next));
                ri->ri_nextnum = nextnum;
                empty_seg = 0;
  
 -              if (!NILFS_SEG_HAS_SR(&ssi) && !scan_newer) {
 +              flags = le16_to_cpu(sum->ss_flags);
 +              if (!(flags & NILFS_SS_SR) && !scan_newer) {
                        /* This will never happen because a superblock
                           (last_segment) always points to a pseg
                           having a super root. */
                if (pseg_start == seg_start) {
                        nilfs_get_segment_range(nilfs, nextnum, &b, &end);
                        while (b <= end)
 -                              sb_breadahead(sbi->s_super, b++);
 +                              __breadahead(nilfs->ns_bdev, b++,
 +                                           nilfs->ns_blocksize);
                }
 -              if (!NILFS_SEG_HAS_SR(&ssi)) {
 -                      if (!ri->ri_lsegs_start && NILFS_SEG_LOGBGN(&ssi)) {
 +              if (!(flags & NILFS_SS_SR)) {
 +                      if (!ri->ri_lsegs_start && (flags & NILFS_SS_LOGBGN)) {
                                ri->ri_lsegs_start = pseg_start;
                                ri->ri_lsegs_start_seq = seg_seq;
                        }
 -                      if (NILFS_SEG_LOGEND(&ssi))
 +                      if (flags & NILFS_SS_LOGEND)
                                ri->ri_lsegs_end = pseg_start;
                        goto try_next_pseg;
                }
                ri->ri_lsegs_start = ri->ri_lsegs_end = 0;
  
                nilfs_dispose_segment_list(&segments);
 -              nilfs->ns_pseg_offset = (sr_pseg_start = pseg_start)
 -                      + ssi.nblocks - seg_start;
 +              sr_pseg_start = pseg_start;
 +              nilfs->ns_pseg_offset = pseg_start + nblocks - seg_start;
                nilfs->ns_seg_seq = seg_seq;
                nilfs->ns_segnum = segnum;
                nilfs->ns_cno = cno;  /* nilfs->ns_cno = ri->ri_cno + 1 */
 -              nilfs->ns_ctime = ssi.ctime;
 +              nilfs->ns_ctime = le64_to_cpu(sum->ss_create);
                nilfs->ns_nextnum = nextnum;
  
                if (scan_newer)
                        scan_newer = 1;
                }
  
 -              /* reset region for roll-forward */
 -              pseg_start += ssi.nblocks;
 -              if (pseg_start < seg_end)
 -                      continue;
 -              goto feed_segment;
 -
   try_next_pseg:
                /* Standing on a course, or met an inconsistent state */
 -              pseg_start += ssi.nblocks;
 +              pseg_start += nblocks;
                if (pseg_start < seg_end)
                        continue;
                goto feed_segment;
  
   super_root_found:
        /* Updating pointers relating to the latest checkpoint */
 +      brelse(bh_sum);
        list_splice_tail(&segments, &ri->ri_used_segments);
        nilfs->ns_last_pseg = sr_pseg_start;
        nilfs->ns_last_seq = nilfs->ns_seg_seq;
        return 0;
  
   failed:
 +      brelse(bh_sum);
        nilfs_dispose_segment_list(&segments);
        return (ret < 0) ? ret : nilfs_warn_segment_error(ret);
  }
diff --combined fs/nilfs2/super.c
index 26078b3407c9a15e8a473e80536e25bcb6baefe0,7c7572a4e13883ffae05711026e0be02e4b855b4..1fa86b9df73b4c885190b6b3bbf95291b7630d4e
@@@ -55,8 -55,6 +55,8 @@@
  #include "nilfs.h"
  #include "mdt.h"
  #include "alloc.h"
 +#include "btree.h"
 +#include "btnode.h"
  #include "page.h"
  #include "cpfile.h"
  #include "ifile.h"
@@@ -76,25 -74,6 +76,25 @@@ struct kmem_cache *nilfs_btree_path_cac
  
  static int nilfs_remount(struct super_block *sb, int *flags, char *data);
  
 +static void nilfs_set_error(struct nilfs_sb_info *sbi)
 +{
 +      struct the_nilfs *nilfs = sbi->s_nilfs;
 +      struct nilfs_super_block **sbp;
 +
 +      down_write(&nilfs->ns_sem);
 +      if (!(nilfs->ns_mount_state & NILFS_ERROR_FS)) {
 +              nilfs->ns_mount_state |= NILFS_ERROR_FS;
 +              sbp = nilfs_prepare_super(sbi, 0);
 +              if (likely(sbp)) {
 +                      sbp[0]->s_state |= cpu_to_le16(NILFS_ERROR_FS);
 +                      if (sbp[1])
 +                              sbp[1]->s_state |= cpu_to_le16(NILFS_ERROR_FS);
 +                      nilfs_commit_super(sbi, NILFS_SB_COMMIT_ALL);
 +              }
 +      }
 +      up_write(&nilfs->ns_sem);
 +}
 +
  /**
   * nilfs_error() - report failure condition on a filesystem
   *
@@@ -120,7 -99,16 +120,7 @@@ void nilfs_error(struct super_block *sb
        va_end(args);
  
        if (!(sb->s_flags & MS_RDONLY)) {
 -              struct the_nilfs *nilfs = sbi->s_nilfs;
 -
 -              down_write(&nilfs->ns_sem);
 -              if (!(nilfs->ns_mount_state & NILFS_ERROR_FS)) {
 -                      nilfs->ns_mount_state |= NILFS_ERROR_FS;
 -                      nilfs->ns_sbp[0]->s_state |=
 -                              cpu_to_le16(NILFS_ERROR_FS);
 -                      nilfs_commit_super(sbi, 1);
 -              }
 -              up_write(&nilfs->ns_sem);
 +              nilfs_set_error(sbi);
  
                if (nilfs_test_opt(sbi, ERRORS_RO)) {
                        printk(KERN_CRIT "Remounting filesystem read-only\n");
@@@ -171,24 -159,7 +171,7 @@@ void nilfs_destroy_inode(struct inode *
        kmem_cache_free(nilfs_inode_cachep, NILFS_I(inode));
  }
  
- static void nilfs_clear_inode(struct inode *inode)
- {
-       struct nilfs_inode_info *ii = NILFS_I(inode);
-       /*
-        * Free resources allocated in nilfs_read_inode(), here.
-        */
-       BUG_ON(!list_empty(&ii->i_dirty));
-       brelse(ii->i_bh);
-       ii->i_bh = NULL;
-       if (test_bit(NILFS_I_BMAP, &ii->i_state))
-               nilfs_bmap_clear(ii->i_bmap);
-       nilfs_btnode_cache_clear(&ii->i_btnode_cache);
- }
 -static int nilfs_sync_super(struct nilfs_sb_info *sbi, int dupsb)
 +static int nilfs_sync_super(struct nilfs_sb_info *sbi, int flag)
  {
        struct the_nilfs *nilfs = sbi->s_nilfs;
        int err;
                printk(KERN_ERR
                       "NILFS: unable to write superblock (err=%d)\n", err);
                if (err == -EIO && nilfs->ns_sbh[1]) {
 +                      /*
 +                       * sbp[0] points to newer log than sbp[1],
 +                       * so copy sbp[0] to sbp[1] to take over sbp[0].
 +                       */
 +                      memcpy(nilfs->ns_sbp[1], nilfs->ns_sbp[0],
 +                             nilfs->ns_sbsize);
                        nilfs_fall_back_super_block(nilfs);
                        goto retry;
                }
        } else {
                struct nilfs_super_block *sbp = nilfs->ns_sbp[0];
  
 +              nilfs->ns_sbwcount++;
 +
                /*
                 * The latest segment becomes trailable from the position
                 * written in superblock.
  
                /* update GC protection for recent segments */
                if (nilfs->ns_sbh[1]) {
 -                      sbp = NULL;
 -                      if (dupsb) {
 +                      if (flag == NILFS_SB_COMMIT_ALL) {
                                set_buffer_dirty(nilfs->ns_sbh[1]);
 -                              if (!sync_dirty_buffer(nilfs->ns_sbh[1]))
 -                                      sbp = nilfs->ns_sbp[1];
 +                              if (sync_dirty_buffer(nilfs->ns_sbh[1]) < 0)
 +                                      goto out;
                        }
 +                      if (le64_to_cpu(nilfs->ns_sbp[1]->s_last_cno) <
 +                          le64_to_cpu(nilfs->ns_sbp[0]->s_last_cno))
 +                              sbp = nilfs->ns_sbp[1];
                }
 -              if (sbp) {
 -                      spin_lock(&nilfs->ns_last_segment_lock);
 -                      nilfs->ns_prot_seq = le64_to_cpu(sbp->s_last_seq);
 -                      spin_unlock(&nilfs->ns_last_segment_lock);
 -              }
 -      }
  
 +              spin_lock(&nilfs->ns_last_segment_lock);
 +              nilfs->ns_prot_seq = le64_to_cpu(sbp->s_last_seq);
 +              spin_unlock(&nilfs->ns_last_segment_lock);
 +      }
 + out:
        return err;
  }
  
 -int nilfs_commit_super(struct nilfs_sb_info *sbi, int dupsb)
 +void nilfs_set_log_cursor(struct nilfs_super_block *sbp,
 +                        struct the_nilfs *nilfs)
 +{
 +      sector_t nfreeblocks;
 +
 +      /* nilfs->ns_sem must be locked by the caller. */
 +      nilfs_count_free_blocks(nilfs, &nfreeblocks);
 +      sbp->s_free_blocks_count = cpu_to_le64(nfreeblocks);
 +
 +      spin_lock(&nilfs->ns_last_segment_lock);
 +      sbp->s_last_seq = cpu_to_le64(nilfs->ns_last_seq);
 +      sbp->s_last_pseg = cpu_to_le64(nilfs->ns_last_pseg);
 +      sbp->s_last_cno = cpu_to_le64(nilfs->ns_last_cno);
 +      spin_unlock(&nilfs->ns_last_segment_lock);
 +}
 +
 +struct nilfs_super_block **nilfs_prepare_super(struct nilfs_sb_info *sbi,
 +                                             int flip)
  {
        struct the_nilfs *nilfs = sbi->s_nilfs;
        struct nilfs_super_block **sbp = nilfs->ns_sbp;
 -      sector_t nfreeblocks;
 -      time_t t;
 -      int err;
  
 -      /* nilfs->sem must be locked by the caller. */
 +      /* nilfs->ns_sem must be locked by the caller. */
        if (sbp[0]->s_magic != cpu_to_le16(NILFS_SUPER_MAGIC)) {
 -              if (sbp[1] && sbp[1]->s_magic == cpu_to_le16(NILFS_SUPER_MAGIC))
 -                      nilfs_swap_super_block(nilfs);
 -              else {
 +              if (sbp[1] &&
 +                  sbp[1]->s_magic == cpu_to_le16(NILFS_SUPER_MAGIC)) {
 +                      memcpy(sbp[0], sbp[1], nilfs->ns_sbsize);
 +              } else {
                        printk(KERN_CRIT "NILFS: superblock broke on dev %s\n",
                               sbi->s_super->s_id);
 -                      return -EIO;
 +                      return NULL;
                }
 +      } else if (sbp[1] &&
 +                 sbp[1]->s_magic != cpu_to_le16(NILFS_SUPER_MAGIC)) {
 +                      memcpy(sbp[1], sbp[0], nilfs->ns_sbsize);
        }
 -      err = nilfs_count_free_blocks(nilfs, &nfreeblocks);
 -      if (unlikely(err)) {
 -              printk(KERN_ERR "NILFS: failed to count free blocks\n");
 -              return err;
 -      }
 -      spin_lock(&nilfs->ns_last_segment_lock);
 -      sbp[0]->s_last_seq = cpu_to_le64(nilfs->ns_last_seq);
 -      sbp[0]->s_last_pseg = cpu_to_le64(nilfs->ns_last_pseg);
 -      sbp[0]->s_last_cno = cpu_to_le64(nilfs->ns_last_cno);
 -      spin_unlock(&nilfs->ns_last_segment_lock);
  
 +      if (flip && sbp[1])
 +              nilfs_swap_super_block(nilfs);
 +
 +      return sbp;
 +}
 +
 +int nilfs_commit_super(struct nilfs_sb_info *sbi, int flag)
 +{
 +      struct the_nilfs *nilfs = sbi->s_nilfs;
 +      struct nilfs_super_block **sbp = nilfs->ns_sbp;
 +      time_t t;
 +
 +      /* nilfs->ns_sem must be locked by the caller. */
        t = get_seconds();
 -      nilfs->ns_sbwtime[0] = t;
 -      sbp[0]->s_free_blocks_count = cpu_to_le64(nfreeblocks);
 +      nilfs->ns_sbwtime = t;
        sbp[0]->s_wtime = cpu_to_le64(t);
        sbp[0]->s_sum = 0;
        sbp[0]->s_sum = cpu_to_le32(crc32_le(nilfs->ns_crc_seed,
                                             (unsigned char *)sbp[0],
                                             nilfs->ns_sbsize));
 -      if (dupsb && sbp[1]) {
 -              memcpy(sbp[1], sbp[0], nilfs->ns_sbsize);
 -              nilfs->ns_sbwtime[1] = t;
 +      if (flag == NILFS_SB_COMMIT_ALL && sbp[1]) {
 +              sbp[1]->s_wtime = sbp[0]->s_wtime;
 +              sbp[1]->s_sum = 0;
 +              sbp[1]->s_sum = cpu_to_le32(crc32_le(nilfs->ns_crc_seed,
 +                                          (unsigned char *)sbp[1],
 +                                          nilfs->ns_sbsize));
        }
        clear_nilfs_sb_dirty(nilfs);
 -      return nilfs_sync_super(sbi, dupsb);
 +      return nilfs_sync_super(sbi, flag);
 +}
 +
 +/**
 + * nilfs_cleanup_super() - write filesystem state for cleanup
 + * @sbi: nilfs_sb_info to be unmounted or degraded to read-only
 + *
 + * This function restores state flags in the on-disk super block.
 + * This will set "clean" flag (i.e. NILFS_VALID_FS) unless the
 + * filesystem was not clean previously.
 + */
 +int nilfs_cleanup_super(struct nilfs_sb_info *sbi)
 +{
 +      struct nilfs_super_block **sbp;
 +      int flag = NILFS_SB_COMMIT;
 +      int ret = -EIO;
 +
 +      sbp = nilfs_prepare_super(sbi, 0);
 +      if (sbp) {
 +              sbp[0]->s_state = cpu_to_le16(sbi->s_nilfs->ns_mount_state);
 +              nilfs_set_log_cursor(sbp[0], sbi->s_nilfs);
 +              if (sbp[1] && sbp[0]->s_last_cno == sbp[1]->s_last_cno) {
 +                      /*
 +                       * make the "clean" flag also to the opposite
 +                       * super block if both super blocks point to
 +                       * the same checkpoint.
 +                       */
 +                      sbp[1]->s_state = sbp[0]->s_state;
 +                      flag = NILFS_SB_COMMIT_ALL;
 +              }
 +              ret = nilfs_commit_super(sbi, flag);
 +      }
 +      return ret;
  }
  
  static void nilfs_put_super(struct super_block *sb)
  
        if (!(sb->s_flags & MS_RDONLY)) {
                down_write(&nilfs->ns_sem);
 -              nilfs->ns_sbp[0]->s_state = cpu_to_le16(nilfs->ns_mount_state);
 -              nilfs_commit_super(sbi, 1);
 +              nilfs_cleanup_super(sbi);
                up_write(&nilfs->ns_sem);
        }
        down_write(&nilfs->ns_super_sem);
@@@ -386,7 -294,6 +369,7 @@@ static int nilfs_sync_fs(struct super_b
  {
        struct nilfs_sb_info *sbi = NILFS_SB(sb);
        struct the_nilfs *nilfs = sbi->s_nilfs;
 +      struct nilfs_super_block **sbp;
        int err = 0;
  
        /* This function is called when super block should be written back */
                err = nilfs_construct_segment(sb);
  
        down_write(&nilfs->ns_sem);
 -      if (nilfs_sb_dirty(nilfs))
 -              nilfs_commit_super(sbi, 1);
 +      if (nilfs_sb_dirty(nilfs)) {
 +              sbp = nilfs_prepare_super(sbi, nilfs_sb_will_flip(nilfs));
 +              if (likely(sbp)) {
 +                      nilfs_set_log_cursor(sbp[0], nilfs);
 +                      nilfs_commit_super(sbi, NILFS_SB_COMMIT);
 +              }
 +      }
        up_write(&nilfs->ns_sem);
  
        return err;
@@@ -523,20 -425,20 +506,20 @@@ static int nilfs_show_options(struct se
        struct nilfs_sb_info *sbi = NILFS_SB(sb);
  
        if (!nilfs_test_opt(sbi, BARRIER))
 -              seq_printf(seq, ",nobarrier");
 +              seq_puts(seq, ",nobarrier");
        if (nilfs_test_opt(sbi, SNAPSHOT))
                seq_printf(seq, ",cp=%llu",
                           (unsigned long long int)sbi->s_snapshot_cno);
        if (nilfs_test_opt(sbi, ERRORS_PANIC))
 -              seq_printf(seq, ",errors=panic");
 +              seq_puts(seq, ",errors=panic");
        if (nilfs_test_opt(sbi, ERRORS_CONT))
 -              seq_printf(seq, ",errors=continue");
 +              seq_puts(seq, ",errors=continue");
        if (nilfs_test_opt(sbi, STRICT_ORDER))
 -              seq_printf(seq, ",order=strict");
 +              seq_puts(seq, ",order=strict");
        if (nilfs_test_opt(sbi, NORECOVERY))
 -              seq_printf(seq, ",norecovery");
 +              seq_puts(seq, ",norecovery");
        if (nilfs_test_opt(sbi, DISCARD))
 -              seq_printf(seq, ",discard");
 +              seq_puts(seq, ",discard");
  
        return 0;
  }
@@@ -548,7 -450,7 +531,7 @@@ static const struct super_operations ni
        /* .write_inode    = nilfs_write_inode, */
        /* .put_inode      = nilfs_put_inode, */
        /* .drop_inode    = nilfs_drop_inode, */
-       .delete_inode   = nilfs_delete_inode,
+       .evict_inode    = nilfs_evict_inode,
        .put_super      = nilfs_put_super,
        /* .write_super    = nilfs_write_super, */
        .sync_fs        = nilfs_sync_fs,
        /* .unlockfs */
        .statfs         = nilfs_statfs,
        .remount_fs     = nilfs_remount,
-       .clear_inode    = nilfs_clear_inode,
        /* .umount_begin */
        .show_options = nilfs_show_options
  };
@@@ -605,25 -506,23 +587,25 @@@ static const struct export_operations n
  
  enum {
        Opt_err_cont, Opt_err_panic, Opt_err_ro,
 -      Opt_nobarrier, Opt_snapshot, Opt_order, Opt_norecovery,
 -      Opt_discard, Opt_err,
 +      Opt_barrier, Opt_nobarrier, Opt_snapshot, Opt_order, Opt_norecovery,
 +      Opt_discard, Opt_nodiscard, Opt_err,
  };
  
  static match_table_t tokens = {
        {Opt_err_cont, "errors=continue"},
        {Opt_err_panic, "errors=panic"},
        {Opt_err_ro, "errors=remount-ro"},
 +      {Opt_barrier, "barrier"},
        {Opt_nobarrier, "nobarrier"},
        {Opt_snapshot, "cp=%u"},
        {Opt_order, "order=%s"},
        {Opt_norecovery, "norecovery"},
        {Opt_discard, "discard"},
 +      {Opt_nodiscard, "nodiscard"},
        {Opt_err, NULL}
  };
  
 -static int parse_options(char *options, struct super_block *sb)
 +static int parse_options(char *options, struct super_block *sb, int is_remount)
  {
        struct nilfs_sb_info *sbi = NILFS_SB(sb);
        char *p;
  
                token = match_token(p, tokens, args);
                switch (token) {
 +              case Opt_barrier:
 +                      nilfs_set_opt(sbi, BARRIER);
 +                      break;
                case Opt_nobarrier:
                        nilfs_clear_opt(sbi, BARRIER);
                        break;
                case Opt_snapshot:
                        if (match_int(&args[0], &option) || option <= 0)
                                return 0;
 -                      if (!(sb->s_flags & MS_RDONLY))
 +                      if (is_remount) {
 +                              if (!nilfs_test_opt(sbi, SNAPSHOT)) {
 +                                      printk(KERN_ERR
 +                                             "NILFS: cannot change regular "
 +                                             "mount to snapshot.\n");
 +                                      return 0;
 +                              } else if (option != sbi->s_snapshot_cno) {
 +                                      printk(KERN_ERR
 +                                             "NILFS: cannot remount to a "
 +                                             "different snapshot.\n");
 +                                      return 0;
 +                              }
 +                              break;
 +                      }
 +                      if (!(sb->s_flags & MS_RDONLY)) {
 +                              printk(KERN_ERR "NILFS: cannot mount snapshot "
 +                                     "read/write.  A read-only option is "
 +                                     "required.\n");
                                return 0;
 +                      }
                        sbi->s_snapshot_cno = option;
                        nilfs_set_opt(sbi, SNAPSHOT);
                        break;
                case Opt_discard:
                        nilfs_set_opt(sbi, DISCARD);
                        break;
 +              case Opt_nodiscard:
 +                      nilfs_clear_opt(sbi, DISCARD);
 +                      break;
                default:
                        printk(KERN_ERR
                               "NILFS: Unrecognized mount option \"%s\"\n", p);
@@@ -720,18 -595,11 +702,18 @@@ nilfs_set_default_options(struct nilfs_
  static int nilfs_setup_super(struct nilfs_sb_info *sbi)
  {
        struct the_nilfs *nilfs = sbi->s_nilfs;
 -      struct nilfs_super_block *sbp = nilfs->ns_sbp[0];
 -      int max_mnt_count = le16_to_cpu(sbp->s_max_mnt_count);
 -      int mnt_count = le16_to_cpu(sbp->s_mnt_count);
 +      struct nilfs_super_block **sbp;
 +      int max_mnt_count;
 +      int mnt_count;
 +
 +      /* nilfs->ns_sem must be locked by the caller. */
 +      sbp = nilfs_prepare_super(sbi, 0);
 +      if (!sbp)
 +              return -EIO;
 +
 +      max_mnt_count = le16_to_cpu(sbp[0]->s_max_mnt_count);
 +      mnt_count = le16_to_cpu(sbp[0]->s_mnt_count);
  
 -      /* nilfs->sem must be locked by the caller. */
        if (nilfs->ns_mount_state & NILFS_ERROR_FS) {
                printk(KERN_WARNING
                       "NILFS warning: mounting fs with errors\n");
  #endif
        }
        if (!max_mnt_count)
 -              sbp->s_max_mnt_count = cpu_to_le16(NILFS_DFL_MAX_MNT_COUNT);
 -
 -      sbp->s_mnt_count = cpu_to_le16(mnt_count + 1);
 -      sbp->s_state = cpu_to_le16(le16_to_cpu(sbp->s_state) & ~NILFS_VALID_FS);
 -      sbp->s_mtime = cpu_to_le64(get_seconds());
 -      return nilfs_commit_super(sbi, 1);
 +              sbp[0]->s_max_mnt_count = cpu_to_le16(NILFS_DFL_MAX_MNT_COUNT);
 +
 +      sbp[0]->s_mnt_count = cpu_to_le16(mnt_count + 1);
 +      sbp[0]->s_state =
 +              cpu_to_le16(le16_to_cpu(sbp[0]->s_state) & ~NILFS_VALID_FS);
 +      sbp[0]->s_mtime = cpu_to_le64(get_seconds());
 +      /* synchronize sbp[1] with sbp[0] */
 +      memcpy(sbp[1], sbp[0], nilfs->ns_sbsize);
 +      return nilfs_commit_super(sbi, NILFS_SB_COMMIT_ALL);
  }
  
  struct nilfs_super_block *nilfs_read_super_block(struct super_block *sb,
@@@ -787,31 -652,7 +769,31 @@@ int nilfs_store_magic_and_option(struc
        sbi->s_interval = le32_to_cpu(sbp->s_c_interval);
        sbi->s_watermark = le32_to_cpu(sbp->s_c_block_max);
  
 -      return !parse_options(data, sb) ? -EINVAL : 0 ;
 +      return !parse_options(data, sb, 0) ? -EINVAL : 0 ;
 +}
 +
 +int nilfs_check_feature_compatibility(struct super_block *sb,
 +                                    struct nilfs_super_block *sbp)
 +{
 +      __u64 features;
 +
 +      features = le64_to_cpu(sbp->s_feature_incompat) &
 +              ~NILFS_FEATURE_INCOMPAT_SUPP;
 +      if (features) {
 +              printk(KERN_ERR "NILFS: couldn't mount because of unsupported "
 +                     "optional features (%llx)\n",
 +                     (unsigned long long)features);
 +              return -EINVAL;
 +      }
 +      features = le64_to_cpu(sbp->s_feature_compat_ro) &
 +              ~NILFS_FEATURE_COMPAT_RO_SUPP;
 +      if (!(sb->s_flags & MS_RDONLY) && features) {
 +              printk(KERN_ERR "NILFS: couldn't mount RDWR because of "
 +                     "unsupported optional features (%llx)\n",
 +                     (unsigned long long)features);
 +              return -EINVAL;
 +      }
 +      return 0;
  }
  
  /**
@@@ -960,6 -801,7 +942,6 @@@ nilfs_fill_super(struct super_block *sb
  static int nilfs_remount(struct super_block *sb, int *flags, char *data)
  {
        struct nilfs_sb_info *sbi = NILFS_SB(sb);
 -      struct nilfs_super_block *sbp;
        struct the_nilfs *nilfs = sbi->s_nilfs;
        unsigned long old_sb_flags;
        struct nilfs_mount_options old_opts;
        old_opts.snapshot_cno = sbi->s_snapshot_cno;
        was_snapshot = nilfs_test_opt(sbi, SNAPSHOT);
  
 -      if (!parse_options(data, sb)) {
 +      if (!parse_options(data, sb, 1)) {
                err = -EINVAL;
                goto restore_opts;
        }
        sb->s_flags = (sb->s_flags & ~MS_POSIXACL);
  
        err = -EINVAL;
 -      if (was_snapshot) {
 -              if (!(*flags & MS_RDONLY)) {
 -                      printk(KERN_ERR "NILFS (device %s): cannot remount "
 -                             "snapshot read/write.\n",
 -                             sb->s_id);
 -                      goto restore_opts;
 -              } else if (sbi->s_snapshot_cno != old_opts.snapshot_cno) {
 -                      printk(KERN_ERR "NILFS (device %s): cannot "
 -                             "remount to a different snapshot.\n",
 -                             sb->s_id);
 -                      goto restore_opts;
 -              }
 -      } else {
 -              if (nilfs_test_opt(sbi, SNAPSHOT)) {
 -                      printk(KERN_ERR "NILFS (device %s): cannot change "
 -                             "a regular mount to a snapshot.\n",
 -                             sb->s_id);
 -                      goto restore_opts;
 -              }
 +      if (was_snapshot && !(*flags & MS_RDONLY)) {
 +              printk(KERN_ERR "NILFS (device %s): cannot remount snapshot "
 +                     "read/write.\n", sb->s_id);
 +              goto restore_opts;
        }
  
        if (!nilfs_valid_fs(nilfs)) {
                 * the RDONLY flag and then mark the partition as valid again.
                 */
                down_write(&nilfs->ns_sem);
 -              sbp = nilfs->ns_sbp[0];
 -              if (!(sbp->s_state & le16_to_cpu(NILFS_VALID_FS)) &&
 -                  (nilfs->ns_mount_state & NILFS_VALID_FS))
 -                      sbp->s_state = cpu_to_le16(nilfs->ns_mount_state);
 -              sbp->s_mtime = cpu_to_le64(get_seconds());
 -              nilfs_commit_super(sbi, 1);
 +              nilfs_cleanup_super(sbi);
                up_write(&nilfs->ns_sem);
        } else {
 +              __u64 features;
 +
                /*
                 * Mounting a RDONLY partition read-write, so reread and
                 * store the current valid flag.  (It may have been changed
                 * by fsck since we originally mounted the partition.)
                 */
 +              down_read(&nilfs->ns_sem);
 +              features = le64_to_cpu(nilfs->ns_sbp[0]->s_feature_compat_ro) &
 +                      ~NILFS_FEATURE_COMPAT_RO_SUPP;
 +              up_read(&nilfs->ns_sem);
 +              if (features) {
 +                      printk(KERN_WARNING "NILFS (device %s): couldn't "
 +                             "remount RDWR because of unsupported optional "
 +                             "features (%llx)\n",
 +                             sb->s_id, (unsigned long long)features);
 +                      err = -EROFS;
 +                      goto restore_opts;
 +              }
 +
                sb->s_flags &= ~MS_RDONLY;
  
                err = nilfs_attach_segment_constructor(sbi);
@@@ -1254,7 -1101,7 +1236,7 @@@ static void nilfs_inode_init_once(void 
        init_rwsem(&ii->xattr_sem);
  #endif
        nilfs_btnode_cache_init_once(&ii->i_btnode_cache);
 -      ii->i_bmap = (struct nilfs_bmap *)&ii->i_bmap_union;
 +      ii->i_bmap = &ii->i_bmap_data;
        inode_init_once(&ii->vfs_inode);
  }
  
diff --combined fs/ocfs2/dlmfs/dlmfs.c
index bef34d0528d5527701399118d10878e7f1bbe4c2,a43ebb11ad3b9eecb0986891229f51c8299a3913..c2903b84bb7a8ccbc0ea099e4a8585559d3fcf67
@@@ -182,7 -182,8 +182,7 @@@ static int dlmfs_file_release(struct in
  {
        int level, status;
        struct dlmfs_inode_private *ip = DLMFS_I(inode);
 -      struct dlmfs_filp_private *fp =
 -              (struct dlmfs_filp_private *) file->private_data;
 +      struct dlmfs_filp_private *fp = file->private_data;
  
        if (S_ISDIR(inode->i_mode))
                BUG();
@@@ -213,10 -214,12 +213,12 @@@ static int dlmfs_file_setattr(struct de
  
        attr->ia_valid &= ~ATTR_SIZE;
        error = inode_change_ok(inode, attr);
-       if (!error)
-               error = inode_setattr(inode, attr);
+       if (error)
+               return error;
  
-       return error;
+       setattr_copy(inode, attr);
+       mark_inode_dirty(inode);
+       return 0;
  }
  
  static unsigned int dlmfs_file_poll(struct file *file, poll_table *wait)
@@@ -354,13 -357,12 +356,12 @@@ static void dlmfs_destroy_inode(struct 
        kmem_cache_free(dlmfs_inode_cache, DLMFS_I(inode));
  }
  
- static void dlmfs_clear_inode(struct inode *inode)
+ static void dlmfs_evict_inode(struct inode *inode)
  {
        int status;
        struct dlmfs_inode_private *ip;
  
-       if (!inode)
-               return;
+       end_writeback(inode);
  
        mlog(0, "inode %lu\n", inode->i_ino);
  
@@@ -630,7 -632,7 +631,7 @@@ static const struct super_operations dl
        .statfs         = simple_statfs,
        .alloc_inode    = dlmfs_alloc_inode,
        .destroy_inode  = dlmfs_destroy_inode,
-       .clear_inode    = dlmfs_clear_inode,
+       .evict_inode    = dlmfs_evict_inode,
        .drop_inode     = generic_delete_inode,
  };
  
diff --combined fs/ocfs2/super.c
index 03a799fdd7402abb631ddd6575d250a5bd7a3a2d,ae1a4437a9803540324c9fc0cdef15d6aa0f086b..fa1be1b304d10b7bf30c4ecb2c7a3fd9b3ecd8ca
@@@ -145,8 -145,7 +145,7 @@@ static const struct super_operations oc
        .alloc_inode    = ocfs2_alloc_inode,
        .destroy_inode  = ocfs2_destroy_inode,
        .drop_inode     = ocfs2_drop_inode,
-       .clear_inode    = ocfs2_clear_inode,
-       .delete_inode   = ocfs2_delete_inode,
+       .evict_inode    = ocfs2_evict_inode,
        .sync_fs        = ocfs2_sync_fs,
        .put_super      = ocfs2_put_super,
        .remount_fs     = ocfs2_remount,
@@@ -2472,7 -2471,7 +2471,7 @@@ static void ocfs2_delete_osb(struct ocf
        kfree(osb->slot_recovery_generations);
        /* FIXME
         * This belongs in journal shutdown, but because we have to
 -       * allocate osb->journal at the start of ocfs2_initalize_osb(),
 +       * allocate osb->journal at the start of ocfs2_initialize_osb(),
         * we free it here.
         */
        kfree(osb->journal);
diff --combined fs/proc/base.c
index 69254a365ce2e1a0797cd37bdf623381fbb0119b,a49d9dd06d1d7e9de38b6bed2a40e3dd0a572706..c806dfb24e082d94a14e8516ee6cecd327f926ab
@@@ -63,7 -63,6 +63,7 @@@
  #include <linux/namei.h>
  #include <linux/mnt_namespace.h>
  #include <linux/mm.h>
 +#include <linux/swap.h>
  #include <linux/rcupdate.h>
  #include <linux/kallsyms.h>
  #include <linux/stacktrace.h>
@@@ -428,14 -427,17 +428,14 @@@ static const struct file_operations pro
  
  #endif
  
 -/* The badness from the OOM killer */
 -unsigned long badness(struct task_struct *p, unsigned long uptime);
  static int proc_oom_score(struct task_struct *task, char *buffer)
  {
        unsigned long points = 0;
 -      struct timespec uptime;
  
 -      do_posix_clock_monotonic_gettime(&uptime);
        read_lock(&tasklist_lock);
        if (pid_alive(task))
 -              points = badness(task, uptime.tv_sec);
 +              points = oom_badness(task, NULL, NULL,
 +                                      totalram_pages + total_swap_pages);
        read_unlock(&tasklist_lock);
        return sprintf(buffer, "%lu\n", points);
  }
@@@ -559,9 -561,19 +559,19 @@@ static int proc_setattr(struct dentry *
                return -EPERM;
  
        error = inode_change_ok(inode, attr);
-       if (!error)
-               error = inode_setattr(inode, attr);
-       return error;
+       if (error)
+               return error;
+       if ((attr->ia_valid & ATTR_SIZE) &&
+           attr->ia_size != i_size_read(inode)) {
+               error = vmtruncate(inode, attr->ia_size);
+               if (error)
+                       return error;
+       }
+       setattr_copy(inode, attr);
+       mark_inode_dirty(inode);
+       return 0;
  }
  
  static const struct inode_operations proc_def_inode_operations = {
@@@ -1037,24 -1049,8 +1047,24 @@@ static ssize_t oom_adjust_write(struct 
                return -EACCES;
        }
  
 +      /*
 +       * Warn that /proc/pid/oom_adj is deprecated, see
 +       * Documentation/feature-removal-schedule.txt.
 +       */
 +      printk_once(KERN_WARNING "%s (%d): /proc/%d/oom_adj is deprecated, "
 +                      "please use /proc/%d/oom_score_adj instead.\n",
 +                      current->comm, task_pid_nr(current),
 +                      task_pid_nr(task), task_pid_nr(task));
        task->signal->oom_adj = oom_adjust;
 -
 +      /*
 +       * Scale /proc/pid/oom_score_adj appropriately ensuring that a maximum
 +       * value is always attainable.
 +       */
 +      if (task->signal->oom_adj == OOM_ADJUST_MAX)
 +              task->signal->oom_score_adj = OOM_SCORE_ADJ_MAX;
 +      else
 +              task->signal->oom_score_adj = (oom_adjust * OOM_SCORE_ADJ_MAX) /
 +                                                              -OOM_DISABLE;
        unlock_task_sighand(task, &flags);
        put_task_struct(task);
  
@@@ -1067,82 -1063,6 +1077,82 @@@ static const struct file_operations pro
        .llseek         = generic_file_llseek,
  };
  
 +static ssize_t oom_score_adj_read(struct file *file, char __user *buf,
 +                                      size_t count, loff_t *ppos)
 +{
 +      struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
 +      char buffer[PROC_NUMBUF];
 +      int oom_score_adj = OOM_SCORE_ADJ_MIN;
 +      unsigned long flags;
 +      size_t len;
 +
 +      if (!task)
 +              return -ESRCH;
 +      if (lock_task_sighand(task, &flags)) {
 +              oom_score_adj = task->signal->oom_score_adj;
 +              unlock_task_sighand(task, &flags);
 +      }
 +      put_task_struct(task);
 +      len = snprintf(buffer, sizeof(buffer), "%d\n", oom_score_adj);
 +      return simple_read_from_buffer(buf, count, ppos, buffer, len);
 +}
 +
 +static ssize_t oom_score_adj_write(struct file *file, const char __user *buf,
 +                                      size_t count, loff_t *ppos)
 +{
 +      struct task_struct *task;
 +      char buffer[PROC_NUMBUF];
 +      unsigned long flags;
 +      long oom_score_adj;
 +      int err;
 +
 +      memset(buffer, 0, sizeof(buffer));
 +      if (count > sizeof(buffer) - 1)
 +              count = sizeof(buffer) - 1;
 +      if (copy_from_user(buffer, buf, count))
 +              return -EFAULT;
 +
 +      err = strict_strtol(strstrip(buffer), 0, &oom_score_adj);
 +      if (err)
 +              return -EINVAL;
 +      if (oom_score_adj < OOM_SCORE_ADJ_MIN ||
 +                      oom_score_adj > OOM_SCORE_ADJ_MAX)
 +              return -EINVAL;
 +
 +      task = get_proc_task(file->f_path.dentry->d_inode);
 +      if (!task)
 +              return -ESRCH;
 +      if (!lock_task_sighand(task, &flags)) {
 +              put_task_struct(task);
 +              return -ESRCH;
 +      }
 +      if (oom_score_adj < task->signal->oom_score_adj &&
 +                      !capable(CAP_SYS_RESOURCE)) {
 +              unlock_task_sighand(task, &flags);
 +              put_task_struct(task);
 +              return -EACCES;
 +      }
 +
 +      task->signal->oom_score_adj = oom_score_adj;
 +      /*
 +       * Scale /proc/pid/oom_adj appropriately ensuring that OOM_DISABLE is
 +       * always attainable.
 +       */
 +      if (task->signal->oom_score_adj == OOM_SCORE_ADJ_MIN)
 +              task->signal->oom_adj = OOM_DISABLE;
 +      else
 +              task->signal->oom_adj = (oom_score_adj * OOM_ADJUST_MAX) /
 +                                                      OOM_SCORE_ADJ_MAX;
 +      unlock_task_sighand(task, &flags);
 +      put_task_struct(task);
 +      return count;
 +}
 +
 +static const struct file_operations proc_oom_score_adj_operations = {
 +      .read           = oom_score_adj_read,
 +      .write          = oom_score_adj_write,
 +};
 +
  #ifdef CONFIG_AUDITSYSCALL
  #define TMPBUFLEN 21
  static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
@@@ -2715,7 -2635,6 +2725,7 @@@ static const struct pid_entry tgid_base
  #endif
        INF("oom_score",  S_IRUGO, proc_oom_score),
        REG("oom_adj",    S_IRUGO|S_IWUSR, proc_oom_adjust_operations),
 +      REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations),
  #ifdef CONFIG_AUDITSYSCALL
        REG("loginuid",   S_IWUSR|S_IRUGO, proc_loginuid_operations),
        REG("sessionid",  S_IRUGO, proc_sessionid_operations),
@@@ -3050,7 -2969,6 +3060,7 @@@ static const struct pid_entry tid_base_
  #endif
        INF("oom_score", S_IRUGO, proc_oom_score),
        REG("oom_adj",   S_IRUGO|S_IWUSR, proc_oom_adjust_operations),
 +      REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations),
  #ifdef CONFIG_AUDITSYSCALL
        REG("loginuid",  S_IWUSR|S_IRUGO, proc_loginuid_operations),
        REG("sessionid",  S_IRUSR, proc_sessionid_operations),
diff --combined fs/quota/dquot.c
index ef72b1699429e856f711504cf7c818642926483a,5cec3e2348f1a5ae691539bbbd0f109de3a8a409..aad1316a977f10888a3a1d64e6bb4430bae4a5ef
@@@ -132,22 -132,6 +132,22 @@@ static __cacheline_aligned_in_smp DEFIN
  __cacheline_aligned_in_smp DEFINE_SPINLOCK(dq_data_lock);
  EXPORT_SYMBOL(dq_data_lock);
  
 +void __quota_error(struct super_block *sb, const char *func,
 +                const char *fmt, ...)
 +{
 +      va_list args;
 +
 +      if (printk_ratelimit()) {
 +              va_start(args, fmt);
 +              printk(KERN_ERR "Quota error (device %s): %s: ",
 +                     sb->s_id, func);
 +              vprintk(fmt, args);
 +              printk("\n");
 +              va_end(args);
 +      }
 +}
 +EXPORT_SYMBOL(__quota_error);
 +
  #if defined(CONFIG_QUOTA_DEBUG) || defined(CONFIG_PRINT_QUOTA_WARNING)
  static char *quotatypes[] = INITQFNAMES;
  #endif
@@@ -721,8 -705,11 +721,8 @@@ void dqput(struct dquot *dquot
                return;
  #ifdef CONFIG_QUOTA_DEBUG
        if (!atomic_read(&dquot->dq_count)) {
 -              printk("VFS: dqput: trying to free free dquot\n");
 -              printk("VFS: device %s, dquot of %s %d\n",
 -                      dquot->dq_sb->s_id,
 -                      quotatypes[dquot->dq_type],
 -                      dquot->dq_id);
 +              quota_error(dquot->dq_sb, "trying to free free dquot of %s %d",
 +                          quotatypes[dquot->dq_type], dquot->dq_id);
                BUG();
        }
  #endif
@@@ -745,9 -732,9 +745,9 @@@ we_slept
                /* Commit dquot before releasing */
                ret = dquot->dq_sb->dq_op->write_dquot(dquot);
                if (ret < 0) {
 -                      printk(KERN_ERR "VFS: cannot write quota structure on "
 -                              "device %s (error %d). Quota may get out of "
 -                              "sync!\n", dquot->dq_sb->s_id, ret);
 +                      quota_error(dquot->dq_sb, "Can't write quota structure"
 +                                  " (error %d). Quota may get out of sync!",
 +                                  ret);
                        /*
                         * We clear dirty bit anyway, so that we avoid
                         * infinite loop here
@@@ -898,7 -885,7 +898,7 @@@ static void add_dquot_ref(struct super_
  
        spin_lock(&inode_lock);
        list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
-               if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW))
+               if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW))
                        continue;
  #ifdef CONFIG_QUOTA_DEBUG
                if (unlikely(inode_get_rsv_space(inode) > 0))
  
  #ifdef CONFIG_QUOTA_DEBUG
        if (reserved) {
 -              printk(KERN_WARNING "VFS (%s): Writes happened before quota"
 -                      " was turned on thus quota information is probably "
 -                      "inconsistent. Please run quotacheck(8).\n", sb->s_id);
 +              quota_error(sb, "Writes happened before quota was turned on "
 +                      "thus quota information is probably inconsistent. "
 +                      "Please run quotacheck(8)");
        }
  #endif
  }
@@@ -960,9 -947,7 +960,9 @@@ static int remove_inode_dquot_ref(struc
                if (dqput_blocks(dquot)) {
  #ifdef CONFIG_QUOTA_DEBUG
                        if (atomic_read(&dquot->dq_count) != 1)
 -                              printk(KERN_WARNING "VFS: Adding dquot with dq_count %d to dispose list.\n", atomic_read(&dquot->dq_count));
 +                              quota_error(inode->i_sb, "Adding dquot with "
 +                                          "dq_count %d to dispose list",
 +                                          atomic_read(&dquot->dq_count));
  #endif
                        spin_lock(&dq_list_lock);
                        /* As dquot must have currently users it can't be on
@@@ -1001,7 -986,6 +1001,7 @@@ static void remove_dquot_ref(struct sup
                struct list_head *tofree_head)
  {
        struct inode *inode;
 +      int reserved = 0;
  
        spin_lock(&inode_lock);
        list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
                 *  only quota pointers and these have separate locking
                 *  (dqptr_sem).
                 */
 -              if (!IS_NOQUOTA(inode))
 +              if (!IS_NOQUOTA(inode)) {
 +                      if (unlikely(inode_get_rsv_space(inode) > 0))
 +                              reserved = 1;
                        remove_inode_dquot_ref(inode, type, tofree_head);
 +              }
        }
        spin_unlock(&inode_lock);
 +#ifdef CONFIG_QUOTA_DEBUG
 +      if (reserved) {
 +              printk(KERN_WARNING "VFS (%s): Writes happened after quota"
 +                      " was disabled thus quota information is probably "
 +                      "inconsistent. Please run quotacheck(8).\n", sb->s_id);
 +      }
 +#endif
  }
  
  /* Gather all references from inodes and drop them */
@@@ -1330,15 -1304,6 +1330,15 @@@ static int info_bdq_free(struct dquot *
        return QUOTA_NL_NOWARN;
  }
  
 +static int dquot_active(const struct inode *inode)
 +{
 +      struct super_block *sb = inode->i_sb;
 +
 +      if (IS_NOQUOTA(inode))
 +              return 0;
 +      return sb_any_quota_loaded(sb) & ~sb_any_quota_suspended(sb);
 +}
 +
  /*
   * Initialize quota pointers in inode
   *
@@@ -1358,7 -1323,7 +1358,7 @@@ static void __dquot_initialize(struct i
  
        /* First test before acquiring mutex - solves deadlocks when we
           * re-enter the quota code and are already holding the mutex */
 -      if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode))
 +      if (!dquot_active(inode))
                return;
  
        /* First get references to structures we might need. */
@@@ -1542,7 -1507,7 +1542,7 @@@ int __dquot_alloc_space(struct inode *i
         * First test before acquiring mutex - solves deadlocks when we
         * re-enter the quota code and are already holding the mutex
         */
 -      if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode)) {
 +      if (!dquot_active(inode)) {
                inode_incr_space(inode, number, reserve);
                goto out;
        }
@@@ -1594,7 -1559,7 +1594,7 @@@ int dquot_alloc_inode(const struct inod
  
        /* First test before acquiring mutex - solves deadlocks when we
           * re-enter the quota code and are already holding the mutex */
 -      if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode))
 +      if (!dquot_active(inode))
                return 0;
        for (cnt = 0; cnt < MAXQUOTAS; cnt++)
                warntype[cnt] = QUOTA_NL_NOWARN;
@@@ -1631,7 -1596,7 +1631,7 @@@ int dquot_claim_space_nodirty(struct in
  {
        int cnt;
  
 -      if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode)) {
 +      if (!dquot_active(inode)) {
                inode_claim_rsv_space(inode, number);
                return 0;
        }
@@@ -1664,7 -1629,7 +1664,7 @@@ void __dquot_free_space(struct inode *i
  
        /* First test before acquiring mutex - solves deadlocks when we
           * re-enter the quota code and are already holding the mutex */
 -      if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode)) {
 +      if (!dquot_active(inode)) {
                inode_decr_space(inode, number, reserve);
                return;
        }
@@@ -1702,7 -1667,7 +1702,7 @@@ void dquot_free_inode(const struct inod
  
        /* First test before acquiring mutex - solves deadlocks when we
           * re-enter the quota code and are already holding the mutex */
 -      if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode))
 +      if (!dquot_active(inode))
                return;
  
        down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
@@@ -1825,7 -1790,7 +1825,7 @@@ int dquot_transfer(struct inode *inode
        struct super_block *sb = inode->i_sb;
        int ret;
  
 -      if (!sb_any_quota_active(sb) || IS_NOQUOTA(inode))
 +      if (!dquot_active(inode))
                return 0;
  
        if (iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid)
@@@ -1992,7 -1957,7 +1992,7 @@@ int dquot_disable(struct super_block *s
                                truncate_inode_pages(&toputinode[cnt]->i_data,
                                                     0);
                                mutex_unlock(&toputinode[cnt]->i_mutex);
 -                              mark_inode_dirty(toputinode[cnt]);
 +                              mark_inode_dirty_sync(toputinode[cnt]);
                        }
                        mutex_unlock(&dqopt->dqonoff_mutex);
                }
@@@ -2305,7 -2270,7 +2305,7 @@@ static void do_get_dqblk(struct dquot *
        memset(di, 0, sizeof(*di));
        di->d_version = FS_DQUOT_VERSION;
        di->d_flags = dquot->dq_type == USRQUOTA ?
 -                      XFS_USER_QUOTA : XFS_GROUP_QUOTA;
 +                      FS_USER_QUOTA : FS_GROUP_QUOTA;
        di->d_id = dquot->dq_id;
  
        spin_lock(&dq_data_lock);
diff --combined fs/reiserfs/inode.c
index 29db72203bde5279322c9b6f549812a04ef9d2f9,a94e08b339fc6c8d0ee455b93946da557ffbb94f..ae35413dcbe1322a0ace18dbff0688138f585764
@@@ -25,7 -25,7 +25,7 @@@ int reiserfs_commit_write(struct file *
  int reiserfs_prepare_write(struct file *f, struct page *page,
                           unsigned from, unsigned to);
  
- void reiserfs_delete_inode(struct inode *inode)
+ void reiserfs_evict_inode(struct inode *inode)
  {
        /* We need blocks for transaction + (user+group) quota update (possibly delete) */
        int jbegin_count =
        int depth;
        int err;
  
-       if (!is_bad_inode(inode))
+       if (!inode->i_nlink && !is_bad_inode(inode))
                dquot_initialize(inode);
  
        truncate_inode_pages(&inode->i_data, 0);
+       if (inode->i_nlink)
+               goto no_delete;
  
        depth = reiserfs_write_lock_once(inode->i_sb);
  
                ;
        }
        out:
-       clear_inode(inode);     /* note this must go after the journal_end to prevent deadlock */
+       end_writeback(inode);   /* note this must go after the journal_end to prevent deadlock */
+       dquot_drop(inode);
        inode->i_blocks = 0;
        reiserfs_write_unlock_once(inode->i_sb, depth);
+ no_delete:
+       end_writeback(inode);
+       dquot_drop(inode);
  }
  
  static void _make_cpu_key(struct cpu_key *key, int version, __u32 dirid,
@@@ -1138,7 -1145,6 +1145,6 @@@ static void init_inode(struct inode *in
        REISERFS_I(inode)->i_prealloc_count = 0;
        REISERFS_I(inode)->i_trans_id = 0;
        REISERFS_I(inode)->i_jl = NULL;
-       mutex_init(&(REISERFS_I(inode)->i_mmap));
        reiserfs_init_xattr_rwsem(inode);
  
        if (stat_data_v1(ih)) {
                inode_set_bytes(inode,
                                to_real_used_space(inode, inode->i_blocks,
                                                   SD_V2_SIZE));
 -              /* read persistent inode attributes from sd and initalise
 +              /* read persistent inode attributes from sd and initialise
                   generic inode flags from them */
                REISERFS_I(inode)->i_attrs = sd_v2_attrs(sd);
                sd_attrs_to_i_attrs(sd_v2_attrs(sd), inode);
@@@ -1841,7 -1847,6 +1847,6 @@@ int reiserfs_new_inode(struct reiserfs_
        REISERFS_I(inode)->i_attrs =
            REISERFS_I(dir)->i_attrs & REISERFS_INHERIT_MASK;
        sd_attrs_to_i_attrs(REISERFS_I(inode)->i_attrs, inode);
-       mutex_init(&(REISERFS_I(inode)->i_mmap));
        reiserfs_init_xattr_rwsem(inode);
  
        /* key to search for correct place for new stat data */
@@@ -2587,8 -2592,7 +2592,7 @@@ static int reiserfs_write_begin(struct 
                old_ref = th->t_refcount;
                th->t_refcount++;
        }
-       ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
-                               reiserfs_get_block);
+       ret = __block_write_begin(page, pos, len, reiserfs_get_block);
        if (ret && reiserfs_transaction_running(inode->i_sb)) {
                struct reiserfs_transaction_handle *th = current->journal_info;
                /* this gets a little ugly.  If reiserfs_get_block returned an
@@@ -3059,10 -3063,25 +3063,25 @@@ static ssize_t reiserfs_direct_IO(int r
  {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
+       ssize_t ret;
  
-       return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
+       ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
                                  offset, nr_segs,
                                  reiserfs_get_blocks_direct_io, NULL);
+       /*
+        * In case of error extending write may have instantiated a few
+        * blocks outside i_size. Trim these off again.
+        */
+       if (unlikely((rw & WRITE) && ret < 0)) {
+               loff_t isize = i_size_read(inode);
+               loff_t end = offset + iov_length(iov, nr_segs);
+               if (end > isize)
+                       vmtruncate(inode, isize);
+       }
+       return ret;
  }
  
  int reiserfs_setattr(struct dentry *dentry, struct iattr *attr)
        int depth;
        int error;
  
+       error = inode_change_ok(inode, attr);
+       if (error)
+               return error;
        /* must be turned off for recursive notify_change calls */
        ia_valid = attr->ia_valid &= ~(ATTR_KILL_SUID|ATTR_KILL_SGID);
  
                goto out;
        }
  
-       error = inode_change_ok(inode, attr);
-       if (!error) {
-               if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
-                   (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
-                       error = reiserfs_chown_xattrs(inode, attr);
+       if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
+           (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
+               struct reiserfs_transaction_handle th;
+               int jbegin_count =
+                   2 *
+                   (REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb) +
+                    REISERFS_QUOTA_DEL_BLOCKS(inode->i_sb)) +
+                   2;
  
-                       if (!error) {
-                               struct reiserfs_transaction_handle th;
-                               int jbegin_count =
-                                   2 *
-                                   (REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb) +
-                                    REISERFS_QUOTA_DEL_BLOCKS(inode->i_sb)) +
-                                   2;
-                               /* (user+group)*(old+new) structure - we count quota info and , inode write (sb, inode) */
-                               error =
-                                   journal_begin(&th, inode->i_sb,
-                                                 jbegin_count);
-                               if (error)
-                                       goto out;
-                               error = dquot_transfer(inode, attr);
-                               if (error) {
-                                       journal_end(&th, inode->i_sb,
-                                                   jbegin_count);
-                                       goto out;
-                               }
-                               /* Update corresponding info in inode so that everything is in
-                                * one transaction */
-                               if (attr->ia_valid & ATTR_UID)
-                                       inode->i_uid = attr->ia_uid;
-                               if (attr->ia_valid & ATTR_GID)
-                                       inode->i_gid = attr->ia_gid;
-                               mark_inode_dirty(inode);
-                               error =
-                                   journal_end(&th, inode->i_sb, jbegin_count);
-                       }
-               }
-               if (!error) {
-                       /*
-                        * Relax the lock here, as it might truncate the
-                        * inode pages and wait for inode pages locks.
-                        * To release such page lock, the owner needs the
-                        * reiserfs lock
-                        */
-                       reiserfs_write_unlock_once(inode->i_sb, depth);
-                       error = inode_setattr(inode, attr);
-                       depth = reiserfs_write_lock_once(inode->i_sb);
+               error = reiserfs_chown_xattrs(inode, attr);
+               if (error)
+                       return error;
+               /* (user+group)*(old+new) structure - we count quota info and , inode write (sb, inode) */
+               error = journal_begin(&th, inode->i_sb, jbegin_count);
+               if (error)
+                       goto out;
+               error = dquot_transfer(inode, attr);
+               if (error) {
+                       journal_end(&th, inode->i_sb, jbegin_count);
+                       goto out;
                }
+               /* Update corresponding info in inode so that everything is in
+                * one transaction */
+               if (attr->ia_valid & ATTR_UID)
+                       inode->i_uid = attr->ia_uid;
+               if (attr->ia_valid & ATTR_GID)
+                       inode->i_gid = attr->ia_gid;
+               mark_inode_dirty(inode);
+               error = journal_end(&th, inode->i_sb, jbegin_count);
+               if (error)
+                       goto out;
+       }
+       /*
+        * Relax the lock here, as it might truncate the
+        * inode pages and wait for inode pages locks.
+        * To release such page lock, the owner needs the
+        * reiserfs lock
+        */
+       reiserfs_write_unlock_once(inode->i_sb, depth);
+       if ((attr->ia_valid & ATTR_SIZE) &&
+           attr->ia_size != i_size_read(inode))
+               error = vmtruncate(inode, attr->ia_size);
+       if (!error) {
+               setattr_copy(inode, attr);
+               mark_inode_dirty(inode);
        }
+       depth = reiserfs_write_lock_once(inode->i_sb);
  
        if (!error && reiserfs_posixacl(inode->i_sb)) {
                if (attr->ia_valid & ATTR_MODE)
diff --combined fs/ubifs/super.c
index 5fc5a0988970d15507ef048a6199c5e0f7219d65,899066dd0c14393a3c55f5ab9988e62af95dfc7b..cd5900b85d38373cc4998a562152fcbe334f541f
@@@ -327,7 -327,7 +327,7 @@@ static int ubifs_write_inode(struct ino
        return err;
  }
  
- static void ubifs_delete_inode(struct inode *inode)
+ static void ubifs_evict_inode(struct inode *inode)
  {
        int err;
        struct ubifs_info *c = inode->i_sb->s_fs_info;
  
        dbg_gen("inode %lu, mode %#x", inode->i_ino, (int)inode->i_mode);
        ubifs_assert(!atomic_read(&inode->i_count));
-       ubifs_assert(inode->i_nlink == 0);
  
        truncate_inode_pages(&inode->i_data, 0);
+       if (inode->i_nlink)
+               goto done;
        if (is_bad_inode(inode))
                goto out;
  
@@@ -367,7 -370,8 +370,8 @@@ out
                c->nospace = c->nospace_rp = 0;
                smp_wmb();
        }
-       clear_inode(inode);
+ done:
+       end_writeback(inode);
  }
  
  static void ubifs_dirty_inode(struct inode *inode)
@@@ -1307,8 -1311,6 +1311,8 @@@ static int mount_ubifs(struct ubifs_inf
                        if (err)
                                goto out_orphans;
                        err = ubifs_rcvry_gc_commit(c);
 +                      if (err)
 +                              goto out_orphans;
                } else {
                        err = take_gc_lnum(c);
                        if (err)
                         */
                        err = ubifs_leb_unmap(c, c->gc_lnum);
                        if (err)
 -                              return err;
 +                              goto out_orphans;
                }
  
                err = dbg_check_lprops(c);
@@@ -1826,7 -1828,7 +1830,7 @@@ const struct super_operations ubifs_sup
        .destroy_inode = ubifs_destroy_inode,
        .put_super     = ubifs_put_super,
        .write_inode   = ubifs_write_inode,
-       .delete_inode  = ubifs_delete_inode,
+       .evict_inode   = ubifs_evict_inode,
        .statfs        = ubifs_statfs,
        .dirty_inode   = ubifs_dirty_inode,
        .remount_fs    = ubifs_remount_fs,
diff --combined fs/udf/file.c
index 6e450e01a1bb81da6987801565de3b3323afc165,04bb5bf076308a055cb25f0f6c941b70f07ed47b..66b9e7e7e4c5434a8e281d03eebbcce730426951
@@@ -36,6 -36,7 +36,6 @@@
  #include <linux/pagemap.h>
  #include <linux/buffer_head.h>
  #include <linux/aio.h>
 -#include <linux/smp_lock.h>
  
  #include "udf_i.h"
  #include "udf_sb.h"
@@@ -227,6 -228,28 +227,28 @@@ const struct file_operations udf_file_o
        .llseek                 = generic_file_llseek,
  };
  
+ static int udf_setattr(struct dentry *dentry, struct iattr *attr)
+ {
+       struct inode *inode = dentry->d_inode;
+       int error;
+       error = inode_change_ok(inode, attr);
+       if (error)
+               return error;
+       if ((attr->ia_valid & ATTR_SIZE) &&
+           attr->ia_size != i_size_read(inode)) {
+               error = vmtruncate(inode, attr->ia_size);
+               if (error)
+                       return error;
+       }
+       setattr_copy(inode, attr);
+       mark_inode_dirty(inode);
+       return 0;
+ }
  const struct inode_operations udf_file_inode_operations = {
+       .setattr                = udf_setattr,
        .truncate               = udf_truncate,
  };
diff --combined fs/udf/super.c
index 12bb651e54009017cad7148fa878c359396c8a46,f9f4a9a0ea2bc6d86b385ff639d04d10c76f395c..65412d84a45d7c5e6e8563111c7ca4b66cec32b7
@@@ -175,8 -175,7 +175,7 @@@ static const struct super_operations ud
        .alloc_inode    = udf_alloc_inode,
        .destroy_inode  = udf_destroy_inode,
        .write_inode    = udf_write_inode,
-       .delete_inode   = udf_delete_inode,
-       .clear_inode    = udf_clear_inode,
+       .evict_inode    = udf_evict_inode,
        .put_super      = udf_put_super,
        .sync_fs        = udf_sync_fs,
        .statfs         = udf_statfs,
@@@ -1579,7 -1578,9 +1578,7 @@@ static int udf_load_sequence(struct sup
  {
        struct anchorVolDescPtr *anchor;
        long main_s, main_e, reserve_s, reserve_e;
 -      struct udf_sb_info *sbi;
  
 -      sbi = UDF_SB(sb);
        anchor = (struct anchorVolDescPtr *)bh->b_data;
  
        /* Locate the main sequence */
index 2ce51fac7d3dfda276fddc73bbd13ec24be56442,620f1d1088cb06d46fea6ed6fe4daafeb06435f3..43e649a72529afa8282f7da2029ab8e6759f0a97
@@@ -203,12 -203,10 +203,10 @@@ int block_write_full_page_endio(struct 
  int block_read_full_page(struct page*, get_block_t*);
  int block_is_partially_uptodate(struct page *page, read_descriptor_t *desc,
                                unsigned long from);
- int block_write_begin_newtrunc(struct file *, struct address_space *,
-                               loff_t, unsigned, unsigned,
-                               struct page **, void **, get_block_t*);
- int block_write_begin(struct file *, struct address_space *,
-                               loff_t, unsigned, unsigned,
-                               struct page **, void **, get_block_t*);
+ int block_write_begin(struct address_space *mapping, loff_t pos, unsigned len,
+               unsigned flags, struct page **pagep, get_block_t *get_block);
+ int __block_write_begin(struct page *page, loff_t pos, unsigned len,
+               get_block_t *get_block);
  int block_write_end(struct file *, struct address_space *,
                                loff_t, unsigned, unsigned,
                                struct page *, void *);
@@@ -217,9 -215,6 +215,6 @@@ int generic_write_end(struct file *, st
                                struct page *, void *);
  void page_zero_new_buffers(struct page *page, unsigned from, unsigned to);
  int block_prepare_write(struct page*, unsigned, unsigned, get_block_t*);
- int cont_write_begin_newtrunc(struct file *, struct address_space *, loff_t,
-                       unsigned, unsigned, struct page **, void **,
-                       get_block_t *, loff_t *);
  int cont_write_begin(struct file *, struct address_space *, loff_t,
                        unsigned, unsigned, struct page **, void **,
                        get_block_t *, loff_t *);
@@@ -230,12 -225,7 +225,7 @@@ int block_page_mkwrite(struct vm_area_s
  void block_sync_page(struct page *);
  sector_t generic_block_bmap(struct address_space *, sector_t, get_block_t *);
  int block_truncate_page(struct address_space *, loff_t, get_block_t *);
- int file_fsync(struct file *, int);
- int nobh_write_begin_newtrunc(struct file *, struct address_space *,
-                               loff_t, unsigned, unsigned,
-                               struct page **, void **, get_block_t*);
- int nobh_write_begin(struct file *, struct address_space *,
-                               loff_t, unsigned, unsigned,
+ int nobh_write_begin(struct address_space *, loff_t, unsigned, unsigned,
                                struct page **, void **, get_block_t*);
  int nobh_write_end(struct file *, struct address_space *,
                                loff_t, unsigned, unsigned,
@@@ -314,10 -304,15 +304,10 @@@ map_bh(struct buffer_head *bh, struct s
        bh->b_size = sb->s_blocksize;
  }
  
 -/*
 - * Calling wait_on_buffer() for a zero-ref buffer is illegal, so we call into
 - * __wait_on_buffer() just to trip a debug check.  Because debug code in inline
 - * functions is bloaty.
 - */
  static inline void wait_on_buffer(struct buffer_head *bh)
  {
        might_sleep();
 -      if (buffer_locked(bh) || atomic_read(&bh->b_count) == 0)
 +      if (buffer_locked(bh))
                __wait_on_buffer(bh);
  }
  
diff --combined include/linux/ext3_fs.h
index 3d3a9915dde29193895357edee90c8d3d13c81f3,e7cb217669923c29e1cc6c42053e6dc17fdd92a1..6ce1bca01724dd1408e1f73e60fcdd58caad345c
@@@ -400,6 -400,7 +400,6 @@@ struct ext3_inode 
  #define EXT3_MOUNT_POSIX_ACL          0x08000 /* POSIX Access Control Lists */
  #define EXT3_MOUNT_RESERVATION                0x10000 /* Preallocation */
  #define EXT3_MOUNT_BARRIER            0x20000 /* Use block barriers */
 -#define EXT3_MOUNT_NOBH                       0x40000 /* No bufferheads */
  #define EXT3_MOUNT_QUOTA              0x80000 /* Some quota option set */
  #define EXT3_MOUNT_USRQUOTA           0x100000 /* "old" user quota */
  #define EXT3_MOUNT_GRPQUOTA           0x200000 /* "old" group quota */
@@@ -895,7 -896,7 +895,7 @@@ int ext3_get_blocks_handle(handle_t *ha
  extern struct inode *ext3_iget(struct super_block *, unsigned long);
  extern int  ext3_write_inode (struct inode *, struct writeback_control *);
  extern int  ext3_setattr (struct dentry *, struct iattr *);
- extern void ext3_delete_inode (struct inode *);
+ extern void ext3_evict_inode (struct inode *);
  extern int  ext3_sync_inode (handle_t *, struct inode *);
  extern void ext3_discard_reservation (struct inode *);
  extern void ext3_dirty_inode(struct inode *);
diff --combined include/linux/fs.h
index 488efec09d148dc91972962048540adfe261e5ac,58e4b035e2825ee8b65e14cd1d797cf7a6d1037d..9e221016a6a9a3857fb39cfca17d5de632fff9d9
@@@ -53,7 -53,6 +53,7 @@@ struct inodes_stat_t 
  #define MAY_APPEND 8
  #define MAY_ACCESS 16
  #define MAY_OPEN 32
 +#define MAY_CHDIR 64
  
  /*
   * flags in file.f_mode.  Note that FMODE_READ and FMODE_WRITE must correspond
  #define MS_KERNMOUNT  (1<<22) /* this is a kern_mount call */
  #define MS_I_VERSION  (1<<23) /* Update inode I_version field */
  #define MS_STRICTATIME        (1<<24) /* Always perform atime updates */
+ #define MS_BORN               (1<<29)
  #define MS_ACTIVE     (1<<30)
  #define MS_NOUSER     (1<<31)
  
@@@ -687,7 -687,6 +688,7 @@@ struct block_device 
   */
  #define PAGECACHE_TAG_DIRTY   0
  #define PAGECACHE_TAG_WRITEBACK       1
 +#define PAGECACHE_TAG_TOWRITE 2
  
  int mapping_tagged(struct address_space *mapping, int tag);
  
@@@ -1564,8 -1563,8 +1565,8 @@@ struct super_operations 
  
        void (*dirty_inode) (struct inode *);
        int (*write_inode) (struct inode *, struct writeback_control *wbc);
-       void (*drop_inode) (struct inode *);
-       void (*delete_inode) (struct inode *);
+       int (*drop_inode) (struct inode *);
+       void (*evict_inode) (struct inode *);
        void (*put_super) (struct super_block *);
        void (*write_super) (struct super_block *);
        int (*sync_fs)(struct super_block *sb, int wait);
        int (*unfreeze_fs) (struct super_block *);
        int (*statfs) (struct dentry *, struct kstatfs *);
        int (*remount_fs) (struct super_block *, int *, char *);
-       void (*clear_inode) (struct inode *);
        void (*umount_begin) (struct super_block *);
  
        int (*show_options)(struct seq_file *, struct vfsmount *);
   * I_FREEING          Set when inode is about to be freed but still has dirty
   *                    pages or buffers attached or the inode itself is still
   *                    dirty.
-  * I_CLEAR            Set by clear_inode().  In this state the inode is clean
-  *                    and can be destroyed.
+  * I_CLEAR            Added by end_writeback().  In this state the inode is clean
+  *                    and can be destroyed.  Inode keeps I_FREEING.
   *
   *                    Inodes that are I_WILL_FREE, I_FREEING or I_CLEAR are
   *                    prohibited for many purposes.  iget() must wait for
@@@ -1816,7 -1814,8 +1816,8 @@@ extern struct vfsmount *collect_mounts(
  extern void drop_collected_mounts(struct vfsmount *);
  extern int iterate_mounts(int (*)(struct vfsmount *, void *), void *,
                          struct vfsmount *);
- extern int vfs_statfs(struct dentry *, struct kstatfs *);
+ extern int vfs_statfs(struct path *, struct kstatfs *);
+ extern int statfs_by_dentry(struct dentry *, struct kstatfs *);
  extern int freeze_super(struct super_block *super);
  extern int thaw_super(struct super_block *super);
  
@@@ -2166,9 -2165,8 +2167,8 @@@ extern void iput(struct inode *)
  extern struct inode * igrab(struct inode *);
  extern ino_t iunique(struct super_block *, ino_t);
  extern int inode_needs_sync(struct inode *inode);
- extern void generic_delete_inode(struct inode *inode);
- extern void generic_drop_inode(struct inode *inode);
- extern int generic_detach_inode(struct inode *inode);
+ extern int generic_delete_inode(struct inode *inode);
+ extern int generic_drop_inode(struct inode *inode);
  
  extern struct inode *ilookup5_nowait(struct super_block *sb,
                unsigned long hashval, int (*test)(struct inode *, void *),
@@@ -2185,7 -2183,7 +2185,7 @@@ extern void unlock_new_inode(struct ino
  
  extern void __iget(struct inode * inode);
  extern void iget_failed(struct inode *);
- extern void clear_inode(struct inode *);
+ extern void end_writeback(struct inode *);
  extern void destroy_inode(struct inode *);
  extern void __destroy_inode(struct inode *);
  extern struct inode *new_inode(struct super_block *);
@@@ -2271,16 -2269,6 +2271,6 @@@ static inline int xip_truncate_page(str
  struct bio;
  typedef void (dio_submit_t)(int rw, struct bio *bio, struct inode *inode,
                            loff_t file_offset);
- void dio_end_io(struct bio *bio, int error);
- ssize_t __blockdev_direct_IO_newtrunc(int rw, struct kiocb *iocb, struct inode *inode,
-       struct block_device *bdev, const struct iovec *iov, loff_t offset,
-       unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
-       dio_submit_t submit_io, int lock_type);
- ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
-       struct block_device *bdev, const struct iovec *iov, loff_t offset,
-       unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
-       dio_submit_t submit_io, int lock_type);
  
  enum {
        /* need locking between buffered and direct access */
        DIO_SKIP_HOLES  = 0x02,
  };
  
- static inline ssize_t blockdev_direct_IO_newtrunc(int rw, struct kiocb *iocb,
-       struct inode *inode, struct block_device *bdev, const struct iovec *iov,
-       loff_t offset, unsigned long nr_segs, get_block_t get_block,
-       dio_iodone_t end_io)
- {
-       return __blockdev_direct_IO_newtrunc(rw, iocb, inode, bdev, iov, offset,
-                                   nr_segs, get_block, end_io, NULL,
-                                   DIO_LOCKING | DIO_SKIP_HOLES);
- }
+ void dio_end_io(struct bio *bio, int error);
+ ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
+       struct block_device *bdev, const struct iovec *iov, loff_t offset,
+       unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
+       dio_submit_t submit_io, int flags);
  
- static inline ssize_t blockdev_direct_IO_no_locking_newtrunc(int rw, struct kiocb *iocb,
-       struct inode *inode, struct block_device *bdev, const struct iovec *iov,
-       loff_t offset, unsigned long nr_segs, get_block_t get_block,
-       dio_iodone_t end_io)
- {
-       return __blockdev_direct_IO_newtrunc(rw, iocb, inode, bdev, iov, offset,
-                               nr_segs, get_block, end_io, NULL, 0);
- }
  static inline ssize_t blockdev_direct_IO(int rw, struct kiocb *iocb,
        struct inode *inode, struct block_device *bdev, const struct iovec *iov,
        loff_t offset, unsigned long nr_segs, get_block_t get_block,
                                    nr_segs, get_block, end_io, NULL,
                                    DIO_LOCKING | DIO_SKIP_HOLES);
  }
- static inline ssize_t blockdev_direct_IO_no_locking(int rw, struct kiocb *iocb,
-       struct inode *inode, struct block_device *bdev, const struct iovec *iov,
-       loff_t offset, unsigned long nr_segs, get_block_t get_block,
-       dio_iodone_t end_io)
- {
-       return __blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset,
-                                   nr_segs, get_block, end_io, NULL, 0);
- }
  #endif
  
  extern const struct file_operations generic_ro_fops;
@@@ -2387,7 -2355,6 +2357,6 @@@ extern int simple_link(struct dentry *
  extern int simple_unlink(struct inode *, struct dentry *);
  extern int simple_rmdir(struct inode *, struct dentry *);
  extern int simple_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
- extern int simple_setsize(struct inode *, loff_t);
  extern int noop_fsync(struct file *, int);
  extern int simple_empty(struct dentry *);
  extern int simple_readpage(struct file *file, struct page *page);
@@@ -2424,8 -2391,7 +2393,7 @@@ extern int buffer_migrate_page(struct a
  
  extern int inode_change_ok(const struct inode *, struct iattr *);
  extern int inode_newsize_ok(const struct inode *, loff_t offset);
- extern int __must_check inode_setattr(struct inode *, const struct iattr *);
- extern void generic_setattr(struct inode *inode, const struct iattr *attr);
+ extern void setattr_copy(struct inode *inode, const struct iattr *attr);
  
  extern void file_update_time(struct file *file);
  
diff --combined include/linux/mm.h
index 7a9ab7db1975bdf9b21d58936f206c10c0dfcef0,980164ea10ee00d60444ad766d061535f62d1fc6..709f6728fc90e223c9f41092d626b7b7fc4458bd
@@@ -815,6 -815,7 +815,7 @@@ static inline void unmap_shared_mapping
  }
  
  extern void truncate_pagecache(struct inode *inode, loff_t old, loff_t new);
+ extern void truncate_setsize(struct inode *inode, loff_t newsize);
  extern int vmtruncate(struct inode *inode, loff_t offset);
  extern int vmtruncate_range(struct inode *inode, loff_t offset, loff_t end);
  
@@@ -1465,14 -1466,6 +1466,14 @@@ extern int sysctl_memory_failure_recove
  extern void shake_page(struct page *p, int access);
  extern atomic_long_t mce_bad_pages;
  extern int soft_offline_page(struct page *page, int flags);
 +#ifdef CONFIG_MEMORY_FAILURE
 +int is_hwpoison_address(unsigned long addr);
 +#else
 +static inline int is_hwpoison_address(unsigned long addr)
 +{
 +      return 0;
 +}
 +#endif
  
  extern void dump_page(struct page *page);
  
index ba394163dea1b89f31cfa3a5555a52ffeafda051,2a464ae147ce0fa72d47a60c638e605a2d8a7b18..91a4177e60ce3779e21c7a3fd8bfbc08858d43f3
@@@ -360,7 -360,7 +360,7 @@@ int is_reiserfs_jr(struct reiserfs_supe
  /* the spot for the super in versions 3.5 - 3.5.10 (inclusive) */
  #define REISERFS_OLD_DISK_OFFSET_IN_BYTES (8 * 1024)
  
 -// reiserfs internal error code (used by search_by_key adn fix_nodes))
 +/* reiserfs internal error code (used by search_by_key and fix_nodes)) */
  #define CARRY_ON      0
  #define REPEAT_SEARCH -1
  #define IO_ERROR      -2
@@@ -2033,7 -2033,7 +2033,7 @@@ void reiserfs_read_locked_inode(struct 
                                struct reiserfs_iget_args *args);
  int reiserfs_find_actor(struct inode *inode, void *p);
  int reiserfs_init_locked_inode(struct inode *inode, void *p);
- void reiserfs_delete_inode(struct inode *inode);
+ void reiserfs_evict_inode(struct inode *inode);
  int reiserfs_write_inode(struct inode *inode, struct writeback_control *wbc);
  int reiserfs_get_block(struct inode *inode, sector_t block,
                       struct buffer_head *bh_result, int create);
diff --combined mm/shmem.c
index 566f9a481e64afb3805d77d4a8465c85fb7e9ea9,1529d8fdc23f003ab7c2a0b06209950ff64ff015..dfaa0f4e9789f5e8f395ac1dee7975c1abffdc1d
@@@ -28,7 -28,6 +28,7 @@@
  #include <linux/file.h>
  #include <linux/mm.h>
  #include <linux/module.h>
 +#include <linux/percpu_counter.h>
  #include <linux/swap.h>
  
  static struct vfsmount *shm_mnt;
@@@ -234,10 -233,10 +234,10 @@@ static void shmem_free_blocks(struct in
  {
        struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
        if (sbinfo->max_blocks) {
 -              spin_lock(&sbinfo->stat_lock);
 -              sbinfo->free_blocks += pages;
 +              percpu_counter_add(&sbinfo->used_blocks, -pages);
 +              spin_lock(&inode->i_lock);
                inode->i_blocks -= pages*BLOCKS_PER_PAGE;
 -              spin_unlock(&sbinfo->stat_lock);
 +              spin_unlock(&inode->i_lock);
        }
  }
  
@@@ -417,17 -416,19 +417,17 @@@ static swp_entry_t *shmem_swp_alloc(str
                if (sgp == SGP_READ)
                        return shmem_swp_map(ZERO_PAGE(0));
                /*
 -               * Test free_blocks against 1 not 0, since we have 1 data
 +               * Test used_blocks against 1 less max_blocks, since we have 1 data
                 * page (and perhaps indirect index pages) yet to allocate:
                 * a waste to allocate index if we cannot allocate data.
                 */
                if (sbinfo->max_blocks) {
 -                      spin_lock(&sbinfo->stat_lock);
 -                      if (sbinfo->free_blocks <= 1) {
 -                              spin_unlock(&sbinfo->stat_lock);
 +                      if (percpu_counter_compare(&sbinfo->used_blocks, (sbinfo->max_blocks - 1)) > 0)
                                return ERR_PTR(-ENOSPC);
 -                      }
 -                      sbinfo->free_blocks--;
 +                      percpu_counter_inc(&sbinfo->used_blocks);
 +                      spin_lock(&inode->i_lock);
                        inode->i_blocks += BLOCKS_PER_PAGE;
 -                      spin_unlock(&sbinfo->stat_lock);
 +                      spin_unlock(&inode->i_lock);
                }
  
                spin_unlock(&info->lock);
@@@ -766,6 -767,10 +766,10 @@@ static int shmem_notify_change(struct d
        loff_t newsize = attr->ia_size;
        int error;
  
+       error = inode_change_ok(inode, attr);
+       if (error)
+               return error;
        if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)
                                        && newsize != inode->i_size) {
                struct page *page = NULL;
                        }
                }
  
-               error = simple_setsize(inode, newsize);
+               /* XXX(truncate): truncate_setsize should be called last */
+               truncate_setsize(inode, newsize);
                if (page)
                        page_cache_release(page);
-               if (error)
-                       return error;
                shmem_truncate_range(inode, newsize, (loff_t)-1);
        }
  
-       error = inode_change_ok(inode, attr);
-       if (!error)
-               generic_setattr(inode, attr);
+       setattr_copy(inode, attr);
  #ifdef CONFIG_TMPFS_POSIX_ACL
-       if (!error && (attr->ia_valid & ATTR_MODE))
+       if (attr->ia_valid & ATTR_MODE)
                error = generic_acl_chmod(inode);
  #endif
        return error;
  }
  
- static void shmem_delete_inode(struct inode *inode)
+ static void shmem_evict_inode(struct inode *inode)
  {
        struct shmem_inode_info *info = SHMEM_I(inode);
  
        }
        BUG_ON(inode->i_blocks);
        shmem_free_inode(inode->i_sb);
-       clear_inode(inode);
+       end_writeback(inode);
  }
  
  static inline int shmem_find_swp(swp_entry_t entry, swp_entry_t *dir, swp_entry_t *edir)
@@@ -932,7 -934,7 +933,7 @@@ found
  
        /*
         * Move _head_ to start search for next from here.
-        * But be careful: shmem_delete_inode checks list_empty without taking
+        * But be careful: shmem_evict_inode checks list_empty without taking
         * mutex, and there's an instant in list_move_tail when info->swaplist
         * would appear empty, if it were the only one on shmem_swaplist.  We
         * could avoid doing it if inode NULL; or use this minor optimization.
@@@ -1222,7 -1224,6 +1223,7 @@@ static int shmem_getpage(struct inode *
        struct shmem_sb_info *sbinfo;
        struct page *filepage = *pagep;
        struct page *swappage;
 +      struct page *prealloc_page = NULL;
        swp_entry_t *entry;
        swp_entry_t swap;
        gfp_t gfp;
@@@ -1247,6 -1248,7 +1248,6 @@@ repeat
                filepage = find_lock_page(mapping, idx);
        if (filepage && PageUptodate(filepage))
                goto done;
 -      error = 0;
        gfp = mapping_gfp_mask(mapping);
        if (!filepage) {
                /*
                if (error)
                        goto failed;
                radix_tree_preload_end();
 +              if (sgp != SGP_READ && !prealloc_page) {
 +                      /* We don't care if this fails */
 +                      prealloc_page = shmem_alloc_page(gfp, info, idx);
 +                      if (prealloc_page) {
 +                              if (mem_cgroup_cache_charge(prealloc_page,
 +                                              current->mm, GFP_KERNEL)) {
 +                                      page_cache_release(prealloc_page);
 +                                      prealloc_page = NULL;
 +                              }
 +                      }
 +              }
        }
 +      error = 0;
  
        spin_lock(&info->lock);
        shmem_recalc_inode(inode);
                shmem_swp_unmap(entry);
                sbinfo = SHMEM_SB(inode->i_sb);
                if (sbinfo->max_blocks) {
 -                      spin_lock(&sbinfo->stat_lock);
 -                      if (sbinfo->free_blocks == 0 ||
 +                      if ((percpu_counter_compare(&sbinfo->used_blocks, sbinfo->max_blocks) > 0) ||
                            shmem_acct_block(info->flags)) {
 -                              spin_unlock(&sbinfo->stat_lock);
                                spin_unlock(&info->lock);
                                error = -ENOSPC;
                                goto failed;
                        }
 -                      sbinfo->free_blocks--;
 +                      percpu_counter_inc(&sbinfo->used_blocks);
 +                      spin_lock(&inode->i_lock);
                        inode->i_blocks += BLOCKS_PER_PAGE;
 -                      spin_unlock(&sbinfo->stat_lock);
 +                      spin_unlock(&inode->i_lock);
                } else if (shmem_acct_block(info->flags)) {
                        spin_unlock(&info->lock);
                        error = -ENOSPC;
                if (!filepage) {
                        int ret;
  
 -                      spin_unlock(&info->lock);
 -                      filepage = shmem_alloc_page(gfp, info, idx);
 -                      if (!filepage) {
 -                              shmem_unacct_blocks(info->flags, 1);
 -                              shmem_free_blocks(inode, 1);
 -                              error = -ENOMEM;
 -                              goto failed;
 -                      }
 -                      SetPageSwapBacked(filepage);
 +                      if (!prealloc_page) {
 +                              spin_unlock(&info->lock);
 +                              filepage = shmem_alloc_page(gfp, info, idx);
 +                              if (!filepage) {
 +                                      shmem_unacct_blocks(info->flags, 1);
 +                                      shmem_free_blocks(inode, 1);
 +                                      error = -ENOMEM;
 +                                      goto failed;
 +                              }
 +                              SetPageSwapBacked(filepage);
  
 -                      /* Precharge page while we can wait, compensate after */
 -                      error = mem_cgroup_cache_charge(filepage, current->mm,
 -                                      GFP_KERNEL);
 -                      if (error) {
 -                              page_cache_release(filepage);
 -                              shmem_unacct_blocks(info->flags, 1);
 -                              shmem_free_blocks(inode, 1);
 -                              filepage = NULL;
 -                              goto failed;
 +                              /*
 +                               * Precharge page while we can wait, compensate
 +                               * after
 +                               */
 +                              error = mem_cgroup_cache_charge(filepage,
 +                                      current->mm, GFP_KERNEL);
 +                              if (error) {
 +                                      page_cache_release(filepage);
 +                                      shmem_unacct_blocks(info->flags, 1);
 +                                      shmem_free_blocks(inode, 1);
 +                                      filepage = NULL;
 +                                      goto failed;
 +                              }
 +
 +                              spin_lock(&info->lock);
 +                      } else {
 +                              filepage = prealloc_page;
 +                              prealloc_page = NULL;
 +                              SetPageSwapBacked(filepage);
                        }
  
 -                      spin_lock(&info->lock);
                        entry = shmem_swp_alloc(info, idx, sgp);
                        if (IS_ERR(entry))
                                error = PTR_ERR(entry);
        }
  done:
        *pagep = filepage;
 -      return 0;
 +      error = 0;
 +      goto out;
  
  failed:
        if (*pagep != filepage) {
                unlock_page(filepage);
                page_cache_release(filepage);
        }
 +out:
 +      if (prealloc_page) {
 +              mem_cgroup_uncharge_cache_page(prealloc_page);
 +              page_cache_release(prealloc_page);
 +      }
        return error;
  }
  
@@@ -1817,16 -1792,17 +1818,16 @@@ static int shmem_statfs(struct dentry *
        buf->f_type = TMPFS_MAGIC;
        buf->f_bsize = PAGE_CACHE_SIZE;
        buf->f_namelen = NAME_MAX;
 -      spin_lock(&sbinfo->stat_lock);
        if (sbinfo->max_blocks) {
                buf->f_blocks = sbinfo->max_blocks;
 -              buf->f_bavail = buf->f_bfree = sbinfo->free_blocks;
 +              buf->f_bavail = buf->f_bfree =
 +                              sbinfo->max_blocks - percpu_counter_sum(&sbinfo->used_blocks);
        }
        if (sbinfo->max_inodes) {
                buf->f_files = sbinfo->max_inodes;
                buf->f_ffree = sbinfo->free_inodes;
        }
        /* else leave those fields 0 like simple_statfs */
 -      spin_unlock(&sbinfo->stat_lock);
        return 0;
  }
  
@@@ -2267,6 -2243,7 +2268,6 @@@ static int shmem_remount_fs(struct supe
  {
        struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
        struct shmem_sb_info config = *sbinfo;
 -      unsigned long blocks;
        unsigned long inodes;
        int error = -EINVAL;
  
                return error;
  
        spin_lock(&sbinfo->stat_lock);
 -      blocks = sbinfo->max_blocks - sbinfo->free_blocks;
        inodes = sbinfo->max_inodes - sbinfo->free_inodes;
 -      if (config.max_blocks < blocks)
 +      if (percpu_counter_compare(&sbinfo->used_blocks, config.max_blocks) > 0)
                goto out;
        if (config.max_inodes < inodes)
                goto out;
  
        error = 0;
        sbinfo->max_blocks  = config.max_blocks;
 -      sbinfo->free_blocks = config.max_blocks - blocks;
        sbinfo->max_inodes  = config.max_inodes;
        sbinfo->free_inodes = config.max_inodes - inodes;
  
@@@ -2366,7 -2345,7 +2367,7 @@@ int shmem_fill_super(struct super_bloc
  #endif
  
        spin_lock_init(&sbinfo->stat_lock);
 -      sbinfo->free_blocks = sbinfo->max_blocks;
 +      percpu_counter_init(&sbinfo->used_blocks, 0);
        sbinfo->free_inodes = sbinfo->max_inodes;
  
        sb->s_maxbytes = SHMEM_MAX_BYTES;
@@@ -2518,7 -2497,7 +2519,7 @@@ static const struct super_operations sh
        .remount_fs     = shmem_remount_fs,
        .show_options   = shmem_show_options,
  #endif
-       .delete_inode   = shmem_delete_inode,
+       .evict_inode    = shmem_evict_inode,
        .drop_inode     = generic_delete_inode,
        .put_super      = shmem_put_super,
  };