staging: android/ram_console: Don't build on arches w/o ioremap
[linux-2.6.git] / drivers / staging / pohmelfs / inode.c
index 7b60579..807e3f3 100644 (file)
 #include <linux/slab.h>
 #include <linux/statfs.h>
 #include <linux/writeback.h>
-#include <linux/quotaops.h>
+#include <linux/prefetch.h>
 
 #include "netfs.h"
 
 #define POHMELFS_MAGIC_NUM     0x504f482e
 
 static struct kmem_cache *pohmelfs_inode_cache;
+static atomic_t psb_bdi_num = ATOMIC_INIT(0);
 
 /*
  * Removes inode from all trees, drops local name cache and removes all queued
@@ -143,7 +144,6 @@ static int pohmelfs_writepages(struct address_space *mapping, struct writeback_c
        struct inode *inode = mapping->host;
        struct pohmelfs_inode *pi = POHMELFS_I(inode);
        struct pohmelfs_sb *psb = POHMELFS_SB(inode->i_sb);
-       struct backing_dev_info *bdi = mapping->backing_dev_info;
        int err = 0;
        int done = 0;
        int nr_pages;
@@ -152,11 +152,6 @@ static int pohmelfs_writepages(struct address_space *mapping, struct writeback_c
        int scanned = 0;
        int range_whole = 0;
 
-       if (wbc->nonblocking && bdi_write_congested(bdi)) {
-               wbc->encountered_congestion = 1;
-               return 0;
-       }
-
        if (wbc->range_cyclic) {
                index = mapping->writeback_index; /* Start from prev offset */
                end = -1;
@@ -248,10 +243,6 @@ retry:
 
                        if (wbc->nr_to_write <= 0)
                                done = 1;
-                       if (wbc->nonblocking && bdi_write_congested(bdi)) {
-                               wbc->encountered_congestion = 1;
-                               done = 1;
-                       }
 
                        continue;
 out_continue:
@@ -332,7 +323,7 @@ int pohmelfs_write_create_inode(struct pohmelfs_inode *pi)
        t = netfs_trans_alloc(psb, err + 1, 0, 0);
        if (!t) {
                err = -ENOMEM;
-               goto err_out_put;
+               goto err_out_exit;
        }
        t->complete = pohmelfs_write_inode_complete;
        t->private = igrab(inode);
@@ -405,7 +396,8 @@ int pohmelfs_remove_child(struct pohmelfs_inode *pi, struct pohmelfs_name *n)
 /*
  * Writeback for given inode.
  */
-static int pohmelfs_write_inode(struct inode *inode, int sync)
+static int pohmelfs_write_inode(struct inode *inode,
+                               struct writeback_control *wbc)
 {
        struct pohmelfs_inode *pi = POHMELFS_I(inode);
 
@@ -693,7 +685,7 @@ static int pohmelfs_readpages_trans_complete(struct page **__pages, unsigned int
                goto err_out_free;
        }
 
-       for (i=0; i<num; ++i) {
+       for (i = 0; i < num; ++i) {
                page = pages[i];
 
                if (err)
@@ -824,7 +816,7 @@ static int pohmelfs_readpages(struct file *file, struct address_space *mapping,
 }
 
 /*
- * Small addres space operations for POHMELFS.
+ * Small address space operations for POHMELFS.
  */
 const struct address_space_operations pohmelfs_aops = {
        .readpage               = pohmelfs_readpage,
@@ -835,8 +827,14 @@ const struct address_space_operations pohmelfs_aops = {
        .set_page_dirty         = __set_page_dirty_nobuffers,
 };
 
+static void pohmelfs_i_callback(struct rcu_head *head)
+{
+       struct inode *inode = container_of(head, struct inode, i_rcu);
+       kmem_cache_free(pohmelfs_inode_cache, POHMELFS_I(inode));
+}
+
 /*
- * ->detroy_inode() callback. Deletes inode from the caches
+ * ->destroy_inode() callback. Deletes inode from the caches
  *  and frees private data.
  */
 static void pohmelfs_destroy_inode(struct inode *inode)
@@ -851,12 +849,12 @@ static void pohmelfs_destroy_inode(struct inode *inode)
 
        dprintk("%s: pi: %p, inode: %p, ino: %llu.\n",
                __func__, pi, &pi->vfs_inode, pi->ino);
-       kmem_cache_free(pohmelfs_inode_cache, pi);
        atomic_long_dec(&psb->total_inodes);
+       call_rcu(&inode->i_rcu, pohmelfs_i_callback);
 }
 
 /*
- * ->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)
 {
@@ -888,15 +886,16 @@ static struct inode *pohmelfs_alloc_inode(struct super_block *sb)
 /*
  * We want fsync() to work on POHMELFS.
  */
-static int pohmelfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+static int pohmelfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
        struct inode *inode = file->f_mapping->host;
-       struct writeback_control wbc = {
-               .sync_mode = WB_SYNC_ALL,
-               .nr_to_write = 0,       /* sys_fsync did this */
-       };
-
-       return sync_inode(inode, &wbc);
+       int err = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (!err) {
+               mutex_lock(&inode->i_mutex);
+               err = sync_inode_metadata(inode, 1);
+               mutex_unlock(&inode->i_mutex);
+       }
+       return err;
 }
 
 ssize_t pohmelfs_write(struct file *file, const char __user *buf,
@@ -921,16 +920,16 @@ ssize_t pohmelfs_write(struct file *file, const char __user *buf,
        if (ret)
                goto err_out_unlock;
 
-       ret = generic_file_aio_write_nolock(&kiocb, &iov, 1, pos);
+       ret = __generic_file_aio_write(&kiocb, &iov, 1, &kiocb.ki_pos);
        *ppos = kiocb.ki_pos;
 
        mutex_unlock(&inode->i_mutex);
        WARN_ON(ret < 0);
 
-       if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
+       if (ret > 0) {
                ssize_t err;
 
-               err = sync_page_range(inode, mapping, pos, ret);
+               err = generic_write_sync(file, pos, ret);
                if (err < 0)
                        ret = err;
                WARN_ON(ret < 0);
@@ -977,18 +976,17 @@ int pohmelfs_setattr_raw(struct inode *inode, struct iattr *attr)
                goto err_out_exit;
        }
 
-       if ((attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
-           (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
-               err = vfs_dq_transfer(inode, attr) ? -EDQUOT : 0;
-               if (err)
+       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;
+               }
        }
 
-       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;
-       }
+       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,
@@ -1134,18 +1132,18 @@ static ssize_t pohmelfs_getxattr(struct dentry *dentry, const char *name,
 
                /*
                 * This loop is a bit ugly, since it waits until reference counter
-                * hits 1 and then put object here. Main goal is to prevent race with
-                * network thread, when it can start processing given request, i.e.
+                * hits 1 and then puts the object here. Main goal is to prevent race with
+                * the network thread, when it can start processing the given request, i.e.
                 * increase its reference counter but yet not complete it, while
                 * we will exit from ->getxattr() with timeout, and although request
                 * will not be freed (its reference counter was increased by network
                 * thread), data pointer provided by user may be released, so we will
-                * overwrite already freed area in network thread.
+                * overwrite an already freed area in the network thread.
                 *
                 * Now after timeout we remove request from the cache, so it can not be
                 * found by network thread, and wait for its reference counter to hit 1,
                 * i.e. if network thread already started to process this request, we wait
-                * it to finish, and then free object locally. If reference counter is
+                * for it to finish, and then free object locally. If reference counter is
                 * already 1, i.e. request is not used by anyone else, we can free it without
                 * problem.
                 */
@@ -1198,7 +1196,7 @@ const struct inode_operations pohmelfs_file_inode_operations = {
 void pohmelfs_fill_inode(struct inode *inode, struct netfs_inode_info *info)
 {
        inode->i_mode = info->mode;
-       inode->i_nlink = info->nlink;
+       set_nlink(inode, info->nlink);
        inode->i_uid = info->uid;
        inode->i_gid = info->gid;
        inode->i_blocks = info->blocks;
@@ -1233,7 +1231,7 @@ void pohmelfs_fill_inode(struct inode *inode, struct netfs_inode_info *info)
        }
 }
 
-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);
@@ -1242,7 +1240,7 @@ static void pohmelfs_drop_inode(struct inode *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,
@@ -1282,7 +1280,7 @@ static void pohmelfs_put_super(struct super_block *sb)
 {
        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;
 
@@ -1332,8 +1330,8 @@ static void pohmelfs_put_super(struct super_block *sb)
        }
 
        psb->trans_scan_timeout = psb->drop_scan_timeout = 0;
-       cancel_rearming_delayed_work(&psb->dwork);
-       cancel_rearming_delayed_work(&psb->drop_dwork);
+       cancel_delayed_work_sync(&psb->dwork);
+       cancel_delayed_work_sync(&psb->drop_dwork);
        flush_scheduled_work();
 
        dprintk("%s: stopped workqueues.\n", __func__);
@@ -1341,6 +1339,8 @@ static void pohmelfs_put_super(struct super_block *sb)
        pohmelfs_crypto_exit(psb);
        pohmelfs_state_exit(psb);
 
+       bdi_destroy(&psb->bdi);
+
        kfree(psb);
        sb->s_fs_info = NULL;
 }
@@ -1369,9 +1369,9 @@ static int pohmelfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        return 0;
 }
 
-static int pohmelfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
+static int pohmelfs_show_options(struct seq_file *seq, struct dentry *root)
 {
-       struct pohmelfs_sb *psb = POHMELFS_SB(vfs->mnt_sb);
+       struct pohmelfs_sb *psb = POHMELFS_SB(root->d_sb);
 
        seq_printf(seq, ",idx=%u", psb->idx);
        seq_printf(seq, ",trans_scan_timeout=%u", jiffies_to_msecs(psb->trans_scan_timeout));
@@ -1437,35 +1437,35 @@ static int pohmelfs_parse_options(char *options, struct pohmelfs_sb *psb, int re
                        continue;
 
                switch (token) {
-                       case pohmelfs_opt_idx:
-                               psb->idx = option;
-                               break;
-                       case pohmelfs_opt_trans_scan_timeout:
-                               psb->trans_scan_timeout = msecs_to_jiffies(option);
-                               break;
-                       case pohmelfs_opt_drop_scan_timeout:
-                               psb->drop_scan_timeout = msecs_to_jiffies(option);
-                               break;
-                       case pohmelfs_opt_wait_on_page_timeout:
-                               psb->wait_on_page_timeout = msecs_to_jiffies(option);
-                               break;
-                       case pohmelfs_opt_mcache_timeout:
-                               psb->mcache_timeout = msecs_to_jiffies(option);
-                               break;
-                       case pohmelfs_opt_trans_retries:
-                               psb->trans_retries = option;
-                               break;
-                       case pohmelfs_opt_crypto_thread_num:
-                               psb->crypto_thread_num = option;
-                               break;
-                       case pohmelfs_opt_trans_max_pages:
-                               psb->trans_max_pages = option;
-                               break;
-                       case pohmelfs_opt_crypto_fail_unsupported:
-                               psb->crypto_fail_unsupported = 1;
-                               break;
-                       default:
-                               return -EINVAL;
+               case pohmelfs_opt_idx:
+                       psb->idx = option;
+                       break;
+               case pohmelfs_opt_trans_scan_timeout:
+                       psb->trans_scan_timeout = msecs_to_jiffies(option);
+                       break;
+               case pohmelfs_opt_drop_scan_timeout:
+                       psb->drop_scan_timeout = msecs_to_jiffies(option);
+                       break;
+               case pohmelfs_opt_wait_on_page_timeout:
+                       psb->wait_on_page_timeout = msecs_to_jiffies(option);
+                       break;
+               case pohmelfs_opt_mcache_timeout:
+                       psb->mcache_timeout = msecs_to_jiffies(option);
+                       break;
+               case pohmelfs_opt_trans_retries:
+                       psb->trans_retries = option;
+                       break;
+               case pohmelfs_opt_crypto_thread_num:
+                       psb->crypto_thread_num = option;
+                       break;
+               case pohmelfs_opt_trans_max_pages:
+                       psb->trans_max_pages = option;
+                       break;
+               case pohmelfs_opt_crypto_fail_unsupported:
+                       psb->crypto_fail_unsupported = 1;
+                       break;
+               default:
+                       return -EINVAL;
                }
        }
 
@@ -1504,7 +1504,9 @@ static void pohmelfs_flush_inode(struct pohmelfs_inode *pi, unsigned int count)
                inode->i_sb->s_op->write_inode(inode, 0);
        }
 
+#ifdef POHMELFS_TRUNCATE_ON_INODE_FLUSH
        truncate_inode_pages(inode->i_mapping, 0);
+#endif
 
        pohmelfs_data_unlock(pi, 0, ~0, POHMELFS_WRITE_LOCK);
        mutex_unlock(&inode->i_mutex);
@@ -1743,11 +1745,10 @@ static int pohmelfs_root_handshake(struct pohmelfs_sb *psb)
        err = wait_event_interruptible_timeout(psb->wait,
                        (psb->flags != ~0),
                        psb->wait_on_page_timeout);
-       if (!err) {
+       if (!err)
                err = -ETIMEDOUT;
-       } else {
+       else if (err > 0)
                err = -psb->flags;
-       }
 
        if (err)
                goto err_out_exit;
@@ -1758,11 +1759,11 @@ err_out_exit:
        return err;
 }
 
-static int pohmelfs_show_stats(struct seq_file *m, struct vfsmount *mnt)
+static int pohmelfs_show_stats(struct seq_file *m, struct dentry *root)
 {
        struct netfs_state *st;
        struct pohmelfs_ctl *ctl;
-       struct pohmelfs_sb *psb = POHMELFS_SB(mnt->mnt_sb);
+       struct pohmelfs_sb *psb = POHMELFS_SB(root->d_sb);
        struct pohmelfs_config *c;
 
        mutex_lock(&psb->state_lock);
@@ -1776,14 +1777,13 @@ static int pohmelfs_show_stats(struct seq_file *m, struct vfsmount *mnt)
                seq_printf(m, "%u ", ctl->idx);
                if (ctl->addr.sa_family == AF_INET) {
                        struct sockaddr_in *sin = (struct sockaddr_in *)&st->ctl.addr;
-                       /* seq_printf(m, "%pi4:%u", &sin->sin_addr.s_addr, ntohs(sin->sin_port)); */
-                       seq_printf(m, "%u.%u.%u.%u:%u", NIPQUAD(sin->sin_addr.s_addr), ntohs(sin->sin_port));
+                       seq_printf(m, "%pI4:%u", &sin->sin_addr.s_addr, ntohs(sin->sin_port));
                } else if (ctl->addr.sa_family == AF_INET6) {
                        struct sockaddr_in6 *sin = (struct sockaddr_in6 *)&st->ctl.addr;
                        seq_printf(m, "%pi6:%u", &sin->sin6_addr, ntohs(sin->sin6_port));
                } else {
                        unsigned int i;
-                       for (i=0; i<ctl->addrlen; ++i)
+                       for (i = 0; i < ctl->addrlen; ++i)
                                seq_printf(m, "%02x.", ctl->addr.addr[i]);
                }
 
@@ -1824,11 +1824,22 @@ static int pohmelfs_fill_super(struct super_block *sb, void *data, int silent)
        if (!psb)
                goto err_out_exit;
 
+       err = bdi_init(&psb->bdi);
+       if (err)
+               goto err_out_free_sb;
+
+       err = bdi_register(&psb->bdi, NULL, "pfs-%d", atomic_inc_return(&psb_bdi_num));
+       if (err) {
+               bdi_destroy(&psb->bdi);
+               goto err_out_free_sb;
+       }
+
        sb->s_fs_info = psb;
        sb->s_op = &pohmelfs_sb_ops;
        sb->s_magic = POHMELFS_MAGIC_NUM;
        sb->s_maxbytes = MAX_LFS_FILESIZE;
        sb->s_blocksize = PAGE_SIZE;
+       sb->s_bdi = &psb->bdi;
 
        psb->sb = sb;
 
@@ -1865,18 +1876,18 @@ static int pohmelfs_fill_super(struct super_block *sb, void *data, int silent)
        INIT_LIST_HEAD(&psb->crypto_active_list);
 
        atomic_set(&psb->trans_gen, 1);
-       atomic_set(&psb->total_inodes, 0);
+       atomic_long_set(&psb->total_inodes, 0);
 
        mutex_init(&psb->state_lock);
        INIT_LIST_HEAD(&psb->state_list);
 
        err = pohmelfs_parse_options((char *) data, psb, 0);
        if (err)
-               goto err_out_free_sb;
+               goto err_out_free_bdi;
 
        err = pohmelfs_copy_crypto(psb);
        if (err)
-               goto err_out_free_sb;
+               goto err_out_free_bdi;
 
        err = pohmelfs_state_init(psb);
        if (err)
@@ -1925,6 +1936,8 @@ err_out_state_exit:
 err_out_free_strings:
        kfree(psb->cipher_string);
        kfree(psb->hash_string);
+err_out_free_bdi:
+       bdi_destroy(&psb->bdi);
 err_out_free_sb:
        kfree(psb);
 err_out_exit:
@@ -1936,11 +1949,10 @@ err_out_exit:
 /*
  * Some VFS magic here...
  */
-static int pohmelfs_get_sb(struct file_system_type *fs_type,
-       int flags, const char *dev_name, void *data, struct vfsmount *mnt)
+static struct dentry *pohmelfs_mount(struct file_system_type *fs_type,
+       int flags, const char *dev_name, void *data)
 {
-       return get_sb_nodev(fs_type, flags, data, pohmelfs_fill_super,
-                               mnt);
+       return mount_nodev(fs_type, flags, data, pohmelfs_fill_super);
 }
 
 /*
@@ -1950,21 +1962,14 @@ static int pohmelfs_get_sb(struct file_system_type *fs_type,
  */
 static void pohmelfs_kill_super(struct super_block *sb)
 {
-       struct writeback_control wbc = {
-               .sync_mode      = WB_SYNC_ALL,
-               .range_start    = 0,
-               .range_end      = LLONG_MAX,
-               .nr_to_write    = LONG_MAX,
-       };
-       generic_sync_sb_inodes(sb, &wbc);
-
+       sync_inodes_sb(sb);
        kill_anon_super(sb);
 }
 
 static struct file_system_type pohmel_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "pohmel",
-       .get_sb         = pohmelfs_get_sb,
+       .mount          = pohmelfs_mount,
        .kill_sb        = pohmelfs_kill_super,
 };
 
@@ -2035,7 +2040,7 @@ err_out_exit:
 
 static void __exit exit_pohmel_fs(void)
 {
-        unregister_filesystem(&pohmel_fs_type);
+       unregister_filesystem(&pohmel_fs_type);
        pohmelfs_destroy_inodecache();
        pohmelfs_mcache_exit();
        pohmelfs_config_exit();