vfs: do (nearly) lockless generic_file_llseek
[linux-2.6.git] / fs / gfs2 / file.c
index 23eab47..fe6bc02 100644 (file)
@@ -63,11 +63,11 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin)
                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
-               error = generic_file_llseek_unlocked(file, offset, origin);
+               error = generic_file_llseek(file, offset, origin);
 
        return error;
 }
@@ -174,7 +174,9 @@ void gfs2_set_inode_flags(struct inode *inode)
        struct gfs2_inode *ip = GFS2_I(inode);
        unsigned int flags = inode->i_flags;
 
-       flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC);
+       flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC|S_NOSEC);
+       if ((ip->i_eattr == 0) && !is_sxid(inode->i_mode))
+               inode->i_flags |= S_NOSEC;
        if (ip->i_diskflags & GFS2_DIF_IMMUTABLE)
                flags |= S_IMMUTABLE;
        if (ip->i_diskflags & GFS2_DIF_APPENDONLY)
@@ -243,7 +245,7 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
            !capable(CAP_LINUX_IMMUTABLE))
                goto out;
        if (!IS_IMMUTABLE(inode)) {
-               error = gfs2_permission(inode, MAY_WRITE, 0);
+               error = gfs2_permission(inode, MAY_WRITE);
                if (error)
                        goto out;
        }
@@ -544,7 +546,9 @@ static int gfs2_close(struct inode *inode, struct file *file)
 
 /**
  * gfs2_fsync - sync the dirty data for a file (across the cluster)
- * @file: the file that points to the dentry (we ignore this)
+ * @file: the file that points to the dentry
+ * @start: the start position in the file to sync
+ * @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
@@ -553,23 +557,32 @@ static int gfs2_close(struct inode *inode, struct file *file)
  * Returns: errno
  */
 
-static int gfs2_fsync(struct file *file, int datasync)
+static int gfs2_fsync(struct file *file, loff_t start, loff_t end,
+                     int datasync)
 {
        struct inode *inode = file->f_mapping->host;
        int sync_state = inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC);
        struct gfs2_inode *ip = GFS2_I(inode);
        int ret;
 
+       ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (ret)
+               return ret;
+       mutex_lock(&inode->i_mutex);
+
        if (datasync)
                sync_state &= ~I_DIRTY_SYNC;
 
        if (sync_state) {
                ret = sync_inode_metadata(inode, 1);
-               if (ret)
+               if (ret) {
+                       mutex_unlock(&inode->i_mutex);
                        return ret;
+               }
                gfs2_ail_flush(ip->i_gl);
        }
 
+       mutex_unlock(&inode->i_mutex);
        return 0;
 }
 
@@ -816,6 +829,7 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset,
        loff_t bytes, max_bytes;
        struct gfs2_alloc *al;
        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;
        next = (next + 1) << sdp->sd_sb.sb_bsize_shift;
 
@@ -823,13 +837,15 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset,
        if (mode & ~FALLOC_FL_KEEP_SIZE)
                return -EOPNOTSUPP;
 
-       offset = (offset >> sdp->sd_sb.sb_bsize_shift) <<
-                sdp->sd_sb.sb_bsize_shift;
+       offset &= bsize_mask;
 
        len = next - offset;
        bytes = sdp->sd_max_rg_data * sdp->sd_sb.sb_bsize / 2;
        if (!bytes)
                bytes = UINT_MAX;
+       bytes &= bsize_mask;
+       if (bytes == 0)
+               bytes = sdp->sd_sb.sb_bsize;
 
        gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &ip->i_gh);
        error = gfs2_glock_nq(&ip->i_gh);
@@ -860,6 +876,9 @@ retry:
                if (error) {
                        if (error == -ENOSPC && bytes > sdp->sd_sb.sb_bsize) {
                                bytes >>= 1;
+                               bytes &= bsize_mask;
+                               if (bytes == 0)
+                                       bytes = sdp->sd_sb.sb_bsize;
                                goto retry;
                        }
                        goto out_qunlock;