staging: android/ram_console: Don't build on arches w/o ioremap
[linux-2.6.git] / drivers / staging / pohmelfs / inode.c
index a12fcc6..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);
@@ -386,7 +377,7 @@ static int pohmelfs_write_inode_create_children(struct inode *inode)
                if (inode && (inode->i_state & I_DIRTY)) {
                        struct pohmelfs_inode *pi = POHMELFS_I(inode);
                        pohmelfs_write_create_inode(pi);
-                       //pohmelfs_meta_command(pi, NETFS_INODE_INFO, 0, NULL, NULL, 0);
+                       /* pohmelfs_meta_command(pi, NETFS_INODE_INFO, 0, NULL, NULL, 0); */
                        iput(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)
@@ -845,18 +843,18 @@ static void pohmelfs_destroy_inode(struct inode *inode)
        struct pohmelfs_sb *psb = POHMELFS_SB(sb);
        struct pohmelfs_inode *pi = POHMELFS_I(inode);
 
-       //pohmelfs_data_unlock(pi, 0, inode->i_size, POHMELFS_READ_LOCK);
+       /* pohmelfs_data_unlock(pi, 0, inode->i_size, POHMELFS_READ_LOCK); */
 
        pohmelfs_inode_del_inode(psb, pi);
 
        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);
@@ -943,7 +942,7 @@ err_out_unlock:
        return ret;
 }
 
-const static struct file_operations pohmelfs_file_ops = {
+static const struct file_operations pohmelfs_file_ops = {
        .open           = generic_file_open,
        .fsync          = pohmelfs_fsync,
 
@@ -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);
@@ -1529,9 +1531,9 @@ static void pohmelfs_drop_scan(struct work_struct *work)
        struct pohmelfs_inode *pi;
        unsigned int count = 0;
 
-       while ((pi = pohmelfs_get_inode_from_list(psb, &psb->drop_list, &count))) {
+       while ((pi = pohmelfs_get_inode_from_list(psb, &psb->drop_list, &count)))
                pohmelfs_put_inode_count(pi, count);
-       }
+
        pohmelfs_check_states(psb);
 
        if (psb->drop_scan_timeout)
@@ -1568,9 +1570,8 @@ static void pohmelfs_trans_scan_state(struct netfs_state *st)
                rb_node = rb_next(rb_node);
 
                err = -ETIMEDOUT;
-               if (timeout && (++dst->retries < psb->trans_retries)) {
+               if (timeout && (++dst->retries < psb->trans_retries))
                        err = netfs_trans_resend(t, psb);
-               }
 
                if (err || (t->flags & NETFS_TRANS_SINGLE_DST)) {
                        if (netfs_trans_remove_nolock(dst, st))
@@ -1744,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;
@@ -1759,6 +1759,44 @@ err_out_exit:
        return err;
 }
 
+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(root->d_sb);
+       struct pohmelfs_config *c;
+
+       mutex_lock(&psb->state_lock);
+
+       seq_printf(m, "\nidx addr(:port) socket_type protocol active priority permissions\n");
+
+       list_for_each_entry(c, &psb->state_list, config_entry) {
+               st = &c->state;
+               ctl = &st->ctl;
+
+               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));
+               } 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)
+                               seq_printf(m, "%02x.", ctl->addr.addr[i]);
+               }
+
+               seq_printf(m, " %u %u %d %u %x\n",
+                               ctl->type, ctl->proto,
+                               st->socket != NULL,
+                               ctl->prio, ctl->perm);
+       }
+       mutex_unlock(&psb->state_lock);
+
+       return 0;
+}
+
 static const struct super_operations pohmelfs_sb_ops = {
        .alloc_inode    = pohmelfs_alloc_inode,
        .destroy_inode  = pohmelfs_destroy_inode,
@@ -1768,6 +1806,7 @@ static const struct super_operations pohmelfs_sb_ops = {
        .remount_fs     = pohmelfs_remount,
        .statfs         = pohmelfs_statfs,
        .show_options   = pohmelfs_show_options,
+       .show_stats     = pohmelfs_show_stats,
 };
 
 /*
@@ -1785,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;
 
@@ -1826,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)
@@ -1886,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:
@@ -1897,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);
 }
 
 /*
@@ -1911,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,
 };
 
@@ -1996,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();