The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/udf/file.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * file.c
    3  *
    4  * PURPOSE
    5  *  File handling routines for the OSTA-UDF(tm) filesystem.
    6  *
    7  * COPYRIGHT
    8  *  This file is distributed under the terms of the GNU General Public
    9  *  License (GPL). Copies of the GPL can be obtained from:
   10  *    ftp://prep.ai.mit.edu/pub/gnu/GPL
   11  *  Each contributing author retains all rights to their own work.
   12  *
   13  *  (C) 1998-1999 Dave Boynton
   14  *  (C) 1998-2004 Ben Fennema
   15  *  (C) 1999-2000 Stelias Computing Inc
   16  *
   17  * HISTORY
   18  *
   19  *  10/02/98 dgb  Attempt to integrate into udf.o
   20  *  10/07/98      Switched to using generic_readpage, etc., like isofs
   21  *                And it works!
   22  *  12/06/98 blf  Added udf_file_read. uses generic_file_read for all cases but
   23  *                ICBTAG_FLAG_AD_IN_ICB.
   24  *  04/06/99      64 bit file handling on 32 bit systems taken from ext2 file.c
   25  *  05/12/99      Preliminary file write support
   26  */
   27 
   28 #include "udfdecl.h"
   29 #include <linux/fs.h>
   30 #include <asm/uaccess.h>
   31 #include <linux/kernel.h>
   32 #include <linux/string.h> /* memset */
   33 #include <linux/capability.h>
   34 #include <linux/errno.h>
   35 #include <linux/pagemap.h>
   36 #include <linux/buffer_head.h>
   37 #include <linux/aio.h>
   38 
   39 #include "udf_i.h"
   40 #include "udf_sb.h"
   41 
   42 static void __udf_adinicb_readpage(struct page *page)
   43 {
   44         struct inode *inode = page->mapping->host;
   45         char *kaddr;
   46         struct udf_inode_info *iinfo = UDF_I(inode);
   47 
   48         kaddr = kmap(page);
   49         memcpy(kaddr, iinfo->i_ext.i_data + iinfo->i_lenEAttr, inode->i_size);
   50         memset(kaddr + inode->i_size, 0, PAGE_CACHE_SIZE - inode->i_size);
   51         flush_dcache_page(page);
   52         SetPageUptodate(page);
   53         kunmap(page);
   54 }
   55 
   56 static int udf_adinicb_readpage(struct file *file, struct page *page)
   57 {
   58         BUG_ON(!PageLocked(page));
   59         __udf_adinicb_readpage(page);
   60         unlock_page(page);
   61 
   62         return 0;
   63 }
   64 
   65 static int udf_adinicb_writepage(struct page *page,
   66                                  struct writeback_control *wbc)
   67 {
   68         struct inode *inode = page->mapping->host;
   69         char *kaddr;
   70         struct udf_inode_info *iinfo = UDF_I(inode);
   71 
   72         BUG_ON(!PageLocked(page));
   73 
   74         kaddr = kmap(page);
   75         memcpy(iinfo->i_ext.i_data + iinfo->i_lenEAttr, kaddr, inode->i_size);
   76         mark_inode_dirty(inode);
   77         SetPageUptodate(page);
   78         kunmap(page);
   79         unlock_page(page);
   80 
   81         return 0;
   82 }
   83 
   84 static int udf_adinicb_write_begin(struct file *file,
   85                         struct address_space *mapping, loff_t pos,
   86                         unsigned len, unsigned flags, struct page **pagep,
   87                         void **fsdata)
   88 {
   89         struct page *page;
   90 
   91         if (WARN_ON_ONCE(pos >= PAGE_CACHE_SIZE))
   92                 return -EIO;
   93         page = grab_cache_page_write_begin(mapping, 0, flags);
   94         if (!page)
   95                 return -ENOMEM;
   96         *pagep = page;
   97 
   98         if (!PageUptodate(page) && len != PAGE_CACHE_SIZE)
   99                 __udf_adinicb_readpage(page);
  100         return 0;
  101 }
  102 
  103 static int udf_adinicb_write_end(struct file *file,
  104                         struct address_space *mapping,
  105                         loff_t pos, unsigned len, unsigned copied,
  106                         struct page *page, void *fsdata)
  107 {
  108         struct inode *inode = mapping->host;
  109         unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
  110         char *kaddr;
  111         struct udf_inode_info *iinfo = UDF_I(inode);
  112 
  113         kaddr = kmap_atomic(page);
  114         memcpy(iinfo->i_ext.i_data + iinfo->i_lenEAttr + offset,
  115                 kaddr + offset, copied);
  116         kunmap_atomic(kaddr);
  117 
  118         return simple_write_end(file, mapping, pos, len, copied, page, fsdata);
  119 }
  120 
  121 static ssize_t udf_adinicb_direct_IO(int rw, struct kiocb *iocb,
  122                                      const struct iovec *iov,
  123                                      loff_t offset, unsigned long nr_segs)
  124 {
  125         /* Fallback to buffered I/O. */
  126         return 0;
  127 }
  128 
  129 const struct address_space_operations udf_adinicb_aops = {
  130         .readpage       = udf_adinicb_readpage,
  131         .writepage      = udf_adinicb_writepage,
  132         .write_begin    = udf_adinicb_write_begin,
  133         .write_end      = udf_adinicb_write_end,
  134         .direct_IO      = udf_adinicb_direct_IO,
  135 };
  136 
  137 static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
  138                                   unsigned long nr_segs, loff_t ppos)
  139 {
  140         ssize_t retval;
  141         struct file *file = iocb->ki_filp;
  142         struct inode *inode = file->f_path.dentry->d_inode;
  143         int err, pos;
  144         size_t count = iocb->ki_left;
  145         struct udf_inode_info *iinfo = UDF_I(inode);
  146 
  147         down_write(&iinfo->i_data_sem);
  148         if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
  149                 if (file->f_flags & O_APPEND)
  150                         pos = inode->i_size;
  151                 else
  152                         pos = ppos;
  153 
  154                 if (inode->i_sb->s_blocksize <
  155                                 (udf_file_entry_alloc_offset(inode) +
  156                                                 pos + count)) {
  157                         err = udf_expand_file_adinicb(inode);
  158                         if (err) {
  159                                 udf_debug("udf_expand_adinicb: err=%d\n", err);
  160                                 return err;
  161                         }
  162                 } else {
  163                         if (pos + count > inode->i_size)
  164                                 iinfo->i_lenAlloc = pos + count;
  165                         else
  166                                 iinfo->i_lenAlloc = inode->i_size;
  167                         up_write(&iinfo->i_data_sem);
  168                 }
  169         } else
  170                 up_write(&iinfo->i_data_sem);
  171 
  172         retval = generic_file_aio_write(iocb, iov, nr_segs, ppos);
  173         if (retval > 0)
  174                 mark_inode_dirty(inode);
  175 
  176         return retval;
  177 }
  178 
  179 long udf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
  180 {
  181         struct inode *inode = filp->f_dentry->d_inode;
  182         long old_block, new_block;
  183         int result = -EINVAL;
  184 
  185         if (inode_permission(inode, MAY_READ) != 0) {
  186                 udf_debug("no permission to access inode %lu\n", inode->i_ino);
  187                 result = -EPERM;
  188                 goto out;
  189         }
  190 
  191         if (!arg) {
  192                 udf_debug("invalid argument to udf_ioctl\n");
  193                 result = -EINVAL;
  194                 goto out;
  195         }
  196 
  197         switch (cmd) {
  198         case UDF_GETVOLIDENT:
  199                 if (copy_to_user((char __user *)arg,
  200                                  UDF_SB(inode->i_sb)->s_volume_ident, 32))
  201                         result = -EFAULT;
  202                 else
  203                         result = 0;
  204                 goto out;
  205         case UDF_RELOCATE_BLOCKS:
  206                 if (!capable(CAP_SYS_ADMIN)) {
  207                         result = -EACCES;
  208                         goto out;
  209                 }
  210                 if (get_user(old_block, (long __user *)arg)) {
  211                         result = -EFAULT;
  212                         goto out;
  213                 }
  214                 result = udf_relocate_blocks(inode->i_sb,
  215                                                 old_block, &new_block);
  216                 if (result == 0)
  217                         result = put_user(new_block, (long __user *)arg);
  218                 goto out;
  219         case UDF_GETEASIZE:
  220                 result = put_user(UDF_I(inode)->i_lenEAttr, (int __user *)arg);
  221                 goto out;
  222         case UDF_GETEABLOCK:
  223                 result = copy_to_user((char __user *)arg,
  224                                       UDF_I(inode)->i_ext.i_data,
  225                                       UDF_I(inode)->i_lenEAttr) ? -EFAULT : 0;
  226                 goto out;
  227         }
  228 
  229 out:
  230         return result;
  231 }
  232 
  233 static int udf_release_file(struct inode *inode, struct file *filp)
  234 {
  235         if (filp->f_mode & FMODE_WRITE) {
  236                 down_write(&UDF_I(inode)->i_data_sem);
  237                 udf_discard_prealloc(inode);
  238                 udf_truncate_tail_extent(inode);
  239                 up_write(&UDF_I(inode)->i_data_sem);
  240         }
  241         return 0;
  242 }
  243 
  244 const struct file_operations udf_file_operations = {
  245         .read                   = do_sync_read,
  246         .aio_read               = generic_file_aio_read,
  247         .unlocked_ioctl         = udf_ioctl,
  248         .open                   = generic_file_open,
  249         .mmap                   = generic_file_mmap,
  250         .write                  = do_sync_write,
  251         .aio_write              = udf_file_aio_write,
  252         .release                = udf_release_file,
  253         .fsync                  = generic_file_fsync,
  254         .splice_read            = generic_file_splice_read,
  255         .llseek                 = generic_file_llseek,
  256 };
  257 
  258 static int udf_setattr(struct dentry *dentry, struct iattr *attr)
  259 {
  260         struct inode *inode = dentry->d_inode;
  261         int error;
  262 
  263         error = inode_change_ok(inode, attr);
  264         if (error)
  265                 return error;
  266 
  267         if ((attr->ia_valid & ATTR_SIZE) &&
  268             attr->ia_size != i_size_read(inode)) {
  269                 error = udf_setsize(inode, attr->ia_size);
  270                 if (error)
  271                         return error;
  272         }
  273 
  274         setattr_copy(inode, attr);
  275         mark_inode_dirty(inode);
  276         return 0;
  277 }
  278 
  279 const struct inode_operations udf_file_inode_operations = {
  280         .setattr                = udf_setattr,
  281 };

Cache object: 0d5a251f6130a8668d39367f48a3fb49


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.