]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/ocfs2/file.c
ocfs2: pass ocfs2_super * into ocfs2_commit_trans()
[karo-tx-linux.git] / fs / ocfs2 / file.c
index 20fffeed630b4c1cd437742ad900205718a80b13..9eb60f21968dbf2b357ba882315fa12a3c3bbbc2 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
 #include <linux/uio.h>
+#include <linux/sched.h>
 
 #define MLOG_MASK_PREFIX ML_INODE
 #include <cluster/masklog.h>
@@ -44,6 +45,7 @@
 #include "file.h"
 #include "sysfile.h"
 #include "inode.h"
+#include "ioctl.h"
 #include "journal.h"
 #include "mmap.h"
 #include "suballoc.h"
@@ -176,7 +178,7 @@ static int ocfs2_simple_size_update(struct inode *inode,
        if (ret < 0)
                mlog_errno(ret);
 
-       ocfs2_commit_trans(handle);
+       ocfs2_commit_trans(osb, handle);
 out:
        return ret;
 }
@@ -205,7 +207,7 @@ static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb,
        if (status < 0)
                mlog_errno(status);
 
-       ocfs2_commit_trans(handle);
+       ocfs2_commit_trans(osb, handle);
 out:
        mlog_exit(status);
        return status;
@@ -461,13 +463,6 @@ restart_all:
             (unsigned long long)OCFS2_I(inode)->ip_blkno, i_size_read(inode),
             fe->i_clusters, clusters_to_add);
 
-       handle = ocfs2_alloc_handle(osb);
-       if (handle == NULL) {
-               status = -ENOMEM;
-               mlog_errno(status);
-               goto leave;
-       }
-
        num_free_extents = ocfs2_num_free_extents(osb,
                                                  inode,
                                                  fe);
@@ -478,10 +473,7 @@ restart_all:
        }
 
        if (!num_free_extents) {
-               status = ocfs2_reserve_new_metadata(osb,
-                                                   handle,
-                                                   fe,
-                                                   &meta_ac);
+               status = ocfs2_reserve_new_metadata(osb, fe, &meta_ac);
                if (status < 0) {
                        if (status != -ENOSPC)
                                mlog_errno(status);
@@ -489,10 +481,7 @@ restart_all:
                }
        }
 
-       status = ocfs2_reserve_clusters(osb,
-                                       handle,
-                                       clusters_to_add,
-                                       &data_ac);
+       status = ocfs2_reserve_clusters(osb, clusters_to_add, &data_ac);
        if (status < 0) {
                if (status != -ENOSPC)
                        mlog_errno(status);
@@ -507,7 +496,7 @@ restart_all:
        drop_alloc_sem = 1;
 
        credits = ocfs2_calc_extend_credits(osb->sb, fe, clusters_to_add);
-       handle = ocfs2_start_trans(osb, handle, credits);
+       handle = ocfs2_start_trans(osb, NULL, credits);
        if (IS_ERR(handle)) {
                status = PTR_ERR(handle);
                handle = NULL;
@@ -564,7 +553,7 @@ restarted_transaction:
                        credits = ocfs2_calc_extend_credits(osb->sb,
                                                            fe,
                                                            clusters_to_add);
-                       status = ocfs2_extend_trans(handle, credits);
+                       status = ocfs2_extend_trans(handle->k_handle, credits);
                        if (status < 0) {
                                /* handle still has to be committed at
                                 * this point. */
@@ -587,7 +576,7 @@ leave:
                drop_alloc_sem = 0;
        }
        if (handle) {
-               ocfs2_commit_trans(handle);
+               ocfs2_commit_trans(osb, handle);
                handle = NULL;
        }
        if (data_ac) {
@@ -666,7 +655,7 @@ static int ocfs2_write_zero_page(struct inode *inode,
                ret = 0;
 
        if (handle)
-               ocfs2_commit_trans(handle);
+               ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
 out_unlock:
        unlock_page(page);
        page_cache_release(page);
@@ -690,6 +679,12 @@ static int ocfs2_zero_extend(struct inode *inode,
                }
 
                start_off += sb->s_blocksize;
+
+               /*
+                * Very large extends have the potential to lock up
+                * the cpu for extended periods of time.
+                */
+               cond_resched();
        }
 
 out:
@@ -727,31 +722,36 @@ static int ocfs2_extend_file(struct inode *inode,
        clusters_to_add = ocfs2_clusters_for_bytes(inode->i_sb, new_i_size) - 
                OCFS2_I(inode)->ip_clusters;
 
-       if (clusters_to_add) {
-               /* 
-                * protect the pages that ocfs2_zero_extend is going to
-                * be pulling into the page cache.. we do this before the
-                * metadata extend so that we don't get into the situation
-                * where we've extended the metadata but can't get the data
-                * lock to zero.
-                */
-               ret = ocfs2_data_lock(inode, 1);
-               if (ret < 0) {
-                       mlog_errno(ret);
-                       goto out;
-               }
+       /* 
+        * protect the pages that ocfs2_zero_extend is going to be
+        * pulling into the page cache.. we do this before the
+        * metadata extend so that we don't get into the situation
+        * where we've extended the metadata but can't get the data
+        * lock to zero.
+        */
+       ret = ocfs2_data_lock(inode, 1);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto out;
+       }
 
+       if (clusters_to_add) {
                ret = ocfs2_extend_allocation(inode, clusters_to_add);
                if (ret < 0) {
                        mlog_errno(ret);
                        goto out_unlock;
                }
+       }
 
-               ret = ocfs2_zero_extend(inode, (u64)new_i_size - tail_to_skip);
-               if (ret < 0) {
-                       mlog_errno(ret);
-                       goto out_unlock;
-               }
+       /*
+        * Call this even if we don't add any clusters to the tree. We
+        * still need to zero the area between the old i_size and the
+        * new i_size.
+        */
+       ret = ocfs2_zero_extend(inode, (u64)new_i_size - tail_to_skip);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto out_unlock;
        }
 
        if (!tail_to_skip) {
@@ -763,8 +763,7 @@ static int ocfs2_extend_file(struct inode *inode,
        }
 
 out_unlock:
-       if (clusters_to_add) /* this is the only case in which we lock */
-               ocfs2_data_unlock(inode, 1);
+       ocfs2_data_unlock(inode, 1);
 
 out:
        return ret;
@@ -813,7 +812,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
                }
        }
 
-       status = ocfs2_meta_lock(inode, NULL, &bh, 1);
+       status = ocfs2_meta_lock(inode, &bh, 1);
        if (status < 0) {
                if (status != -ENOENT)
                        mlog_errno(status);
@@ -851,7 +850,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
                mlog_errno(status);
 
 bail_commit:
-       ocfs2_commit_trans(handle);
+       ocfs2_commit_trans(osb, handle);
 bail_unlock:
        ocfs2_meta_unlock(inode, 1);
 bail_unlock_rw:
@@ -939,7 +938,7 @@ static int ocfs2_write_remove_suid(struct inode *inode)
 out_bh:
        brelse(bh);
 out_trans:
-       ocfs2_commit_trans(handle);
+       ocfs2_commit_trans(osb, handle);
 out:
        mlog_exit(ret);
        return ret;
@@ -960,25 +959,23 @@ static inline int ocfs2_write_should_remove_suid(struct inode *inode)
 }
 
 static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
-                                   const char __user *buf,
-                                   size_t count,
+                                   const struct iovec *iov,
+                                   unsigned long nr_segs,
                                    loff_t pos)
 {
-       struct iovec local_iov = { .iov_base = (void __user *)buf,
-                                  .iov_len = count };
        int ret, rw_level = -1, meta_level = -1, have_alloc_sem = 0;
        u32 clusters;
        struct file *filp = iocb->ki_filp;
        struct inode *inode = filp->f_dentry->d_inode;
        loff_t newsize, saved_pos;
 
-       mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", filp, buf,
-                  (unsigned int)count,
+       mlog_entry("(0x%p, %u, '%.*s')\n", filp,
+                  (unsigned int)nr_segs,
                   filp->f_dentry->d_name.len,
                   filp->f_dentry->d_name.name);
 
        /* happy write of zero bytes */
-       if (count == 0)
+       if (iocb->ki_left == 0)
                return 0;
 
        if (!inode) {
@@ -1009,7 +1006,7 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
         */
        meta_level = (filp->f_flags & O_APPEND) ? 1 : 0;
        for(;;) {
-               ret = ocfs2_meta_lock(inode, NULL, NULL, meta_level);
+               ret = ocfs2_meta_lock(inode, NULL, meta_level);
                if (ret < 0) {
                        meta_level = -1;
                        mlog_errno(ret);
@@ -1047,7 +1044,7 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
                } else {
                        saved_pos = iocb->ki_pos;
                }
-               newsize = count + saved_pos;
+               newsize = iocb->ki_left + saved_pos;
 
                mlog(0, "pos=%lld newsize=%lld cursize=%lld\n",
                     (long long) saved_pos, (long long) newsize,
@@ -1080,7 +1077,7 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
                if (!clusters)
                        break;
 
-               ret = ocfs2_extend_file(inode, NULL, newsize, count);
+               ret = ocfs2_extend_file(inode, NULL, newsize, iocb->ki_left);
                if (ret < 0) {
                        if (ret != -ENOSPC)
                                mlog_errno(ret);
@@ -1097,7 +1094,7 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
        /* communicate with ocfs2_dio_end_io */
        ocfs2_iocb_set_rw_locked(iocb);
 
-       ret = generic_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos);
+       ret = generic_file_aio_write_nolock(iocb, iov, nr_segs, iocb->ki_pos);
 
        /* buffered aio wouldn't have proper lock coverage today */
        BUG_ON(ret == -EIOCBQUEUED && !(filp->f_flags & O_DIRECT));
@@ -1131,16 +1128,16 @@ out:
 }
 
 static ssize_t ocfs2_file_aio_read(struct kiocb *iocb,
-                                  char __user *buf,
-                                  size_t count,
+                                  const struct iovec *iov,
+                                  unsigned long nr_segs,
                                   loff_t pos)
 {
        int ret = 0, rw_level = -1, have_alloc_sem = 0;
        struct file *filp = iocb->ki_filp;
        struct inode *inode = filp->f_dentry->d_inode;
 
-       mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", filp, buf,
-                  (unsigned int)count,
+       mlog_entry("(0x%p, %u, '%.*s')\n", filp,
+                  (unsigned int)nr_segs,
                   filp->f_dentry->d_name.len,
                   filp->f_dentry->d_name.name);
 
@@ -1168,7 +1165,23 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb,
                ocfs2_iocb_set_rw_locked(iocb);
        }
 
-       ret = generic_file_aio_read(iocb, buf, count, iocb->ki_pos);
+       /*
+        * We're fine letting folks race truncates and extending
+        * writes with read across the cluster, just like they can
+        * locally. Hence no rw_lock during read.
+        * 
+        * Take and drop the meta data lock to update inode fields
+        * like i_size. This allows the checks down below
+        * generic_file_aio_read() a chance of actually working. 
+        */
+       ret = ocfs2_meta_lock(inode, NULL, 0);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto bail;
+       }
+       ocfs2_meta_unlock(inode, 0);
+
+       ret = generic_file_aio_read(iocb, iov, nr_segs, iocb->ki_pos);
        if (ret == -EINVAL)
                mlog(ML_ERROR, "generic_file_aio_read returned -EINVAL\n");
 
@@ -1211,10 +1224,12 @@ const struct file_operations ocfs2_fops = {
        .open           = ocfs2_file_open,
        .aio_read       = ocfs2_file_aio_read,
        .aio_write      = ocfs2_file_aio_write,
+       .ioctl          = ocfs2_ioctl,
 };
 
 const struct file_operations ocfs2_dops = {
        .read           = generic_read_dir,
        .readdir        = ocfs2_readdir,
        .fsync          = ocfs2_sync_file,
+       .ioctl          = ocfs2_ioctl,
 };