[funini.com] -> [kei@sodan] -> Kernel Reading

root/fs/udf/file.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. udf_adinicb_readpage
  2. udf_adinicb_writepage
  3. udf_adinicb_write_end
  4. udf_file_aio_write
  5. udf_ioctl
  6. udf_release_file

/*
 * file.c
 *
 * PURPOSE
 *  File handling routines for the OSTA-UDF(tm) filesystem.
 *
 * COPYRIGHT
 *  This file is distributed under the terms of the GNU General Public
 *  License (GPL). Copies of the GPL can be obtained from:
 *    ftp://prep.ai.mit.edu/pub/gnu/GPL
 *  Each contributing author retains all rights to their own work.
 *
 *  (C) 1998-1999 Dave Boynton
 *  (C) 1998-2004 Ben Fennema
 *  (C) 1999-2000 Stelias Computing Inc
 *
 * HISTORY
 *
 *  10/02/98 dgb  Attempt to integrate into udf.o
 *  10/07/98      Switched to using generic_readpage, etc., like isofs
 *                And it works!
 *  12/06/98 blf  Added udf_file_read. uses generic_file_read for all cases but
 *                ICBTAG_FLAG_AD_IN_ICB.
 *  04/06/99      64 bit file handling on 32 bit systems taken from ext2 file.c
 *  05/12/99      Preliminary file write support
 */

#include "udfdecl.h"
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/kernel.h>
#include <linux/string.h> /* memset */
#include <linux/capability.h>
#include <linux/errno.h>
#include <linux/smp_lock.h>
#include <linux/pagemap.h>
#include <linux/buffer_head.h>
#include <linux/aio.h>

#include "udf_i.h"
#include "udf_sb.h"

static int udf_adinicb_readpage(struct file *file, struct page *page)
{
        struct inode *inode = page->mapping->host;
        char *kaddr;
        struct udf_inode_info *iinfo = UDF_I(inode);

        BUG_ON(!PageLocked(page));

        kaddr = kmap(page);
        memset(kaddr, 0, PAGE_CACHE_SIZE);
        memcpy(kaddr, iinfo->i_ext.i_data + iinfo->i_lenEAttr, inode->i_size);
        flush_dcache_page(page);
        SetPageUptodate(page);
        kunmap(page);
        unlock_page(page);

        return 0;
}

static int udf_adinicb_writepage(struct page *page,
                                 struct writeback_control *wbc)
{
        struct inode *inode = page->mapping->host;
        char *kaddr;
        struct udf_inode_info *iinfo = UDF_I(inode);

        BUG_ON(!PageLocked(page));

        kaddr = kmap(page);
        memcpy(iinfo->i_ext.i_data + iinfo->i_lenEAttr, kaddr, inode->i_size);
        mark_inode_dirty(inode);
        SetPageUptodate(page);
        kunmap(page);
        unlock_page(page);

        return 0;
}

static int udf_adinicb_write_end(struct file *file,
                        struct address_space *mapping,
                        loff_t pos, unsigned len, unsigned copied,
                        struct page *page, void *fsdata)
{
        struct inode *inode = mapping->host;
        unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
        char *kaddr;
        struct udf_inode_info *iinfo = UDF_I(inode);

        kaddr = kmap_atomic(page, KM_USER0);
        memcpy(iinfo->i_ext.i_data + iinfo->i_lenEAttr + offset,
                kaddr + offset, copied);
        kunmap_atomic(kaddr, KM_USER0);

        return simple_write_end(file, mapping, pos, len, copied, page, fsdata);
}

const struct address_space_operations udf_adinicb_aops = {
        .readpage       = udf_adinicb_readpage,
        .writepage      = udf_adinicb_writepage,
        .sync_page      = block_sync_page,
        .write_begin = simple_write_begin,
        .write_end = udf_adinicb_write_end,
};

static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
                                  unsigned long nr_segs, loff_t ppos)
{
        ssize_t retval;
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_path.dentry->d_inode;
        int err, pos;
        size_t count = iocb->ki_left;
        struct udf_inode_info *iinfo = UDF_I(inode);

        if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
                if (file->f_flags & O_APPEND)
                        pos = inode->i_size;
                else
                        pos = ppos;

                if (inode->i_sb->s_blocksize <
                                (udf_file_entry_alloc_offset(inode) +
                                                pos + count)) {
                        udf_expand_file_adinicb(inode, pos + count, &err);
                        if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
                                udf_debug("udf_expand_adinicb: err=%d\n", err);
                                return err;
                        }
                } else {
                        if (pos + count > inode->i_size)
                                iinfo->i_lenAlloc = pos + count;
                        else
                                iinfo->i_lenAlloc = inode->i_size;
                }
        }

        retval = generic_file_aio_write(iocb, iov, nr_segs, ppos);
        if (retval > 0)
                mark_inode_dirty(inode);

        return retval;
}

int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
              unsigned long arg)
{
        long old_block, new_block;
        int result = -EINVAL;

        if (file_permission(filp, MAY_READ) != 0) {
                udf_debug("no permission to access inode %lu\n",
                          inode->i_ino);
                return -EPERM;
        }

        if (!arg) {
                udf_debug("invalid argument to udf_ioctl\n");
                return -EINVAL;
        }

        switch (cmd) {
        case UDF_GETVOLIDENT:
                if (copy_to_user((char __user *)arg,
                                 UDF_SB(inode->i_sb)->s_volume_ident, 32))
                        return -EFAULT;
                else
                        return 0;
        case UDF_RELOCATE_BLOCKS:
                if (!capable(CAP_SYS_ADMIN))
                        return -EACCES;
                if (get_user(old_block, (long __user *)arg))
                        return -EFAULT;
                result = udf_relocate_blocks(inode->i_sb,
                                                old_block, &new_block);
                if (result == 0)
                        result = put_user(new_block, (long __user *)arg);
                return result;
        case UDF_GETEASIZE:
                result = put_user(UDF_I(inode)->i_lenEAttr, (int __user *)arg);
                break;
        case UDF_GETEABLOCK:
                result = copy_to_user((char __user *)arg,
                                      UDF_I(inode)->i_ext.i_data,
                                      UDF_I(inode)->i_lenEAttr) ? -EFAULT : 0;
                break;
        }

        return result;
}

static int udf_release_file(struct inode *inode, struct file *filp)
{
        if (filp->f_mode & FMODE_WRITE) {
                lock_kernel();
                udf_discard_prealloc(inode);
                unlock_kernel();
        }
        return 0;
}

const struct file_operations udf_file_operations = {
        .read                   = do_sync_read,
        .aio_read               = generic_file_aio_read,
        .ioctl                  = udf_ioctl,
        .open                   = generic_file_open,
        .mmap                   = generic_file_mmap,
        .write                  = do_sync_write,
        .aio_write              = udf_file_aio_write,
        .release                = udf_release_file,
        .fsync                  = udf_fsync_file,
        .splice_read            = generic_file_splice_read,
        .llseek                 = generic_file_llseek,
};

const struct inode_operations udf_file_inode_operations = {
        .truncate = udf_truncate,
};

/* [<][>][^][v][top][bottom][index][help] */

[funini.com] -> [kei@sodan] -> Kernel Reading