Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/hch/vfs...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 28 Oct 2011 17:49:34 +0000 (10:49 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 28 Oct 2011 17:49:34 +0000 (10:49 -0700)
* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/hch/vfs-queue: (21 commits)
  leases: fix write-open/read-lease race
  nfs: drop unnecessary locking in llseek
  ext4: replace cut'n'pasted llseek code with generic_file_llseek_size
  vfs: add generic_file_llseek_size
  vfs: do (nearly) lockless generic_file_llseek
  direct-io: merge direct_io_walker into __blockdev_direct_IO
  direct-io: inline the complete submission path
  direct-io: separate map_bh from dio
  direct-io: use a slab cache for struct dio
  direct-io: rearrange fields in dio/dio_submit to avoid holes
  direct-io: fix a wrong comment
  direct-io: separate fields only used in the submission path from struct dio
  vfs: fix spinning prevention in prune_icache_sb
  vfs: add a comment to inode_permission()
  vfs: pass all mask flags check_acl and posix_acl_permission
  vfs: add hex format for MAY_* flag values
  vfs: indicate that the permission functions take all the MAY_* flags
  compat: sync compat_stats with statfs.
  vfs: add "device" tag to /proc/self/mountstats
  cleanup: vfs: small comment fix for block_invalidatepage
  ...

Fix up trivial conflict in fs/gfs2/file.c (llseek changes)

1  2 
fs/cifs/cifsfs.c
fs/compat.c
fs/gfs2/file.c
include/linux/fs.h

diff --combined fs/cifs/cifsfs.c
@@@ -53,7 -53,7 +53,7 @@@
  int cifsFYI = 0;
  int cifsERROR = 1;
  int traceSMB = 0;
 -unsigned int oplockEnabled = 1;
 +bool enable_oplocks = true;
  unsigned int linuxExtEnabled = 1;
  unsigned int lookupCacheEnabled = 1;
  unsigned int multiuser_mount = 0;
@@@ -74,7 -74,7 +74,7 @@@ module_param(cifs_min_small, int, 0)
  MODULE_PARM_DESC(cifs_min_small, "Small network buffers in pool. Default: 30 "
                                 "Range: 2 to 256");
  unsigned int cifs_max_pending = CIFS_MAX_REQ;
 -module_param(cifs_max_pending, int, 0);
 +module_param(cifs_max_pending, int, 0444);
  MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. "
                                   "Default: 50 Range: 2 to 256");
  unsigned short echo_retries = 5;
@@@ -82,10 -82,6 +82,10 @@@ module_param(echo_retries, ushort, 0644
  MODULE_PARM_DESC(echo_retries, "Number of echo attempts before giving up and "
                               "reconnecting server. Default: 5. 0 means "
                               "never reconnect.");
 +module_param(enable_oplocks, bool, 0644);
 +MODULE_PARM_DESC(enable_oplocks, "Enable or disable oplocks (bool). Default:"
 +                               "y/Y/1");
 +
  extern mempool_t *cifs_sm_req_poolp;
  extern mempool_t *cifs_req_poolp;
  extern mempool_t *cifs_mid_poolp;
@@@ -136,12 -132,12 +136,12 @@@ cifs_read_super(struct super_block *sb
        else
                sb->s_d_op = &cifs_dentry_ops;
  
 -#ifdef CIFS_NFSD_EXPORT
 +#ifdef CONFIG_CIFS_NFSD_EXPORT
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
                cFYI(1, "export ops supported");
                sb->s_export_op = &cifs_export_ops;
        }
 -#endif /* CIFS_NFSD_EXPORT */
 +#endif /* CONFIG_CIFS_NFSD_EXPORT */
  
        return 0;
  
@@@ -436,12 -432,6 +436,12 @@@ cifs_show_options(struct seq_file *s, s
                seq_printf(s, ",mfsymlinks");
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE)
                seq_printf(s, ",fsc");
 +      if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)
 +              seq_printf(s, ",nostrictsync");
 +      if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
 +              seq_printf(s, ",noperm");
 +      if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO)
 +              seq_printf(s, ",strictcache");
  
        seq_printf(s, ",rsize=%d", cifs_sb->rsize);
        seq_printf(s, ",wsize=%d", cifs_sb->wsize);
@@@ -540,6 -530,7 +540,6 @@@ cifs_get_root(struct smb_vol *vol, stru
        char *full_path = NULL;
        char *s, *p;
        char sep;
 -      int xid;
  
        full_path = cifs_build_path_to_root(vol, cifs_sb,
                                            cifs_sb_master_tcon(cifs_sb));
  
        cFYI(1, "Get root dentry for %s", full_path);
  
 -      xid = GetXid();
        sep = CIFS_DIR_SEP(cifs_sb);
        dentry = dget(sb->s_root);
        p = s = full_path;
                dput(dentry);
                dentry = child;
        } while (!IS_ERR(dentry));
 -      _FreeXid(xid);
        kfree(full_path);
        return dentry;
  }
@@@ -730,7 -723,7 +730,7 @@@ static loff_t cifs_llseek(struct file *
                if (rc < 0)
                        return (loff_t)rc;
        }
-       return generic_file_llseek_unlocked(file, offset, origin);
+       return generic_file_llseek(file, offset, origin);
  }
  
  static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
@@@ -949,8 -942,7 +949,8 @@@ cifs_init_once(void *inode
        struct cifsInodeInfo *cifsi = inode;
  
        inode_init_once(&cifsi->vfs_inode);
 -      INIT_LIST_HEAD(&cifsi->lockList);
 +      INIT_LIST_HEAD(&cifsi->llist);
 +      mutex_init(&cifsi->lock_mutex);
  }
  
  static int
diff --combined fs/compat.c
@@@ -37,6 -37,7 +37,6 @@@
  #include <linux/dirent.h>
  #include <linux/fsnotify.h>
  #include <linux/highuid.h>
 -#include <linux/nfsd/syscall.h>
  #include <linux/personality.h>
  #include <linux/rwsem.h>
  #include <linux/tsacct_kern.h>
@@@ -246,11 -247,8 +246,8 @@@ static int put_compat_statfs(struct com
            __put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) ||
            __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) ||
            __put_user(kbuf->f_frsize, &ubuf->f_frsize) ||
-           __put_user(0, &ubuf->f_spare[0]) || 
-           __put_user(0, &ubuf->f_spare[1]) || 
-           __put_user(0, &ubuf->f_spare[2]) || 
-           __put_user(0, &ubuf->f_spare[3]) || 
-           __put_user(0, &ubuf->f_spare[4]))
+           __put_user(kbuf->f_flags, &ubuf->f_flags) ||
+           __clear_user(ubuf->f_spare, sizeof(ubuf->f_spare)))
                return -EFAULT;
        return 0;
  }
diff --combined fs/gfs2/file.c
@@@ -59,24 -59,15 +59,24 @@@ static loff_t gfs2_llseek(struct file *
        struct gfs2_holder i_gh;
        loff_t error;
  
 -      if (origin == 2) {
 +      switch (origin) {
 +      case SEEK_END: /* These reference inode->i_size */
 +      case SEEK_DATA:
 +      case SEEK_HOLE:
                error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY,
                                           &i_gh);
                if (!error) {
-                       error = generic_file_llseek_unlocked(file, offset, origin);
+                       error = generic_file_llseek(file, offset, origin);
                        gfs2_glock_dq_uninit(&i_gh);
                }
 -      } else
 +              break;
 +      case SEEK_CUR:
 +      case SEEK_SET:
-               error = generic_file_llseek_unlocked(file, offset, origin);
+               error = generic_file_llseek(file, offset, origin);
 +              break;
 +      default:
 +              error = -EINVAL;
 +      }
  
        return error;
  }
@@@ -366,15 -357,8 +366,15 @@@ static int gfs2_page_mkwrite(struct vm_
        unsigned int data_blocks, ind_blocks, rblocks;
        struct gfs2_holder gh;
        struct gfs2_alloc *al;
 +      loff_t size;
        int ret;
  
 +      /* Wait if fs is frozen. This is racy so we check again later on
 +       * and retry if the fs has been frozen after the page lock has
 +       * been acquired
 +       */
 +      vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE);
 +
        gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
        ret = gfs2_glock_nq(&gh);
        if (ret)
        set_bit(GLF_DIRTY, &ip->i_gl->gl_flags);
        set_bit(GIF_SW_PAGED, &ip->i_flags);
  
 -      if (!gfs2_write_alloc_required(ip, pos, PAGE_CACHE_SIZE))
 +      if (!gfs2_write_alloc_required(ip, pos, PAGE_CACHE_SIZE)) {
 +              lock_page(page);
 +              if (!PageUptodate(page) || page->mapping != inode->i_mapping) {
 +                      ret = -EAGAIN;
 +                      unlock_page(page);
 +              }
                goto out_unlock;
 +      }
 +
        ret = -ENOMEM;
        al = gfs2_alloc_get(ip);
        if (al == NULL)
                rblocks += data_blocks ? data_blocks : 1;
        if (ind_blocks || data_blocks) {
                rblocks += RES_STATFS + RES_QUOTA;
 -              rblocks += gfs2_rg_blocks(al);
 +              rblocks += gfs2_rg_blocks(ip);
        }
        ret = gfs2_trans_begin(sdp, rblocks, 0);
        if (ret)
  
        lock_page(page);
        ret = -EINVAL;
 -      last_index = ip->i_inode.i_size >> PAGE_CACHE_SHIFT;
 -      if (page->index > last_index)
 -              goto out_unlock_page;
 +      size = i_size_read(inode);
 +      last_index = (size - 1) >> PAGE_CACHE_SHIFT;
 +      /* Check page index against inode size */
 +      if (size == 0 || (page->index > last_index))
 +              goto out_trans_end;
 +
 +      ret = -EAGAIN;
 +      /* If truncated, we must retry the operation, we may have raced
 +       * with the glock demotion code.
 +       */
 +      if (!PageUptodate(page) || page->mapping != inode->i_mapping)
 +              goto out_trans_end;
 +
 +      /* Unstuff, if required, and allocate backing blocks for page */
        ret = 0;
 -      if (!PageUptodate(page) || page->mapping != ip->i_inode.i_mapping)
 -              goto out_unlock_page;
 -      if (gfs2_is_stuffed(ip)) {
 +      if (gfs2_is_stuffed(ip))
                ret = gfs2_unstuff_dinode(ip, page);
 -              if (ret)
 -                      goto out_unlock_page;
 -      }
 -      ret = gfs2_allocate_page_backing(page);
 +      if (ret == 0)
 +              ret = gfs2_allocate_page_backing(page);
  
 -out_unlock_page:
 -      unlock_page(page);
 +out_trans_end:
 +      if (ret)
 +              unlock_page(page);
        gfs2_trans_end(sdp);
  out_trans_fail:
        gfs2_inplace_release(ip);
@@@ -453,17 -422,11 +453,17 @@@ out_unlock
        gfs2_glock_dq(&gh);
  out:
        gfs2_holder_uninit(&gh);
 -      if (ret == -ENOMEM)
 -              ret = VM_FAULT_OOM;
 -      else if (ret)
 -              ret = VM_FAULT_SIGBUS;
 -      return ret;
 +      if (ret == 0) {
 +              set_page_dirty(page);
 +              /* This check must be post dropping of transaction lock */
 +              if (inode->i_sb->s_frozen == SB_UNFROZEN) {
 +                      wait_on_page_writeback(page);
 +              } else {
 +                      ret = -EAGAIN;
 +                      unlock_page(page);
 +              }
 +      }
 +      return block_page_mkwrite_return(ret);
  }
  
  static const struct vm_operations_struct gfs2_vm_ops = {
@@@ -588,16 -551,8 +588,16 @@@ static int gfs2_close(struct inode *ino
   * @end: the end position in the file to sync
   * @datasync: set if we can ignore timestamp changes
   *
 - * The VFS will flush data for us. We only need to worry
 - * about metadata here.
 + * We split the data flushing here so that we don't wait for the data
 + * until after we've also sent the metadata to disk. Note that for
 + * data=ordered, we will write & wait for the data at the log flush
 + * stage anyway, so this is unlikely to make much of a difference
 + * except in the data=writeback case.
 + *
 + * If the fdatawrite fails due to any reason except -EIO, we will
 + * continue the remainder of the fsync, although we'll still report
 + * the error at the end. This is to match filemap_write_and_wait_range()
 + * behaviour.
   *
   * Returns: errno
   */
  static int gfs2_fsync(struct file *file, loff_t start, loff_t end,
                      int datasync)
  {
 -      struct inode *inode = file->f_mapping->host;
 +      struct address_space *mapping = file->f_mapping;
 +      struct inode *inode = mapping->host;
        int sync_state = inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC);
        struct gfs2_inode *ip = GFS2_I(inode);
 -      int ret;
 +      int ret, ret1 = 0;
  
 -      ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
 -      if (ret)
 -              return ret;
 -      mutex_lock(&inode->i_mutex);
 +      if (mapping->nrpages) {
 +              ret1 = filemap_fdatawrite_range(mapping, start, end);
 +              if (ret1 == -EIO)
 +                      return ret1;
 +      }
  
        if (datasync)
                sync_state &= ~I_DIRTY_SYNC;
  
        if (sync_state) {
                ret = sync_inode_metadata(inode, 1);
 -              if (ret) {
 -                      mutex_unlock(&inode->i_mutex);
 +              if (ret)
                        return ret;
 -              }
 -              gfs2_ail_flush(ip->i_gl);
 +              if (gfs2_is_jdata(ip))
 +                      filemap_write_and_wait(mapping);
 +              gfs2_ail_flush(ip->i_gl, 1);
        }
  
 -      mutex_unlock(&inode->i_mutex);
 -      return 0;
 +      if (mapping->nrpages)
 +              ret = filemap_fdatawait_range(mapping, start, end);
 +
 +      return ret ? ret : ret1;
  }
  
  /**
@@@ -669,18 -620,135 +669,18 @@@ static ssize_t gfs2_file_aio_write(stru
        return generic_file_aio_write(iocb, iov, nr_segs, pos);
  }
  
 -static int empty_write_end(struct page *page, unsigned from,
 -                         unsigned to, int mode)
 -{
 -      struct inode *inode = page->mapping->host;
 -      struct gfs2_inode *ip = GFS2_I(inode);
 -      struct buffer_head *bh;
 -      unsigned offset, blksize = 1 << inode->i_blkbits;
 -      pgoff_t end_index = i_size_read(inode) >> PAGE_CACHE_SHIFT;
 -
 -      zero_user(page, from, to-from);
 -      mark_page_accessed(page);
 -
 -      if (page->index < end_index || !(mode & FALLOC_FL_KEEP_SIZE)) {
 -              if (!gfs2_is_writeback(ip))
 -                      gfs2_page_add_databufs(ip, page, from, to);
 -
 -              block_commit_write(page, from, to);
 -              return 0;
 -      }
 -
 -      offset = 0;
 -      bh = page_buffers(page);
 -      while (offset < to) {
 -              if (offset >= from) {
 -                      set_buffer_uptodate(bh);
 -                      mark_buffer_dirty(bh);
 -                      clear_buffer_new(bh);
 -                      write_dirty_buffer(bh, WRITE);
 -              }
 -              offset += blksize;
 -              bh = bh->b_this_page;
 -      }
 -
 -      offset = 0;
 -      bh = page_buffers(page);
 -      while (offset < to) {
 -              if (offset >= from) {
 -                      wait_on_buffer(bh);
 -                      if (!buffer_uptodate(bh))
 -                              return -EIO;
 -              }
 -              offset += blksize;
 -              bh = bh->b_this_page;
 -      }
 -      return 0;
 -}
 -
 -static int needs_empty_write(sector_t block, struct inode *inode)
 -{
 -      int error;
 -      struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 };
 -
 -      bh_map.b_size = 1 << inode->i_blkbits;
 -      error = gfs2_block_map(inode, block, &bh_map, 0);
 -      if (unlikely(error))
 -              return error;
 -      return !buffer_mapped(&bh_map);
 -}
 -
 -static int write_empty_blocks(struct page *page, unsigned from, unsigned to,
 -                            int mode)
 -{
 -      struct inode *inode = page->mapping->host;
 -      unsigned start, end, next, blksize;
 -      sector_t block = page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
 -      int ret;
 -
 -      blksize = 1 << inode->i_blkbits;
 -      next = end = 0;
 -      while (next < from) {
 -              next += blksize;
 -              block++;
 -      }
 -      start = next;
 -      do {
 -              next += blksize;
 -              ret = needs_empty_write(block, inode);
 -              if (unlikely(ret < 0))
 -                      return ret;
 -              if (ret == 0) {
 -                      if (end) {
 -                              ret = __block_write_begin(page, start, end - start,
 -                                                        gfs2_block_map);
 -                              if (unlikely(ret))
 -                                      return ret;
 -                              ret = empty_write_end(page, start, end, mode);
 -                              if (unlikely(ret))
 -                                      return ret;
 -                              end = 0;
 -                      }
 -                      start = next;
 -              }
 -              else
 -                      end = next;
 -              block++;
 -      } while (next < to);
 -
 -      if (end) {
 -              ret = __block_write_begin(page, start, end - start, gfs2_block_map);
 -              if (unlikely(ret))
 -                      return ret;
 -              ret = empty_write_end(page, start, end, mode);
 -              if (unlikely(ret))
 -                      return ret;
 -      }
 -
 -      return 0;
 -}
 -
  static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,
                           int mode)
  {
        struct gfs2_inode *ip = GFS2_I(inode);
        struct buffer_head *dibh;
        int error;
 -      u64 start = offset >> PAGE_CACHE_SHIFT;
 -      unsigned int start_offset = offset & ~PAGE_CACHE_MASK;
 -      u64 end = (offset + len - 1) >> PAGE_CACHE_SHIFT;
 -      pgoff_t curr;
 -      struct page *page;
 -      unsigned int end_offset = (offset + len) & ~PAGE_CACHE_MASK;
 -      unsigned int from, to;
 -
 -      if (!end_offset)
 -              end_offset = PAGE_CACHE_SIZE;
 +      unsigned int nr_blks;
 +      sector_t lblock = offset >> inode->i_blkbits;
  
        error = gfs2_meta_inode_buffer(ip, &dibh);
        if (unlikely(error))
 -              goto out;
 +              return error;
  
        gfs2_trans_add_bh(ip->i_gl, dibh, 1);
  
                        goto out;
        }
  
 -      curr = start;
 -      offset = start << PAGE_CACHE_SHIFT;
 -      from = start_offset;
 -      to = PAGE_CACHE_SIZE;
 -      while (curr <= end) {
 -              page = grab_cache_page_write_begin(inode->i_mapping, curr,
 -                                                 AOP_FLAG_NOFS);
 -              if (unlikely(!page)) {
 -                      error = -ENOMEM;
 -                      goto out;
 -              }
 +      while (len) {
 +              struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 };
 +              bh_map.b_size = len;
 +              set_buffer_zeronew(&bh_map);
  
 -              if (curr == end)
 -                      to = end_offset;
 -              error = write_empty_blocks(page, from, to, mode);
 -              if (!error && offset + to > inode->i_size &&
 -                  !(mode & FALLOC_FL_KEEP_SIZE)) {
 -                      i_size_write(inode, offset + to);
 -              }
 -              unlock_page(page);
 -              page_cache_release(page);
 -              if (error)
 +              error = gfs2_block_map(inode, lblock, &bh_map, 1);
 +              if (unlikely(error))
                        goto out;
 -              curr++;
 -              offset += PAGE_CACHE_SIZE;
 -              from = 0;
 +              len -= bh_map.b_size;
 +              nr_blks = bh_map.b_size >> inode->i_blkbits;
 +              lblock += nr_blks;
 +              if (!buffer_new(&bh_map))
 +                      continue;
 +              if (unlikely(!buffer_zeronew(&bh_map))) {
 +                      error = -EIO;
 +                      goto out;
 +              }
        }
 +      if (offset + len > inode->i_size && !(mode & FALLOC_FL_KEEP_SIZE))
 +              i_size_write(inode, offset + len);
  
 -      gfs2_dinode_out(ip, dibh->b_data);
        mark_inode_dirty(inode);
  
 -      brelse(dibh);
 -
  out:
 +      brelse(dibh);
        return error;
  }
  
@@@ -722,7 -799,7 +722,7 @@@ static void calc_max_reserv(struct gfs2
                            unsigned int *data_blocks, unsigned int *ind_blocks)
  {
        const struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
 -      unsigned int max_blocks = ip->i_alloc->al_rgd->rd_free_clone;
 +      unsigned int max_blocks = ip->i_rgd->rd_free_clone;
        unsigned int tmp, max_data = max_blocks - 3 * (sdp->sd_max_height - 1);
  
        for (tmp = max_data; tmp > sdp->sd_diptrs;) {
@@@ -754,7 -831,6 +754,7 @@@ static long gfs2_fallocate(struct file 
        int error;
        loff_t bsize_mask = ~((loff_t)sdp->sd_sb.sb_bsize - 1);
        loff_t next = (offset + len - 1) >> sdp->sd_sb.sb_bsize_shift;
 +      loff_t max_chunk_size = UINT_MAX & bsize_mask;
        next = (next + 1) << sdp->sd_sb.sb_bsize_shift;
  
        /* We only support the FALLOC_FL_KEEP_SIZE mode */
@@@ -808,12 -884,11 +808,12 @@@ retry
                        goto out_qunlock;
                }
                max_bytes = bytes;
 -              calc_max_reserv(ip, len, &max_bytes, &data_blocks, &ind_blocks);
 +              calc_max_reserv(ip, (len > max_chunk_size)? max_chunk_size: len,
 +                              &max_bytes, &data_blocks, &ind_blocks);
                al->al_requested = data_blocks + ind_blocks;
  
                rblocks = RES_DINODE + ind_blocks + RES_STATFS + RES_QUOTA +
 -                        RES_RG_HDR + gfs2_rg_blocks(al);
 +                        RES_RG_HDR + gfs2_rg_blocks(ip);
                if (gfs2_is_jdata(ip))
                        rblocks += data_blocks ? data_blocks : 1;
  
diff --combined include/linux/fs.h
@@@ -58,14 -58,15 +58,15 @@@ struct inodes_stat_t 
  
  #define NR_FILE  8192 /* this can well be larger on a larger system */
  
- #define MAY_EXEC 1
- #define MAY_WRITE 2
- #define MAY_READ 4
- #define MAY_APPEND 8
- #define MAY_ACCESS 16
- #define MAY_OPEN 32
- #define MAY_CHDIR 64
- #define MAY_NOT_BLOCK 128     /* called from RCU mode, don't block */
+ #define MAY_EXEC              0x00000001
+ #define MAY_WRITE             0x00000002
+ #define MAY_READ              0x00000004
+ #define MAY_APPEND            0x00000008
+ #define MAY_ACCESS            0x00000010
+ #define MAY_OPEN              0x00000020
+ #define MAY_CHDIR             0x00000040
+ /* called from RCU mode, don't block */
+ #define MAY_NOT_BLOCK         0x00000080
  
  /*
   * flags in file.f_mode.  Note that FMODE_READ and FMODE_WRITE must correspond
@@@ -963,7 -964,12 +964,12 @@@ struct file 
  #define f_dentry      f_path.dentry
  #define f_vfsmnt      f_path.mnt
        const struct file_operations    *f_op;
-       spinlock_t              f_lock;  /* f_ep_links, f_flags, no IRQ */
+       /*
+        * Protects f_ep_links, f_flags, f_pos vs i_size in lseek SEEK_CUR.
+        * Must not be taken from IRQ context.
+        */
+       spinlock_t              f_lock;
  #ifdef CONFIG_SMP
        int                     f_sb_list_cpu;
  #endif
@@@ -1063,8 -1069,6 +1069,8 @@@ static inline int file_check_writeable(
  #define FL_LEASE      32      /* lease held on this file */
  #define FL_CLOSE      64      /* unlock on close */
  #define FL_SLEEP      128     /* A blocking lock */
 +#define FL_DOWNGRADE_PENDING  256 /* Lease is being downgraded */
 +#define FL_UNLOCK_PENDING     512 /* Lease is being broken */
  
  /*
   * Special return value from posix_lock_file() and vfs_lock_file() for
@@@ -1111,7 -1115,7 +1117,7 @@@ struct file_lock 
        struct list_head fl_link;       /* doubly linked list of all locks */
        struct list_head fl_block;      /* circular list of blocked processes */
        fl_owner_t fl_owner;
 -      unsigned char fl_flags;
 +      unsigned int fl_flags;
        unsigned char fl_type;
        unsigned int fl_pid;
        struct pid *fl_nspid;
        loff_t fl_end;
  
        struct fasync_struct *  fl_fasync; /* for lease break notifications */
 -      unsigned long fl_break_time;    /* for nonblocking lease breaks */
 +      /* for lease breaks: */
 +      unsigned long fl_break_time;
 +      unsigned long fl_downgrade_time;
  
        const struct file_lock_operations *fl_ops;      /* Callbacks for filesystems */
        const struct lock_manager_operations *fl_lmops; /* Callbacks for lockmanagers */
@@@ -2401,8 -2403,8 +2407,8 @@@ file_ra_state_init(struct file_ra_stat
  extern loff_t noop_llseek(struct file *file, loff_t offset, int origin);
  extern loff_t no_llseek(struct file *file, loff_t offset, int origin);
  extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin);
- extern loff_t generic_file_llseek_unlocked(struct file *file, loff_t offset,
-                       int origin);
+ extern loff_t generic_file_llseek_size(struct file *file, loff_t offset,
+               int origin, loff_t maxsize);
  extern int generic_file_open(struct inode * inode, struct file * filp);
  extern int nonseekable_open(struct inode * inode, struct file * filp);