Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=b25801038da5823bba1b5440a57ca68afc51b6bd
Commit:     b25801038da5823bba1b5440a57ca68afc51b6bd
Parent:     063c4561f52a74de686fe0ff2f96f4f54c9fecd2
Author:     Mark Fasheh <[EMAIL PROTECTED]>
AuthorDate: Fri Mar 9 16:53:21 2007 -0800
Committer:  Mark Fasheh <[EMAIL PROTECTED]>
CommitDate: Tue Jul 10 17:32:09 2007 -0700

    ocfs2: Support xfs style space reservation ioctls
    
    We re-use the RESVSP/UNRESVSP ioctls from xfs which allow the user to
    allocate and deallocate regions to a file without zeroing data or changing
    i_size.
    
    Though renamed, the structure passed in from user is identical to struct
    xfs_flock64. The three fields that are actually used right now are l_whence,
    l_start and l_len.
    
    This should get ocfs2 immediate compatibility with userspace software using
    the pre-existing xfs ioctls.
    
    Signed-off-by: Mark Fasheh <[EMAIL PROTECTED]>
---
 fs/ocfs2/file.c     |  182 +++++++++++++++++++++++++++++++++++++++++++++++----
 fs/ocfs2/file.h     |    3 +
 fs/ocfs2/ioctl.c    |   15 ++++
 fs/ocfs2/ocfs2_fs.h |   26 +++++++
 fs/ocfs2/super.c    |    4 +-
 fs/ocfs2/super.h    |    2 +
 6 files changed, 216 insertions(+), 16 deletions(-)

diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 11f7cf9..f04c7aa 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -1111,17 +1111,16 @@ out:
        return ret;
 }
 
-static int ocfs2_write_remove_suid(struct inode *inode)
+static int __ocfs2_write_remove_suid(struct inode *inode,
+                                    struct buffer_head *bh)
 {
        int ret;
-       struct buffer_head *bh = NULL;
-       struct ocfs2_inode_info *oi = OCFS2_I(inode);
        handle_t *handle;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
        struct ocfs2_dinode *di;
 
        mlog_entry("(Inode %llu, mode 0%o)\n",
-                  (unsigned long long)oi->ip_blkno, inode->i_mode);
+                  (unsigned long long)OCFS2_I(inode)->ip_blkno, inode->i_mode);
 
        handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
        if (handle == NULL) {
@@ -1130,17 +1129,11 @@ static int ocfs2_write_remove_suid(struct inode *inode)
                goto out;
        }
 
-       ret = ocfs2_read_block(osb, oi->ip_blkno, &bh, OCFS2_BH_CACHED, inode);
-       if (ret < 0) {
-               mlog_errno(ret);
-               goto out_trans;
-       }
-
        ret = ocfs2_journal_access(handle, inode, bh,
                                   OCFS2_JOURNAL_ACCESS_WRITE);
        if (ret < 0) {
                mlog_errno(ret);
-               goto out_bh;
+               goto out_trans;
        }
 
        inode->i_mode &= ~S_ISUID;
@@ -1153,8 +1146,7 @@ static int ocfs2_write_remove_suid(struct inode *inode)
        ret = ocfs2_journal_dirty(handle, bh);
        if (ret < 0)
                mlog_errno(ret);
-out_bh:
-       brelse(bh);
+
 out_trans:
        ocfs2_commit_trans(osb, handle);
 out:
@@ -1200,6 +1192,25 @@ out:
        return ret;
 }
 
+static int ocfs2_write_remove_suid(struct inode *inode)
+{
+       int ret;
+       struct buffer_head *bh = NULL;
+       struct ocfs2_inode_info *oi = OCFS2_I(inode);
+
+       ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
+                              oi->ip_blkno, &bh, OCFS2_BH_CACHED, inode);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       ret =  __ocfs2_write_remove_suid(inode, bh);
+out:
+       brelse(bh);
+       return ret;
+}
+
 /*
  * Allocate enough extents to cover the region starting at byte offset
  * start for len bytes. Existing extents are skipped, any extents
@@ -1490,6 +1501,151 @@ out:
        return ret;
 }
 
+/*
+ * Parts of this function taken from xfs_change_file_space()
+ */
+int ocfs2_change_file_space(struct file *file, unsigned int cmd,
+                           struct ocfs2_space_resv *sr)
+{
+       int ret;
+       s64 llen;
+       struct inode *inode = file->f_path.dentry->d_inode;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       struct buffer_head *di_bh = NULL;
+       handle_t *handle;
+       unsigned long long max_off = 
ocfs2_max_file_offset(inode->i_sb->s_blocksize_bits);
+
+       if ((cmd == OCFS2_IOC_RESVSP || cmd == OCFS2_IOC_RESVSP64) &&
+           !ocfs2_writes_unwritten_extents(osb))
+               return -ENOTTY;
+       else if ((cmd == OCFS2_IOC_UNRESVSP || cmd == OCFS2_IOC_UNRESVSP64) &&
+                !ocfs2_sparse_alloc(osb))
+               return -ENOTTY;
+
+       if (!S_ISREG(inode->i_mode))
+               return -EINVAL;
+
+       if (!(file->f_mode & FMODE_WRITE))
+               return -EBADF;
+
+       if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb))
+               return -EROFS;
+
+       mutex_lock(&inode->i_mutex);
+
+       /*
+        * This prevents concurrent writes on other nodes
+        */
+       ret = ocfs2_rw_lock(inode, 1);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       ret = ocfs2_meta_lock(inode, &di_bh, 1);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_rw_unlock;
+       }
+
+       if (inode->i_flags & (S_IMMUTABLE|S_APPEND)) {
+               ret = -EPERM;
+               goto out_meta_unlock;
+       }
+
+       switch (sr->l_whence) {
+       case 0: /*SEEK_SET*/
+               break;
+       case 1: /*SEEK_CUR*/
+               sr->l_start += file->f_pos;
+               break;
+       case 2: /*SEEK_END*/
+               sr->l_start += i_size_read(inode);
+               break;
+       default:
+               ret = -EINVAL;
+               goto out_meta_unlock;
+       }
+       sr->l_whence = 0;
+
+       llen = sr->l_len > 0 ? sr->l_len - 1 : sr->l_len;
+
+       if (sr->l_start < 0
+           || sr->l_start > max_off
+           || (sr->l_start + llen) < 0
+           || (sr->l_start + llen) > max_off) {
+               ret = -EINVAL;
+               goto out_meta_unlock;
+       }
+
+       if (cmd == OCFS2_IOC_RESVSP || cmd == OCFS2_IOC_RESVSP64) {
+               if (sr->l_len <= 0) {
+                       ret = -EINVAL;
+                       goto out_meta_unlock;
+               }
+       }
+
+       if (should_remove_suid(file->f_path.dentry)) {
+               ret = __ocfs2_write_remove_suid(inode, di_bh);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out_meta_unlock;
+               }
+       }
+
+       down_write(&OCFS2_I(inode)->ip_alloc_sem);
+       switch (cmd) {
+       case OCFS2_IOC_RESVSP:
+       case OCFS2_IOC_RESVSP64:
+               /*
+                * This takes unsigned offsets, but the signed ones we
+                * pass have been checked against overflow above.
+                */
+               ret = ocfs2_allocate_unwritten_extents(inode, sr->l_start,
+                                                      sr->l_len);
+               break;
+       case OCFS2_IOC_UNRESVSP:
+       case OCFS2_IOC_UNRESVSP64:
+               ret = ocfs2_remove_inode_range(inode, di_bh, sr->l_start,
+                                              sr->l_len);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       up_write(&OCFS2_I(inode)->ip_alloc_sem);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_meta_unlock;
+       }
+
+       /*
+        * We update c/mtime for these changes
+        */
+       handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               mlog_errno(ret);
+               goto out_meta_unlock;
+       }
+
+       inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+       ret = ocfs2_mark_inode_dirty(handle, inode, di_bh);
+       if (ret < 0)
+               mlog_errno(ret);
+
+       ocfs2_commit_trans(osb, handle);
+
+out_meta_unlock:
+       brelse(di_bh);
+       ocfs2_meta_unlock(inode, 1);
+out_rw_unlock:
+       ocfs2_rw_unlock(inode, 1);
+
+       mutex_unlock(&inode->i_mutex);
+out:
+       return ret;
+}
+
 static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
                                         loff_t *ppos,
                                         size_t count,
diff --git a/fs/ocfs2/file.h b/fs/ocfs2/file.h
index 79115c9..36fe27f 100644
--- a/fs/ocfs2/file.h
+++ b/fs/ocfs2/file.h
@@ -62,4 +62,7 @@ int ocfs2_should_update_atime(struct inode *inode,
 int ocfs2_update_inode_atime(struct inode *inode,
                             struct buffer_head *bh);
 
+int ocfs2_change_file_space(struct file *file, unsigned int cmd,
+                           struct ocfs2_space_resv *sr);
+
 #endif /* OCFS2_FILE_H */
diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c
index f3ad21a..bd68c3f 100644
--- a/fs/ocfs2/ioctl.c
+++ b/fs/ocfs2/ioctl.c
@@ -14,6 +14,7 @@
 #include "ocfs2.h"
 #include "alloc.h"
 #include "dlmglue.h"
+#include "file.h"
 #include "inode.h"
 #include "journal.h"
 
@@ -115,6 +116,7 @@ int ocfs2_ioctl(struct inode * inode, struct file * filp,
 {
        unsigned int flags;
        int status;
+       struct ocfs2_space_resv sr;
 
        switch (cmd) {
        case OCFS2_IOC_GETFLAGS:
@@ -130,6 +132,14 @@ int ocfs2_ioctl(struct inode * inode, struct file * filp,
 
                return ocfs2_set_inode_attr(inode, flags,
                        OCFS2_FL_MODIFIABLE);
+       case OCFS2_IOC_RESVSP:
+       case OCFS2_IOC_RESVSP64:
+       case OCFS2_IOC_UNRESVSP:
+       case OCFS2_IOC_UNRESVSP64:
+               if (copy_from_user(&sr, (int __user *) arg, sizeof(sr)))
+                       return -EFAULT;
+
+               return ocfs2_change_file_space(filp, cmd, &sr);
        default:
                return -ENOTTY;
        }
@@ -148,6 +158,11 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, 
unsigned long arg)
        case OCFS2_IOC32_SETFLAGS:
                cmd = OCFS2_IOC_SETFLAGS;
                break;
+       case OCFS2_IOC_RESVSP:
+       case OCFS2_IOC_RESVSP64:
+       case OCFS2_IOC_UNRESVSP:
+       case OCFS2_IOC_UNRESVSP64:
+               break;
        default:
                return -ENOIOCTLCMD;
        }
diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h
index c20a74b..82f8a75 100644
--- a/fs/ocfs2/ocfs2_fs.h
+++ b/fs/ocfs2/ocfs2_fs.h
@@ -175,6 +175,32 @@
 #define OCFS2_IOC32_SETFLAGS   _IOW('f', 2, int)
 
 /*
+ * Space reservation / allocation / free ioctls and argument structure
+ * are designed to be compatible with XFS.
+ *
+ * ALLOCSP* and FREESP* are not and will never be supported, but are
+ * included here for completeness.
+ */
+struct ocfs2_space_resv {
+       __s16           l_type;
+       __s16           l_whence;
+       __s64           l_start;
+       __s64           l_len;          /* len == 0 means until end of file */
+       __s32           l_sysid;
+       __u32           l_pid;
+       __s32           l_pad[4];       /* reserve area                     */
+};
+
+#define OCFS2_IOC_ALLOCSP              _IOW ('X', 10, struct ocfs2_space_resv)
+#define OCFS2_IOC_FREESP               _IOW ('X', 11, struct ocfs2_space_resv)
+#define OCFS2_IOC_RESVSP               _IOW ('X', 40, struct ocfs2_space_resv)
+#define OCFS2_IOC_UNRESVSP     _IOW ('X', 41, struct ocfs2_space_resv)
+#define OCFS2_IOC_ALLOCSP64    _IOW ('X', 36, struct ocfs2_space_resv)
+#define OCFS2_IOC_FREESP64     _IOW ('X', 37, struct ocfs2_space_resv)
+#define OCFS2_IOC_RESVSP64     _IOW ('X', 42, struct ocfs2_space_resv)
+#define OCFS2_IOC_UNRESVSP64   _IOW ('X', 43, struct ocfs2_space_resv)
+
+/*
  * Journal Flags (ocfs2_dinode.id1.journal1.i_flags)
  */
 #define OCFS2_JOURNAL_DIRTY_FL (0x00000001)    /* Journal needs recovery */
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index f07718a..3a5a1ed 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -115,8 +115,6 @@ static void ocfs2_write_super(struct super_block *sb);
 static struct inode *ocfs2_alloc_inode(struct super_block *sb);
 static void ocfs2_destroy_inode(struct inode *inode);
 
-static unsigned long long ocfs2_max_file_offset(unsigned int blockshift);
-
 static const struct super_operations ocfs2_sops = {
        .statfs         = ocfs2_statfs,
        .alloc_inode    = ocfs2_alloc_inode,
@@ -321,7 +319,7 @@ static void ocfs2_destroy_inode(struct inode *inode)
 /* From xfs_super.c:xfs_max_file_offset
  * Copyright (c) 2000-2004 Silicon Graphics, Inc.
  */
-static unsigned long long ocfs2_max_file_offset(unsigned int blockshift)
+unsigned long long ocfs2_max_file_offset(unsigned int blockshift)
 {
        unsigned int pagefactor = 1;
        unsigned int bitshift = BITS_PER_LONG - 1;
diff --git a/fs/ocfs2/super.h b/fs/ocfs2/super.h
index 783f527..3b9cb3d 100644
--- a/fs/ocfs2/super.h
+++ b/fs/ocfs2/super.h
@@ -45,4 +45,6 @@ void __ocfs2_abort(struct super_block *sb,
 
 #define ocfs2_abort(sb, fmt, args...) __ocfs2_abort(sb, __PRETTY_FUNCTION__, 
fmt, ##args)
 
+unsigned long long ocfs2_max_file_offset(unsigned int blockshift);
+
 #endif /* OCFS2_SUPER_H */
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to