linux/fs/coda/inode.c
Linus Torvalds 24e7ea3bea Major changes for 3.14 include support for the newly added ZERO_RANGE
and COLLAPSE_RANGE fallocate operations, and scalability improvements
 in the jbd2 layer and in xattr handling when the extended attributes
 spill over into an external block.
 
 Other than that, the usual clean ups and minor bug fixes.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQIcBAABCAAGBQJTPbD2AAoJENNvdpvBGATwDmUQANSfGYIQazB8XKKgtNTMiG/Y
 Ky7n1JzN9lTX/6nMsqQnbfCweLRmxqpWUBuyKDRHUi8IG0/voXSTFsAOOgz0R15A
 ERRRWkVvHixLpohuL/iBdEMFHwNZYPGr3jkm0EIgzhtXNgk5DNmiuMwvHmCY27kI
 kdNZIw9fip/WRNoFLDBGnLGC37aanoHhCIbVlySy5o9LN1pkC8BgXAYV0Rk19SVd
 bWCudSJEirFEqWS5H8vsBAEm/ioxTjwnNL8tX8qms6orZ6h8yMLFkHoIGWPw3Q15
 a0TSUoMyav50Yr59QaDeWx9uaPQVeK41wiYFI2rZOnyG2ts0u0YXs/nLwJqTovgs
 rzvbdl6cd3Nj++rPi97MTA7iXK96WQPjsDJoeeEgnB0d/qPyTk6mLKgftzLTNgSa
 ZmWjrB19kr6CMbebMC4L6eqJ8Fr66pCT8c/iue8wc4MUHi7FwHKH64fqWvzp2YT/
 +165dqqo2JnUv7tIp6sUi1geun+bmDHLZFXgFa7fNYFtcU3I+uY1mRr3eMVAJndA
 2d6ASe/KhQbpVnjKJdQ8/b833ZS3p+zkgVPrd68bBr3t7gUmX91wk+p1ct6rUPLr
 700F+q/pQWL8ap0pU9Ht/h3gEJIfmRzTwxlOeYyOwDseqKuS87PSB3BzV3dDunSU
 DrPKlXwIgva7zq5/S0Vr
 =4s1Z
 -----END PGP SIGNATURE-----

Merge tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4

Pull ext4 updates from Ted Ts'o:
 "Major changes for 3.14 include support for the newly added ZERO_RANGE
  and COLLAPSE_RANGE fallocate operations, and scalability improvements
  in the jbd2 layer and in xattr handling when the extended attributes
  spill over into an external block.

  Other than that, the usual clean ups and minor bug fixes"

* tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: (42 commits)
  ext4: fix premature freeing of partial clusters split across leaf blocks
  ext4: remove unneeded test of ret variable
  ext4: fix comment typo
  ext4: make ext4_block_zero_page_range static
  ext4: atomically set inode->i_flags in ext4_set_inode_flags()
  ext4: optimize Hurd tests when reading/writing inodes
  ext4: kill i_version support for Hurd-castrated file systems
  ext4: each filesystem creates and uses its own mb_cache
  fs/mbcache.c: doucple the locking of local from global data
  fs/mbcache.c: change block and index hash chain to hlist_bl_node
  ext4: Introduce FALLOC_FL_ZERO_RANGE flag for fallocate
  ext4: refactor ext4_fallocate code
  ext4: Update inode i_size after the preallocation
  ext4: fix partial cluster handling for bigalloc file systems
  ext4: delete path dealloc code in ext4_ext_handle_uninitialized_extents
  ext4: only call sync_filesystm() when remounting read-only
  fs: push sync_filesystem() down to the file system's remount_fs()
  jbd2: improve error messages for inconsistent journal heads
  jbd2: minimize region locked by j_list_lock in jbd2_journal_forget()
  jbd2: minimize region locked by j_list_lock in journal_get_create_access()
  ...
2014-04-04 15:39:39 -07:00

335 lines
7.3 KiB
C

/*
* Super block/filesystem wide operations
*
* Copyright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk> and
* Michael Callahan <callahan@maths.ox.ac.uk>
*
* Rewritten for Linux 2.1. Peter Braam <braam@cs.cmu.edu>
* Copyright (C) Carnegie Mellon University
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/file.h>
#include <linux/vfs.h>
#include <linux/slab.h>
#include <linux/pid_namespace.h>
#include <asm/uaccess.h>
#include <linux/fs.h>
#include <linux/vmalloc.h>
#include <linux/coda.h>
#include <linux/coda_psdev.h>
#include "coda_linux.h"
#include "coda_cache.h"
#include "coda_int.h"
/* VFS super_block ops */
static void coda_evict_inode(struct inode *);
static void coda_put_super(struct super_block *);
static int coda_statfs(struct dentry *dentry, struct kstatfs *buf);
static struct kmem_cache * coda_inode_cachep;
static struct inode *coda_alloc_inode(struct super_block *sb)
{
struct coda_inode_info *ei;
ei = kmem_cache_alloc(coda_inode_cachep, GFP_KERNEL);
if (!ei)
return NULL;
memset(&ei->c_fid, 0, sizeof(struct CodaFid));
ei->c_flags = 0;
ei->c_uid = GLOBAL_ROOT_UID;
ei->c_cached_perm = 0;
spin_lock_init(&ei->c_lock);
return &ei->vfs_inode;
}
static void coda_i_callback(struct rcu_head *head)
{
struct inode *inode = container_of(head, struct inode, i_rcu);
kmem_cache_free(coda_inode_cachep, ITOC(inode));
}
static void coda_destroy_inode(struct inode *inode)
{
call_rcu(&inode->i_rcu, coda_i_callback);
}
static void init_once(void *foo)
{
struct coda_inode_info *ei = (struct coda_inode_info *) foo;
inode_init_once(&ei->vfs_inode);
}
int __init coda_init_inodecache(void)
{
coda_inode_cachep = kmem_cache_create("coda_inode_cache",
sizeof(struct coda_inode_info),
0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
init_once);
if (coda_inode_cachep == NULL)
return -ENOMEM;
return 0;
}
void coda_destroy_inodecache(void)
{
/*
* Make sure all delayed rcu free inodes are flushed before we
* destroy cache.
*/
rcu_barrier();
kmem_cache_destroy(coda_inode_cachep);
}
static int coda_remount(struct super_block *sb, int *flags, char *data)
{
sync_filesystem(sb);
*flags |= MS_NOATIME;
return 0;
}
/* exported operations */
static const struct super_operations coda_super_operations =
{
.alloc_inode = coda_alloc_inode,
.destroy_inode = coda_destroy_inode,
.evict_inode = coda_evict_inode,
.put_super = coda_put_super,
.statfs = coda_statfs,
.remount_fs = coda_remount,
};
static int get_device_index(struct coda_mount_data *data)
{
struct fd f;
struct inode *inode;
int idx;
if (data == NULL) {
printk("coda_read_super: Bad mount data\n");
return -1;
}
if (data->version != CODA_MOUNT_VERSION) {
printk("coda_read_super: Bad mount version\n");
return -1;
}
f = fdget(data->fd);
if (!f.file)
goto Ebadf;
inode = file_inode(f.file);
if (!S_ISCHR(inode->i_mode) || imajor(inode) != CODA_PSDEV_MAJOR) {
fdput(f);
goto Ebadf;
}
idx = iminor(inode);
fdput(f);
if (idx < 0 || idx >= MAX_CODADEVS) {
printk("coda_read_super: Bad minor number\n");
return -1;
}
return idx;
Ebadf:
printk("coda_read_super: Bad file\n");
return -1;
}
static int coda_fill_super(struct super_block *sb, void *data, int silent)
{
struct inode *root = NULL;
struct venus_comm *vc;
struct CodaFid fid;
int error;
int idx;
if (task_active_pid_ns(current) != &init_pid_ns)
return -EINVAL;
idx = get_device_index((struct coda_mount_data *) data);
/* Ignore errors in data, for backward compatibility */
if(idx == -1)
idx = 0;
printk(KERN_INFO "coda_read_super: device index: %i\n", idx);
vc = &coda_comms[idx];
mutex_lock(&vc->vc_mutex);
if (!vc->vc_inuse) {
printk("coda_read_super: No pseudo device\n");
error = -EINVAL;
goto unlock_out;
}
if (vc->vc_sb) {
printk("coda_read_super: Device already mounted\n");
error = -EBUSY;
goto unlock_out;
}
error = bdi_setup_and_register(&vc->bdi, "coda", BDI_CAP_MAP_COPY);
if (error)
goto unlock_out;
vc->vc_sb = sb;
mutex_unlock(&vc->vc_mutex);
sb->s_fs_info = vc;
sb->s_flags |= MS_NOATIME;
sb->s_blocksize = 4096; /* XXXXX what do we put here?? */
sb->s_blocksize_bits = 12;
sb->s_magic = CODA_SUPER_MAGIC;
sb->s_op = &coda_super_operations;
sb->s_d_op = &coda_dentry_operations;
sb->s_bdi = &vc->bdi;
/* get root fid from Venus: this needs the root inode */
error = venus_rootfid(sb, &fid);
if ( error ) {
printk("coda_read_super: coda_get_rootfid failed with %d\n",
error);
goto error;
}
printk("coda_read_super: rootfid is %s\n", coda_f2s(&fid));
/* make root inode */
root = coda_cnode_make(&fid, sb);
if (IS_ERR(root)) {
error = PTR_ERR(root);
printk("Failure of coda_cnode_make for root: error %d\n", error);
goto error;
}
printk("coda_read_super: rootinode is %ld dev %s\n",
root->i_ino, root->i_sb->s_id);
sb->s_root = d_make_root(root);
if (!sb->s_root) {
error = -EINVAL;
goto error;
}
return 0;
error:
mutex_lock(&vc->vc_mutex);
bdi_destroy(&vc->bdi);
vc->vc_sb = NULL;
sb->s_fs_info = NULL;
unlock_out:
mutex_unlock(&vc->vc_mutex);
return error;
}
static void coda_put_super(struct super_block *sb)
{
struct venus_comm *vcp = coda_vcp(sb);
mutex_lock(&vcp->vc_mutex);
bdi_destroy(&vcp->bdi);
vcp->vc_sb = NULL;
sb->s_fs_info = NULL;
mutex_unlock(&vcp->vc_mutex);
printk("Coda: Bye bye.\n");
}
static void coda_evict_inode(struct inode *inode)
{
truncate_inode_pages_final(&inode->i_data);
clear_inode(inode);
coda_cache_clear_inode(inode);
}
int coda_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
{
int err = coda_revalidate_inode(dentry->d_inode);
if (!err)
generic_fillattr(dentry->d_inode, stat);
return err;
}
int coda_setattr(struct dentry *de, struct iattr *iattr)
{
struct inode *inode = de->d_inode;
struct coda_vattr vattr;
int error;
memset(&vattr, 0, sizeof(vattr));
inode->i_ctime = CURRENT_TIME_SEC;
coda_iattr_to_vattr(iattr, &vattr);
vattr.va_type = C_VNON; /* cannot set type */
/* Venus is responsible for truncating the container-file!!! */
error = venus_setattr(inode->i_sb, coda_i2f(inode), &vattr);
if (!error) {
coda_vattr_to_iattr(inode, &vattr);
coda_cache_clear_inode(inode);
}
return error;
}
const struct inode_operations coda_file_inode_operations = {
.permission = coda_permission,
.getattr = coda_getattr,
.setattr = coda_setattr,
};
static int coda_statfs(struct dentry *dentry, struct kstatfs *buf)
{
int error;
error = venus_statfs(dentry, buf);
if (error) {
/* fake something like AFS does */
buf->f_blocks = 9000000;
buf->f_bfree = 9000000;
buf->f_bavail = 9000000;
buf->f_files = 9000000;
buf->f_ffree = 9000000;
}
/* and fill in the rest */
buf->f_type = CODA_SUPER_MAGIC;
buf->f_bsize = 4096;
buf->f_namelen = CODA_MAXNAMLEN;
return 0;
}
/* init_coda: used by filesystems.c to register coda */
static struct dentry *coda_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
return mount_nodev(fs_type, flags, data, coda_fill_super);
}
struct file_system_type coda_fs_type = {
.owner = THIS_MODULE,
.name = "coda",
.mount = coda_mount,
.kill_sb = kill_anon_super,
.fs_flags = FS_BINARY_MOUNTDATA,
};
MODULE_ALIAS_FS("coda");