18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * inode.c 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * PURPOSE 58c2ecf20Sopenharmony_ci * Inode handling routines for the OSTA-UDF(tm) filesystem. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * COPYRIGHT 88c2ecf20Sopenharmony_ci * This file is distributed under the terms of the GNU General Public 98c2ecf20Sopenharmony_ci * License (GPL). Copies of the GPL can be obtained from: 108c2ecf20Sopenharmony_ci * ftp://prep.ai.mit.edu/pub/gnu/GPL 118c2ecf20Sopenharmony_ci * Each contributing author retains all rights to their own work. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * (C) 1998 Dave Boynton 148c2ecf20Sopenharmony_ci * (C) 1998-2004 Ben Fennema 158c2ecf20Sopenharmony_ci * (C) 1999-2000 Stelias Computing Inc 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * HISTORY 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * 10/04/98 dgb Added rudimentary directory functions 208c2ecf20Sopenharmony_ci * 10/07/98 Fully working udf_block_map! It works! 218c2ecf20Sopenharmony_ci * 11/25/98 bmap altered to better support extents 228c2ecf20Sopenharmony_ci * 12/06/98 blf partition support in udf_iget, udf_block_map 238c2ecf20Sopenharmony_ci * and udf_read_inode 248c2ecf20Sopenharmony_ci * 12/12/98 rewrote udf_block_map to handle next extents and descs across 258c2ecf20Sopenharmony_ci * block boundaries (which is not actually allowed) 268c2ecf20Sopenharmony_ci * 12/20/98 added support for strategy 4096 278c2ecf20Sopenharmony_ci * 03/07/99 rewrote udf_block_map (again) 288c2ecf20Sopenharmony_ci * New funcs, inode_bmap, udf_next_aext 298c2ecf20Sopenharmony_ci * 04/19/99 Support for writing device EA's for major/minor # 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include "udfdecl.h" 338c2ecf20Sopenharmony_ci#include <linux/mm.h> 348c2ecf20Sopenharmony_ci#include <linux/module.h> 358c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 368c2ecf20Sopenharmony_ci#include <linux/writeback.h> 378c2ecf20Sopenharmony_ci#include <linux/slab.h> 388c2ecf20Sopenharmony_ci#include <linux/crc-itu-t.h> 398c2ecf20Sopenharmony_ci#include <linux/mpage.h> 408c2ecf20Sopenharmony_ci#include <linux/uio.h> 418c2ecf20Sopenharmony_ci#include <linux/bio.h> 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#include "udf_i.h" 448c2ecf20Sopenharmony_ci#include "udf_sb.h" 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#define EXTENT_MERGE_SIZE 5 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define FE_MAPPED_PERMS (FE_PERM_U_READ | FE_PERM_U_WRITE | FE_PERM_U_EXEC | \ 498c2ecf20Sopenharmony_ci FE_PERM_G_READ | FE_PERM_G_WRITE | FE_PERM_G_EXEC | \ 508c2ecf20Sopenharmony_ci FE_PERM_O_READ | FE_PERM_O_WRITE | FE_PERM_O_EXEC) 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#define FE_DELETE_PERMS (FE_PERM_U_DELETE | FE_PERM_G_DELETE | \ 538c2ecf20Sopenharmony_ci FE_PERM_O_DELETE) 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic umode_t udf_convert_permissions(struct fileEntry *); 568c2ecf20Sopenharmony_cistatic int udf_update_inode(struct inode *, int); 578c2ecf20Sopenharmony_cistatic int udf_sync_inode(struct inode *inode); 588c2ecf20Sopenharmony_cistatic int udf_alloc_i_data(struct inode *inode, size_t size); 598c2ecf20Sopenharmony_cistatic sector_t inode_getblk(struct inode *, sector_t, int *, int *); 608c2ecf20Sopenharmony_cistatic int udf_insert_aext(struct inode *, struct extent_position, 618c2ecf20Sopenharmony_ci struct kernel_lb_addr, uint32_t); 628c2ecf20Sopenharmony_cistatic void udf_split_extents(struct inode *, int *, int, udf_pblk_t, 638c2ecf20Sopenharmony_ci struct kernel_long_ad *, int *); 648c2ecf20Sopenharmony_cistatic void udf_prealloc_extents(struct inode *, int, int, 658c2ecf20Sopenharmony_ci struct kernel_long_ad *, int *); 668c2ecf20Sopenharmony_cistatic void udf_merge_extents(struct inode *, struct kernel_long_ad *, int *); 678c2ecf20Sopenharmony_cistatic int udf_update_extents(struct inode *, struct kernel_long_ad *, int, 688c2ecf20Sopenharmony_ci int, struct extent_position *); 698c2ecf20Sopenharmony_cistatic int udf_get_block(struct inode *, sector_t, struct buffer_head *, int); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic void __udf_clear_extent_cache(struct inode *inode) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci struct udf_inode_info *iinfo = UDF_I(inode); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (iinfo->cached_extent.lstart != -1) { 768c2ecf20Sopenharmony_ci brelse(iinfo->cached_extent.epos.bh); 778c2ecf20Sopenharmony_ci iinfo->cached_extent.lstart = -1; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci/* Invalidate extent cache */ 828c2ecf20Sopenharmony_cistatic void udf_clear_extent_cache(struct inode *inode) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci struct udf_inode_info *iinfo = UDF_I(inode); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci spin_lock(&iinfo->i_extent_cache_lock); 878c2ecf20Sopenharmony_ci __udf_clear_extent_cache(inode); 888c2ecf20Sopenharmony_ci spin_unlock(&iinfo->i_extent_cache_lock); 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci/* Return contents of extent cache */ 928c2ecf20Sopenharmony_cistatic int udf_read_extent_cache(struct inode *inode, loff_t bcount, 938c2ecf20Sopenharmony_ci loff_t *lbcount, struct extent_position *pos) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci struct udf_inode_info *iinfo = UDF_I(inode); 968c2ecf20Sopenharmony_ci int ret = 0; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci spin_lock(&iinfo->i_extent_cache_lock); 998c2ecf20Sopenharmony_ci if ((iinfo->cached_extent.lstart <= bcount) && 1008c2ecf20Sopenharmony_ci (iinfo->cached_extent.lstart != -1)) { 1018c2ecf20Sopenharmony_ci /* Cache hit */ 1028c2ecf20Sopenharmony_ci *lbcount = iinfo->cached_extent.lstart; 1038c2ecf20Sopenharmony_ci memcpy(pos, &iinfo->cached_extent.epos, 1048c2ecf20Sopenharmony_ci sizeof(struct extent_position)); 1058c2ecf20Sopenharmony_ci if (pos->bh) 1068c2ecf20Sopenharmony_ci get_bh(pos->bh); 1078c2ecf20Sopenharmony_ci ret = 1; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci spin_unlock(&iinfo->i_extent_cache_lock); 1108c2ecf20Sopenharmony_ci return ret; 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci/* Add extent to extent cache */ 1148c2ecf20Sopenharmony_cistatic void udf_update_extent_cache(struct inode *inode, loff_t estart, 1158c2ecf20Sopenharmony_ci struct extent_position *pos) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci struct udf_inode_info *iinfo = UDF_I(inode); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci spin_lock(&iinfo->i_extent_cache_lock); 1208c2ecf20Sopenharmony_ci /* Invalidate previously cached extent */ 1218c2ecf20Sopenharmony_ci __udf_clear_extent_cache(inode); 1228c2ecf20Sopenharmony_ci if (pos->bh) 1238c2ecf20Sopenharmony_ci get_bh(pos->bh); 1248c2ecf20Sopenharmony_ci memcpy(&iinfo->cached_extent.epos, pos, sizeof(*pos)); 1258c2ecf20Sopenharmony_ci iinfo->cached_extent.lstart = estart; 1268c2ecf20Sopenharmony_ci switch (iinfo->i_alloc_type) { 1278c2ecf20Sopenharmony_ci case ICBTAG_FLAG_AD_SHORT: 1288c2ecf20Sopenharmony_ci iinfo->cached_extent.epos.offset -= sizeof(struct short_ad); 1298c2ecf20Sopenharmony_ci break; 1308c2ecf20Sopenharmony_ci case ICBTAG_FLAG_AD_LONG: 1318c2ecf20Sopenharmony_ci iinfo->cached_extent.epos.offset -= sizeof(struct long_ad); 1328c2ecf20Sopenharmony_ci break; 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci spin_unlock(&iinfo->i_extent_cache_lock); 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_civoid udf_evict_inode(struct inode *inode) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci struct udf_inode_info *iinfo = UDF_I(inode); 1408c2ecf20Sopenharmony_ci int want_delete = 0; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci if (!is_bad_inode(inode)) { 1438c2ecf20Sopenharmony_ci if (!inode->i_nlink) { 1448c2ecf20Sopenharmony_ci want_delete = 1; 1458c2ecf20Sopenharmony_ci udf_setsize(inode, 0); 1468c2ecf20Sopenharmony_ci udf_update_inode(inode, IS_SYNC(inode)); 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB && 1498c2ecf20Sopenharmony_ci inode->i_size != iinfo->i_lenExtents) { 1508c2ecf20Sopenharmony_ci udf_warn(inode->i_sb, 1518c2ecf20Sopenharmony_ci "Inode %lu (mode %o) has inode size %llu different from extent length %llu. Filesystem need not be standards compliant.\n", 1528c2ecf20Sopenharmony_ci inode->i_ino, inode->i_mode, 1538c2ecf20Sopenharmony_ci (unsigned long long)inode->i_size, 1548c2ecf20Sopenharmony_ci (unsigned long long)iinfo->i_lenExtents); 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci truncate_inode_pages_final(&inode->i_data); 1588c2ecf20Sopenharmony_ci invalidate_inode_buffers(inode); 1598c2ecf20Sopenharmony_ci clear_inode(inode); 1608c2ecf20Sopenharmony_ci kfree(iinfo->i_data); 1618c2ecf20Sopenharmony_ci iinfo->i_data = NULL; 1628c2ecf20Sopenharmony_ci udf_clear_extent_cache(inode); 1638c2ecf20Sopenharmony_ci if (want_delete) { 1648c2ecf20Sopenharmony_ci udf_free_inode(inode); 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic void udf_write_failed(struct address_space *mapping, loff_t to) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci struct inode *inode = mapping->host; 1718c2ecf20Sopenharmony_ci struct udf_inode_info *iinfo = UDF_I(inode); 1728c2ecf20Sopenharmony_ci loff_t isize = inode->i_size; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (to > isize) { 1758c2ecf20Sopenharmony_ci truncate_pagecache(inode, isize); 1768c2ecf20Sopenharmony_ci if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { 1778c2ecf20Sopenharmony_ci down_write(&iinfo->i_data_sem); 1788c2ecf20Sopenharmony_ci udf_clear_extent_cache(inode); 1798c2ecf20Sopenharmony_ci udf_truncate_extents(inode); 1808c2ecf20Sopenharmony_ci up_write(&iinfo->i_data_sem); 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic int udf_writepage(struct page *page, struct writeback_control *wbc) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci return block_write_full_page(page, udf_get_block, wbc); 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic int udf_writepages(struct address_space *mapping, 1918c2ecf20Sopenharmony_ci struct writeback_control *wbc) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci return mpage_writepages(mapping, wbc, udf_get_block); 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic int udf_readpage(struct file *file, struct page *page) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci return mpage_readpage(page, udf_get_block); 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic void udf_readahead(struct readahead_control *rac) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci mpage_readahead(rac, udf_get_block); 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic int udf_write_begin(struct file *file, struct address_space *mapping, 2078c2ecf20Sopenharmony_ci loff_t pos, unsigned len, unsigned flags, 2088c2ecf20Sopenharmony_ci struct page **pagep, void **fsdata) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci int ret; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci ret = block_write_begin(mapping, pos, len, flags, pagep, udf_get_block); 2138c2ecf20Sopenharmony_ci if (unlikely(ret)) 2148c2ecf20Sopenharmony_ci udf_write_failed(mapping, pos + len); 2158c2ecf20Sopenharmony_ci return ret; 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic ssize_t udf_direct_IO(struct kiocb *iocb, struct iov_iter *iter) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci struct file *file = iocb->ki_filp; 2218c2ecf20Sopenharmony_ci struct address_space *mapping = file->f_mapping; 2228c2ecf20Sopenharmony_ci struct inode *inode = mapping->host; 2238c2ecf20Sopenharmony_ci size_t count = iov_iter_count(iter); 2248c2ecf20Sopenharmony_ci ssize_t ret; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci ret = blockdev_direct_IO(iocb, inode, iter, udf_get_block); 2278c2ecf20Sopenharmony_ci if (unlikely(ret < 0 && iov_iter_rw(iter) == WRITE)) 2288c2ecf20Sopenharmony_ci udf_write_failed(mapping, iocb->ki_pos + count); 2298c2ecf20Sopenharmony_ci return ret; 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic sector_t udf_bmap(struct address_space *mapping, sector_t block) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci return generic_block_bmap(mapping, block, udf_get_block); 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ciconst struct address_space_operations udf_aops = { 2388c2ecf20Sopenharmony_ci .readpage = udf_readpage, 2398c2ecf20Sopenharmony_ci .readahead = udf_readahead, 2408c2ecf20Sopenharmony_ci .writepage = udf_writepage, 2418c2ecf20Sopenharmony_ci .writepages = udf_writepages, 2428c2ecf20Sopenharmony_ci .write_begin = udf_write_begin, 2438c2ecf20Sopenharmony_ci .write_end = generic_write_end, 2448c2ecf20Sopenharmony_ci .direct_IO = udf_direct_IO, 2458c2ecf20Sopenharmony_ci .bmap = udf_bmap, 2468c2ecf20Sopenharmony_ci}; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci/* 2498c2ecf20Sopenharmony_ci * Expand file stored in ICB to a normal one-block-file 2508c2ecf20Sopenharmony_ci * 2518c2ecf20Sopenharmony_ci * This function requires i_data_sem for writing and releases it. 2528c2ecf20Sopenharmony_ci * This function requires i_mutex held 2538c2ecf20Sopenharmony_ci */ 2548c2ecf20Sopenharmony_ciint udf_expand_file_adinicb(struct inode *inode) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci struct page *page; 2578c2ecf20Sopenharmony_ci char *kaddr; 2588c2ecf20Sopenharmony_ci struct udf_inode_info *iinfo = UDF_I(inode); 2598c2ecf20Sopenharmony_ci int err; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci WARN_ON_ONCE(!inode_is_locked(inode)); 2628c2ecf20Sopenharmony_ci if (!iinfo->i_lenAlloc) { 2638c2ecf20Sopenharmony_ci if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD)) 2648c2ecf20Sopenharmony_ci iinfo->i_alloc_type = ICBTAG_FLAG_AD_SHORT; 2658c2ecf20Sopenharmony_ci else 2668c2ecf20Sopenharmony_ci iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG; 2678c2ecf20Sopenharmony_ci /* from now on we have normal address_space methods */ 2688c2ecf20Sopenharmony_ci inode->i_data.a_ops = &udf_aops; 2698c2ecf20Sopenharmony_ci up_write(&iinfo->i_data_sem); 2708c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 2718c2ecf20Sopenharmony_ci return 0; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci /* 2748c2ecf20Sopenharmony_ci * Release i_data_sem so that we can lock a page - page lock ranks 2758c2ecf20Sopenharmony_ci * above i_data_sem. i_mutex still protects us against file changes. 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_ci up_write(&iinfo->i_data_sem); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci page = find_or_create_page(inode->i_mapping, 0, GFP_NOFS); 2808c2ecf20Sopenharmony_ci if (!page) 2818c2ecf20Sopenharmony_ci return -ENOMEM; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if (!PageUptodate(page)) { 2848c2ecf20Sopenharmony_ci kaddr = kmap_atomic(page); 2858c2ecf20Sopenharmony_ci memset(kaddr + iinfo->i_lenAlloc, 0x00, 2868c2ecf20Sopenharmony_ci PAGE_SIZE - iinfo->i_lenAlloc); 2878c2ecf20Sopenharmony_ci memcpy(kaddr, iinfo->i_data + iinfo->i_lenEAttr, 2888c2ecf20Sopenharmony_ci iinfo->i_lenAlloc); 2898c2ecf20Sopenharmony_ci flush_dcache_page(page); 2908c2ecf20Sopenharmony_ci SetPageUptodate(page); 2918c2ecf20Sopenharmony_ci kunmap_atomic(kaddr); 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci down_write(&iinfo->i_data_sem); 2948c2ecf20Sopenharmony_ci memset(iinfo->i_data + iinfo->i_lenEAttr, 0x00, 2958c2ecf20Sopenharmony_ci iinfo->i_lenAlloc); 2968c2ecf20Sopenharmony_ci iinfo->i_lenAlloc = 0; 2978c2ecf20Sopenharmony_ci if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD)) 2988c2ecf20Sopenharmony_ci iinfo->i_alloc_type = ICBTAG_FLAG_AD_SHORT; 2998c2ecf20Sopenharmony_ci else 3008c2ecf20Sopenharmony_ci iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG; 3018c2ecf20Sopenharmony_ci /* from now on we have normal address_space methods */ 3028c2ecf20Sopenharmony_ci inode->i_data.a_ops = &udf_aops; 3038c2ecf20Sopenharmony_ci set_page_dirty(page); 3048c2ecf20Sopenharmony_ci unlock_page(page); 3058c2ecf20Sopenharmony_ci up_write(&iinfo->i_data_sem); 3068c2ecf20Sopenharmony_ci err = filemap_fdatawrite(inode->i_mapping); 3078c2ecf20Sopenharmony_ci if (err) { 3088c2ecf20Sopenharmony_ci /* Restore everything back so that we don't lose data... */ 3098c2ecf20Sopenharmony_ci lock_page(page); 3108c2ecf20Sopenharmony_ci down_write(&iinfo->i_data_sem); 3118c2ecf20Sopenharmony_ci kaddr = kmap_atomic(page); 3128c2ecf20Sopenharmony_ci memcpy(iinfo->i_data + iinfo->i_lenEAttr, kaddr, inode->i_size); 3138c2ecf20Sopenharmony_ci kunmap_atomic(kaddr); 3148c2ecf20Sopenharmony_ci unlock_page(page); 3158c2ecf20Sopenharmony_ci iinfo->i_alloc_type = ICBTAG_FLAG_AD_IN_ICB; 3168c2ecf20Sopenharmony_ci inode->i_data.a_ops = &udf_adinicb_aops; 3178c2ecf20Sopenharmony_ci iinfo->i_lenAlloc = inode->i_size; 3188c2ecf20Sopenharmony_ci up_write(&iinfo->i_data_sem); 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci put_page(page); 3218c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci return err; 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistruct buffer_head *udf_expand_dir_adinicb(struct inode *inode, 3278c2ecf20Sopenharmony_ci udf_pblk_t *block, int *err) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci udf_pblk_t newblock; 3308c2ecf20Sopenharmony_ci struct buffer_head *dbh = NULL; 3318c2ecf20Sopenharmony_ci struct kernel_lb_addr eloc; 3328c2ecf20Sopenharmony_ci uint8_t alloctype; 3338c2ecf20Sopenharmony_ci struct extent_position epos; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci struct udf_fileident_bh sfibh, dfibh; 3368c2ecf20Sopenharmony_ci loff_t f_pos = udf_ext0_offset(inode); 3378c2ecf20Sopenharmony_ci int size = udf_ext0_offset(inode) + inode->i_size; 3388c2ecf20Sopenharmony_ci struct fileIdentDesc cfi, *sfi, *dfi; 3398c2ecf20Sopenharmony_ci struct udf_inode_info *iinfo = UDF_I(inode); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD)) 3428c2ecf20Sopenharmony_ci alloctype = ICBTAG_FLAG_AD_SHORT; 3438c2ecf20Sopenharmony_ci else 3448c2ecf20Sopenharmony_ci alloctype = ICBTAG_FLAG_AD_LONG; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci if (!inode->i_size) { 3478c2ecf20Sopenharmony_ci iinfo->i_alloc_type = alloctype; 3488c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 3498c2ecf20Sopenharmony_ci return NULL; 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci /* alloc block, and copy data to it */ 3538c2ecf20Sopenharmony_ci *block = udf_new_block(inode->i_sb, inode, 3548c2ecf20Sopenharmony_ci iinfo->i_location.partitionReferenceNum, 3558c2ecf20Sopenharmony_ci iinfo->i_location.logicalBlockNum, err); 3568c2ecf20Sopenharmony_ci if (!(*block)) 3578c2ecf20Sopenharmony_ci return NULL; 3588c2ecf20Sopenharmony_ci newblock = udf_get_pblock(inode->i_sb, *block, 3598c2ecf20Sopenharmony_ci iinfo->i_location.partitionReferenceNum, 3608c2ecf20Sopenharmony_ci 0); 3618c2ecf20Sopenharmony_ci if (!newblock) 3628c2ecf20Sopenharmony_ci return NULL; 3638c2ecf20Sopenharmony_ci dbh = udf_tgetblk(inode->i_sb, newblock); 3648c2ecf20Sopenharmony_ci if (!dbh) 3658c2ecf20Sopenharmony_ci return NULL; 3668c2ecf20Sopenharmony_ci lock_buffer(dbh); 3678c2ecf20Sopenharmony_ci memset(dbh->b_data, 0x00, inode->i_sb->s_blocksize); 3688c2ecf20Sopenharmony_ci set_buffer_uptodate(dbh); 3698c2ecf20Sopenharmony_ci unlock_buffer(dbh); 3708c2ecf20Sopenharmony_ci mark_buffer_dirty_inode(dbh, inode); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci sfibh.soffset = sfibh.eoffset = 3738c2ecf20Sopenharmony_ci f_pos & (inode->i_sb->s_blocksize - 1); 3748c2ecf20Sopenharmony_ci sfibh.sbh = sfibh.ebh = NULL; 3758c2ecf20Sopenharmony_ci dfibh.soffset = dfibh.eoffset = 0; 3768c2ecf20Sopenharmony_ci dfibh.sbh = dfibh.ebh = dbh; 3778c2ecf20Sopenharmony_ci while (f_pos < size) { 3788c2ecf20Sopenharmony_ci iinfo->i_alloc_type = ICBTAG_FLAG_AD_IN_ICB; 3798c2ecf20Sopenharmony_ci sfi = udf_fileident_read(inode, &f_pos, &sfibh, &cfi, NULL, 3808c2ecf20Sopenharmony_ci NULL, NULL, NULL); 3818c2ecf20Sopenharmony_ci if (!sfi) { 3828c2ecf20Sopenharmony_ci brelse(dbh); 3838c2ecf20Sopenharmony_ci return NULL; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci iinfo->i_alloc_type = alloctype; 3868c2ecf20Sopenharmony_ci sfi->descTag.tagLocation = cpu_to_le32(*block); 3878c2ecf20Sopenharmony_ci dfibh.soffset = dfibh.eoffset; 3888c2ecf20Sopenharmony_ci dfibh.eoffset += (sfibh.eoffset - sfibh.soffset); 3898c2ecf20Sopenharmony_ci dfi = (struct fileIdentDesc *)(dbh->b_data + dfibh.soffset); 3908c2ecf20Sopenharmony_ci if (udf_write_fi(inode, sfi, dfi, &dfibh, sfi->impUse, 3918c2ecf20Sopenharmony_ci sfi->fileIdent + 3928c2ecf20Sopenharmony_ci le16_to_cpu(sfi->lengthOfImpUse))) { 3938c2ecf20Sopenharmony_ci iinfo->i_alloc_type = ICBTAG_FLAG_AD_IN_ICB; 3948c2ecf20Sopenharmony_ci brelse(dbh); 3958c2ecf20Sopenharmony_ci return NULL; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci mark_buffer_dirty_inode(dbh, inode); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci memset(iinfo->i_data + iinfo->i_lenEAttr, 0, iinfo->i_lenAlloc); 4018c2ecf20Sopenharmony_ci iinfo->i_lenAlloc = 0; 4028c2ecf20Sopenharmony_ci eloc.logicalBlockNum = *block; 4038c2ecf20Sopenharmony_ci eloc.partitionReferenceNum = 4048c2ecf20Sopenharmony_ci iinfo->i_location.partitionReferenceNum; 4058c2ecf20Sopenharmony_ci iinfo->i_lenExtents = inode->i_size; 4068c2ecf20Sopenharmony_ci epos.bh = NULL; 4078c2ecf20Sopenharmony_ci epos.block = iinfo->i_location; 4088c2ecf20Sopenharmony_ci epos.offset = udf_file_entry_alloc_offset(inode); 4098c2ecf20Sopenharmony_ci udf_add_aext(inode, &epos, &eloc, inode->i_size, 0); 4108c2ecf20Sopenharmony_ci /* UniqueID stuff */ 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci brelse(epos.bh); 4138c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 4148c2ecf20Sopenharmony_ci return dbh; 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic int udf_get_block(struct inode *inode, sector_t block, 4188c2ecf20Sopenharmony_ci struct buffer_head *bh_result, int create) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci int err, new; 4218c2ecf20Sopenharmony_ci sector_t phys = 0; 4228c2ecf20Sopenharmony_ci struct udf_inode_info *iinfo; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci if (!create) { 4258c2ecf20Sopenharmony_ci phys = udf_block_map(inode, block); 4268c2ecf20Sopenharmony_ci if (phys) 4278c2ecf20Sopenharmony_ci map_bh(bh_result, inode->i_sb, phys); 4288c2ecf20Sopenharmony_ci return 0; 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci err = -EIO; 4328c2ecf20Sopenharmony_ci new = 0; 4338c2ecf20Sopenharmony_ci iinfo = UDF_I(inode); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci down_write(&iinfo->i_data_sem); 4368c2ecf20Sopenharmony_ci if (block == iinfo->i_next_alloc_block + 1) { 4378c2ecf20Sopenharmony_ci iinfo->i_next_alloc_block++; 4388c2ecf20Sopenharmony_ci iinfo->i_next_alloc_goal++; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci /* 4428c2ecf20Sopenharmony_ci * Block beyond EOF and prealloc extents? Just discard preallocation 4438c2ecf20Sopenharmony_ci * as it is not useful and complicates things. 4448c2ecf20Sopenharmony_ci */ 4458c2ecf20Sopenharmony_ci if (((loff_t)block) << inode->i_blkbits >= iinfo->i_lenExtents) 4468c2ecf20Sopenharmony_ci udf_discard_prealloc(inode); 4478c2ecf20Sopenharmony_ci udf_clear_extent_cache(inode); 4488c2ecf20Sopenharmony_ci phys = inode_getblk(inode, block, &err, &new); 4498c2ecf20Sopenharmony_ci if (!phys) 4508c2ecf20Sopenharmony_ci goto abort; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (new) 4538c2ecf20Sopenharmony_ci set_buffer_new(bh_result); 4548c2ecf20Sopenharmony_ci map_bh(bh_result, inode->i_sb, phys); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ciabort: 4578c2ecf20Sopenharmony_ci up_write(&iinfo->i_data_sem); 4588c2ecf20Sopenharmony_ci return err; 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistatic struct buffer_head *udf_getblk(struct inode *inode, udf_pblk_t block, 4628c2ecf20Sopenharmony_ci int create, int *err) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci struct buffer_head *bh; 4658c2ecf20Sopenharmony_ci struct buffer_head dummy; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci dummy.b_state = 0; 4688c2ecf20Sopenharmony_ci dummy.b_blocknr = -1000; 4698c2ecf20Sopenharmony_ci *err = udf_get_block(inode, block, &dummy, create); 4708c2ecf20Sopenharmony_ci if (!*err && buffer_mapped(&dummy)) { 4718c2ecf20Sopenharmony_ci bh = sb_getblk(inode->i_sb, dummy.b_blocknr); 4728c2ecf20Sopenharmony_ci if (buffer_new(&dummy)) { 4738c2ecf20Sopenharmony_ci lock_buffer(bh); 4748c2ecf20Sopenharmony_ci memset(bh->b_data, 0x00, inode->i_sb->s_blocksize); 4758c2ecf20Sopenharmony_ci set_buffer_uptodate(bh); 4768c2ecf20Sopenharmony_ci unlock_buffer(bh); 4778c2ecf20Sopenharmony_ci mark_buffer_dirty_inode(bh, inode); 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci return bh; 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci return NULL; 4838c2ecf20Sopenharmony_ci} 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci/* Extend the file with new blocks totaling 'new_block_bytes', 4868c2ecf20Sopenharmony_ci * return the number of extents added 4878c2ecf20Sopenharmony_ci */ 4888c2ecf20Sopenharmony_cistatic int udf_do_extend_file(struct inode *inode, 4898c2ecf20Sopenharmony_ci struct extent_position *last_pos, 4908c2ecf20Sopenharmony_ci struct kernel_long_ad *last_ext, 4918c2ecf20Sopenharmony_ci loff_t new_block_bytes) 4928c2ecf20Sopenharmony_ci{ 4938c2ecf20Sopenharmony_ci uint32_t add; 4948c2ecf20Sopenharmony_ci int count = 0, fake = !(last_ext->extLength & UDF_EXTENT_LENGTH_MASK); 4958c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 4968c2ecf20Sopenharmony_ci struct udf_inode_info *iinfo; 4978c2ecf20Sopenharmony_ci int err; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci /* The previous extent is fake and we should not extend by anything 5008c2ecf20Sopenharmony_ci * - there's nothing to do... */ 5018c2ecf20Sopenharmony_ci if (!new_block_bytes && fake) 5028c2ecf20Sopenharmony_ci return 0; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci iinfo = UDF_I(inode); 5058c2ecf20Sopenharmony_ci /* Round the last extent up to a multiple of block size */ 5068c2ecf20Sopenharmony_ci if (last_ext->extLength & (sb->s_blocksize - 1)) { 5078c2ecf20Sopenharmony_ci last_ext->extLength = 5088c2ecf20Sopenharmony_ci (last_ext->extLength & UDF_EXTENT_FLAG_MASK) | 5098c2ecf20Sopenharmony_ci (((last_ext->extLength & UDF_EXTENT_LENGTH_MASK) + 5108c2ecf20Sopenharmony_ci sb->s_blocksize - 1) & ~(sb->s_blocksize - 1)); 5118c2ecf20Sopenharmony_ci iinfo->i_lenExtents = 5128c2ecf20Sopenharmony_ci (iinfo->i_lenExtents + sb->s_blocksize - 1) & 5138c2ecf20Sopenharmony_ci ~(sb->s_blocksize - 1); 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci /* Can we merge with the previous extent? */ 5178c2ecf20Sopenharmony_ci if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) == 5188c2ecf20Sopenharmony_ci EXT_NOT_RECORDED_NOT_ALLOCATED) { 5198c2ecf20Sopenharmony_ci add = (1 << 30) - sb->s_blocksize - 5208c2ecf20Sopenharmony_ci (last_ext->extLength & UDF_EXTENT_LENGTH_MASK); 5218c2ecf20Sopenharmony_ci if (add > new_block_bytes) 5228c2ecf20Sopenharmony_ci add = new_block_bytes; 5238c2ecf20Sopenharmony_ci new_block_bytes -= add; 5248c2ecf20Sopenharmony_ci last_ext->extLength += add; 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci if (fake) { 5288c2ecf20Sopenharmony_ci err = udf_add_aext(inode, last_pos, &last_ext->extLocation, 5298c2ecf20Sopenharmony_ci last_ext->extLength, 1); 5308c2ecf20Sopenharmony_ci if (err < 0) 5318c2ecf20Sopenharmony_ci goto out_err; 5328c2ecf20Sopenharmony_ci count++; 5338c2ecf20Sopenharmony_ci } else { 5348c2ecf20Sopenharmony_ci struct kernel_lb_addr tmploc; 5358c2ecf20Sopenharmony_ci uint32_t tmplen; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci udf_write_aext(inode, last_pos, &last_ext->extLocation, 5388c2ecf20Sopenharmony_ci last_ext->extLength, 1); 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci /* 5418c2ecf20Sopenharmony_ci * We've rewritten the last extent. If we are going to add 5428c2ecf20Sopenharmony_ci * more extents, we may need to enter possible following 5438c2ecf20Sopenharmony_ci * empty indirect extent. 5448c2ecf20Sopenharmony_ci */ 5458c2ecf20Sopenharmony_ci if (new_block_bytes) 5468c2ecf20Sopenharmony_ci udf_next_aext(inode, last_pos, &tmploc, &tmplen, 0); 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci /* Managed to do everything necessary? */ 5508c2ecf20Sopenharmony_ci if (!new_block_bytes) 5518c2ecf20Sopenharmony_ci goto out; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci /* All further extents will be NOT_RECORDED_NOT_ALLOCATED */ 5548c2ecf20Sopenharmony_ci last_ext->extLocation.logicalBlockNum = 0; 5558c2ecf20Sopenharmony_ci last_ext->extLocation.partitionReferenceNum = 0; 5568c2ecf20Sopenharmony_ci add = (1 << 30) - sb->s_blocksize; 5578c2ecf20Sopenharmony_ci last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | add; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci /* Create enough extents to cover the whole hole */ 5608c2ecf20Sopenharmony_ci while (new_block_bytes > add) { 5618c2ecf20Sopenharmony_ci new_block_bytes -= add; 5628c2ecf20Sopenharmony_ci err = udf_add_aext(inode, last_pos, &last_ext->extLocation, 5638c2ecf20Sopenharmony_ci last_ext->extLength, 1); 5648c2ecf20Sopenharmony_ci if (err) 5658c2ecf20Sopenharmony_ci goto out_err; 5668c2ecf20Sopenharmony_ci count++; 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci if (new_block_bytes) { 5698c2ecf20Sopenharmony_ci last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | 5708c2ecf20Sopenharmony_ci new_block_bytes; 5718c2ecf20Sopenharmony_ci err = udf_add_aext(inode, last_pos, &last_ext->extLocation, 5728c2ecf20Sopenharmony_ci last_ext->extLength, 1); 5738c2ecf20Sopenharmony_ci if (err) 5748c2ecf20Sopenharmony_ci goto out_err; 5758c2ecf20Sopenharmony_ci count++; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ciout: 5798c2ecf20Sopenharmony_ci /* last_pos should point to the last written extent... */ 5808c2ecf20Sopenharmony_ci if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) 5818c2ecf20Sopenharmony_ci last_pos->offset -= sizeof(struct short_ad); 5828c2ecf20Sopenharmony_ci else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG) 5838c2ecf20Sopenharmony_ci last_pos->offset -= sizeof(struct long_ad); 5848c2ecf20Sopenharmony_ci else 5858c2ecf20Sopenharmony_ci return -EIO; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci return count; 5888c2ecf20Sopenharmony_ciout_err: 5898c2ecf20Sopenharmony_ci /* Remove extents we've created so far */ 5908c2ecf20Sopenharmony_ci udf_clear_extent_cache(inode); 5918c2ecf20Sopenharmony_ci udf_truncate_extents(inode); 5928c2ecf20Sopenharmony_ci return err; 5938c2ecf20Sopenharmony_ci} 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci/* Extend the final block of the file to final_block_len bytes */ 5968c2ecf20Sopenharmony_cistatic void udf_do_extend_final_block(struct inode *inode, 5978c2ecf20Sopenharmony_ci struct extent_position *last_pos, 5988c2ecf20Sopenharmony_ci struct kernel_long_ad *last_ext, 5998c2ecf20Sopenharmony_ci uint32_t new_elen) 6008c2ecf20Sopenharmony_ci{ 6018c2ecf20Sopenharmony_ci uint32_t added_bytes; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci /* 6048c2ecf20Sopenharmony_ci * Extent already large enough? It may be already rounded up to block 6058c2ecf20Sopenharmony_ci * size... 6068c2ecf20Sopenharmony_ci */ 6078c2ecf20Sopenharmony_ci if (new_elen <= (last_ext->extLength & UDF_EXTENT_LENGTH_MASK)) 6088c2ecf20Sopenharmony_ci return; 6098c2ecf20Sopenharmony_ci added_bytes = new_elen - (last_ext->extLength & UDF_EXTENT_LENGTH_MASK); 6108c2ecf20Sopenharmony_ci last_ext->extLength += added_bytes; 6118c2ecf20Sopenharmony_ci UDF_I(inode)->i_lenExtents += added_bytes; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci udf_write_aext(inode, last_pos, &last_ext->extLocation, 6148c2ecf20Sopenharmony_ci last_ext->extLength, 1); 6158c2ecf20Sopenharmony_ci} 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_cistatic int udf_extend_file(struct inode *inode, loff_t newsize) 6188c2ecf20Sopenharmony_ci{ 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci struct extent_position epos; 6218c2ecf20Sopenharmony_ci struct kernel_lb_addr eloc; 6228c2ecf20Sopenharmony_ci uint32_t elen; 6238c2ecf20Sopenharmony_ci int8_t etype; 6248c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 6258c2ecf20Sopenharmony_ci sector_t first_block = newsize >> sb->s_blocksize_bits, offset; 6268c2ecf20Sopenharmony_ci loff_t new_elen; 6278c2ecf20Sopenharmony_ci int adsize; 6288c2ecf20Sopenharmony_ci struct udf_inode_info *iinfo = UDF_I(inode); 6298c2ecf20Sopenharmony_ci struct kernel_long_ad extent; 6308c2ecf20Sopenharmony_ci int err = 0; 6318c2ecf20Sopenharmony_ci bool within_last_ext; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) 6348c2ecf20Sopenharmony_ci adsize = sizeof(struct short_ad); 6358c2ecf20Sopenharmony_ci else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG) 6368c2ecf20Sopenharmony_ci adsize = sizeof(struct long_ad); 6378c2ecf20Sopenharmony_ci else 6388c2ecf20Sopenharmony_ci BUG(); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci /* 6418c2ecf20Sopenharmony_ci * When creating hole in file, just don't bother with preserving 6428c2ecf20Sopenharmony_ci * preallocation. It likely won't be very useful anyway. 6438c2ecf20Sopenharmony_ci */ 6448c2ecf20Sopenharmony_ci udf_discard_prealloc(inode); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset); 6478c2ecf20Sopenharmony_ci within_last_ext = (etype != -1); 6488c2ecf20Sopenharmony_ci /* We don't expect extents past EOF... */ 6498c2ecf20Sopenharmony_ci WARN_ON_ONCE(within_last_ext && 6508c2ecf20Sopenharmony_ci elen > ((loff_t)offset + 1) << inode->i_blkbits); 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci if ((!epos.bh && epos.offset == udf_file_entry_alloc_offset(inode)) || 6538c2ecf20Sopenharmony_ci (epos.bh && epos.offset == sizeof(struct allocExtDesc))) { 6548c2ecf20Sopenharmony_ci /* File has no extents at all or has empty last 6558c2ecf20Sopenharmony_ci * indirect extent! Create a fake extent... */ 6568c2ecf20Sopenharmony_ci extent.extLocation.logicalBlockNum = 0; 6578c2ecf20Sopenharmony_ci extent.extLocation.partitionReferenceNum = 0; 6588c2ecf20Sopenharmony_ci extent.extLength = EXT_NOT_RECORDED_NOT_ALLOCATED; 6598c2ecf20Sopenharmony_ci } else { 6608c2ecf20Sopenharmony_ci epos.offset -= adsize; 6618c2ecf20Sopenharmony_ci etype = udf_next_aext(inode, &epos, &extent.extLocation, 6628c2ecf20Sopenharmony_ci &extent.extLength, 0); 6638c2ecf20Sopenharmony_ci extent.extLength |= etype << 30; 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci new_elen = ((loff_t)offset << inode->i_blkbits) | 6678c2ecf20Sopenharmony_ci (newsize & (sb->s_blocksize - 1)); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci /* File has extent covering the new size (could happen when extending 6708c2ecf20Sopenharmony_ci * inside a block)? 6718c2ecf20Sopenharmony_ci */ 6728c2ecf20Sopenharmony_ci if (within_last_ext) { 6738c2ecf20Sopenharmony_ci /* Extending file within the last file block */ 6748c2ecf20Sopenharmony_ci udf_do_extend_final_block(inode, &epos, &extent, new_elen); 6758c2ecf20Sopenharmony_ci } else { 6768c2ecf20Sopenharmony_ci err = udf_do_extend_file(inode, &epos, &extent, new_elen); 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci if (err < 0) 6808c2ecf20Sopenharmony_ci goto out; 6818c2ecf20Sopenharmony_ci err = 0; 6828c2ecf20Sopenharmony_ci iinfo->i_lenExtents = newsize; 6838c2ecf20Sopenharmony_ciout: 6848c2ecf20Sopenharmony_ci brelse(epos.bh); 6858c2ecf20Sopenharmony_ci return err; 6868c2ecf20Sopenharmony_ci} 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_cistatic sector_t inode_getblk(struct inode *inode, sector_t block, 6898c2ecf20Sopenharmony_ci int *err, int *new) 6908c2ecf20Sopenharmony_ci{ 6918c2ecf20Sopenharmony_ci struct kernel_long_ad laarr[EXTENT_MERGE_SIZE]; 6928c2ecf20Sopenharmony_ci struct extent_position prev_epos, cur_epos, next_epos; 6938c2ecf20Sopenharmony_ci int count = 0, startnum = 0, endnum = 0; 6948c2ecf20Sopenharmony_ci uint32_t elen = 0, tmpelen; 6958c2ecf20Sopenharmony_ci struct kernel_lb_addr eloc, tmpeloc; 6968c2ecf20Sopenharmony_ci int c = 1; 6978c2ecf20Sopenharmony_ci loff_t lbcount = 0, b_off = 0; 6988c2ecf20Sopenharmony_ci udf_pblk_t newblocknum, newblock = 0; 6998c2ecf20Sopenharmony_ci sector_t offset = 0; 7008c2ecf20Sopenharmony_ci int8_t etype; 7018c2ecf20Sopenharmony_ci struct udf_inode_info *iinfo = UDF_I(inode); 7028c2ecf20Sopenharmony_ci udf_pblk_t goal = 0, pgoal = iinfo->i_location.logicalBlockNum; 7038c2ecf20Sopenharmony_ci int lastblock = 0; 7048c2ecf20Sopenharmony_ci bool isBeyondEOF; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci *err = 0; 7078c2ecf20Sopenharmony_ci *new = 0; 7088c2ecf20Sopenharmony_ci prev_epos.offset = udf_file_entry_alloc_offset(inode); 7098c2ecf20Sopenharmony_ci prev_epos.block = iinfo->i_location; 7108c2ecf20Sopenharmony_ci prev_epos.bh = NULL; 7118c2ecf20Sopenharmony_ci cur_epos = next_epos = prev_epos; 7128c2ecf20Sopenharmony_ci b_off = (loff_t)block << inode->i_sb->s_blocksize_bits; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci /* find the extent which contains the block we are looking for. 7158c2ecf20Sopenharmony_ci alternate between laarr[0] and laarr[1] for locations of the 7168c2ecf20Sopenharmony_ci current extent, and the previous extent */ 7178c2ecf20Sopenharmony_ci do { 7188c2ecf20Sopenharmony_ci if (prev_epos.bh != cur_epos.bh) { 7198c2ecf20Sopenharmony_ci brelse(prev_epos.bh); 7208c2ecf20Sopenharmony_ci get_bh(cur_epos.bh); 7218c2ecf20Sopenharmony_ci prev_epos.bh = cur_epos.bh; 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci if (cur_epos.bh != next_epos.bh) { 7248c2ecf20Sopenharmony_ci brelse(cur_epos.bh); 7258c2ecf20Sopenharmony_ci get_bh(next_epos.bh); 7268c2ecf20Sopenharmony_ci cur_epos.bh = next_epos.bh; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci lbcount += elen; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci prev_epos.block = cur_epos.block; 7328c2ecf20Sopenharmony_ci cur_epos.block = next_epos.block; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci prev_epos.offset = cur_epos.offset; 7358c2ecf20Sopenharmony_ci cur_epos.offset = next_epos.offset; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 1); 7388c2ecf20Sopenharmony_ci if (etype == -1) 7398c2ecf20Sopenharmony_ci break; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci c = !c; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci laarr[c].extLength = (etype << 30) | elen; 7448c2ecf20Sopenharmony_ci laarr[c].extLocation = eloc; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci if (etype != (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) 7478c2ecf20Sopenharmony_ci pgoal = eloc.logicalBlockNum + 7488c2ecf20Sopenharmony_ci ((elen + inode->i_sb->s_blocksize - 1) >> 7498c2ecf20Sopenharmony_ci inode->i_sb->s_blocksize_bits); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci count++; 7528c2ecf20Sopenharmony_ci } while (lbcount + elen <= b_off); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci b_off -= lbcount; 7558c2ecf20Sopenharmony_ci offset = b_off >> inode->i_sb->s_blocksize_bits; 7568c2ecf20Sopenharmony_ci /* 7578c2ecf20Sopenharmony_ci * Move prev_epos and cur_epos into indirect extent if we are at 7588c2ecf20Sopenharmony_ci * the pointer to it 7598c2ecf20Sopenharmony_ci */ 7608c2ecf20Sopenharmony_ci udf_next_aext(inode, &prev_epos, &tmpeloc, &tmpelen, 0); 7618c2ecf20Sopenharmony_ci udf_next_aext(inode, &cur_epos, &tmpeloc, &tmpelen, 0); 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci /* if the extent is allocated and recorded, return the block 7648c2ecf20Sopenharmony_ci if the extent is not a multiple of the blocksize, round up */ 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci if (etype == (EXT_RECORDED_ALLOCATED >> 30)) { 7678c2ecf20Sopenharmony_ci if (elen & (inode->i_sb->s_blocksize - 1)) { 7688c2ecf20Sopenharmony_ci elen = EXT_RECORDED_ALLOCATED | 7698c2ecf20Sopenharmony_ci ((elen + inode->i_sb->s_blocksize - 1) & 7708c2ecf20Sopenharmony_ci ~(inode->i_sb->s_blocksize - 1)); 7718c2ecf20Sopenharmony_ci udf_write_aext(inode, &cur_epos, &eloc, elen, 1); 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci newblock = udf_get_lb_pblock(inode->i_sb, &eloc, offset); 7748c2ecf20Sopenharmony_ci goto out_free; 7758c2ecf20Sopenharmony_ci } 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci /* Are we beyond EOF and preallocated extent? */ 7788c2ecf20Sopenharmony_ci if (etype == -1) { 7798c2ecf20Sopenharmony_ci int ret; 7808c2ecf20Sopenharmony_ci loff_t hole_len; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci isBeyondEOF = true; 7838c2ecf20Sopenharmony_ci if (count) { 7848c2ecf20Sopenharmony_ci if (c) 7858c2ecf20Sopenharmony_ci laarr[0] = laarr[1]; 7868c2ecf20Sopenharmony_ci startnum = 1; 7878c2ecf20Sopenharmony_ci } else { 7888c2ecf20Sopenharmony_ci /* Create a fake extent when there's not one */ 7898c2ecf20Sopenharmony_ci memset(&laarr[0].extLocation, 0x00, 7908c2ecf20Sopenharmony_ci sizeof(struct kernel_lb_addr)); 7918c2ecf20Sopenharmony_ci laarr[0].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED; 7928c2ecf20Sopenharmony_ci /* Will udf_do_extend_file() create real extent from 7938c2ecf20Sopenharmony_ci a fake one? */ 7948c2ecf20Sopenharmony_ci startnum = (offset > 0); 7958c2ecf20Sopenharmony_ci } 7968c2ecf20Sopenharmony_ci /* Create extents for the hole between EOF and offset */ 7978c2ecf20Sopenharmony_ci hole_len = (loff_t)offset << inode->i_blkbits; 7988c2ecf20Sopenharmony_ci ret = udf_do_extend_file(inode, &prev_epos, laarr, hole_len); 7998c2ecf20Sopenharmony_ci if (ret < 0) { 8008c2ecf20Sopenharmony_ci *err = ret; 8018c2ecf20Sopenharmony_ci goto out_free; 8028c2ecf20Sopenharmony_ci } 8038c2ecf20Sopenharmony_ci c = 0; 8048c2ecf20Sopenharmony_ci offset = 0; 8058c2ecf20Sopenharmony_ci count += ret; 8068c2ecf20Sopenharmony_ci /* 8078c2ecf20Sopenharmony_ci * Is there any real extent? - otherwise we overwrite the fake 8088c2ecf20Sopenharmony_ci * one... 8098c2ecf20Sopenharmony_ci */ 8108c2ecf20Sopenharmony_ci if (count) 8118c2ecf20Sopenharmony_ci c = !c; 8128c2ecf20Sopenharmony_ci laarr[c].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | 8138c2ecf20Sopenharmony_ci inode->i_sb->s_blocksize; 8148c2ecf20Sopenharmony_ci memset(&laarr[c].extLocation, 0x00, 8158c2ecf20Sopenharmony_ci sizeof(struct kernel_lb_addr)); 8168c2ecf20Sopenharmony_ci count++; 8178c2ecf20Sopenharmony_ci endnum = c + 1; 8188c2ecf20Sopenharmony_ci lastblock = 1; 8198c2ecf20Sopenharmony_ci } else { 8208c2ecf20Sopenharmony_ci isBeyondEOF = false; 8218c2ecf20Sopenharmony_ci endnum = startnum = ((count > 2) ? 2 : count); 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci /* if the current extent is in position 0, 8248c2ecf20Sopenharmony_ci swap it with the previous */ 8258c2ecf20Sopenharmony_ci if (!c && count != 1) { 8268c2ecf20Sopenharmony_ci laarr[2] = laarr[0]; 8278c2ecf20Sopenharmony_ci laarr[0] = laarr[1]; 8288c2ecf20Sopenharmony_ci laarr[1] = laarr[2]; 8298c2ecf20Sopenharmony_ci c = 1; 8308c2ecf20Sopenharmony_ci } 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci /* if the current block is located in an extent, 8338c2ecf20Sopenharmony_ci read the next extent */ 8348c2ecf20Sopenharmony_ci etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 0); 8358c2ecf20Sopenharmony_ci if (etype != -1) { 8368c2ecf20Sopenharmony_ci laarr[c + 1].extLength = (etype << 30) | elen; 8378c2ecf20Sopenharmony_ci laarr[c + 1].extLocation = eloc; 8388c2ecf20Sopenharmony_ci count++; 8398c2ecf20Sopenharmony_ci startnum++; 8408c2ecf20Sopenharmony_ci endnum++; 8418c2ecf20Sopenharmony_ci } else 8428c2ecf20Sopenharmony_ci lastblock = 1; 8438c2ecf20Sopenharmony_ci } 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci /* if the current extent is not recorded but allocated, get the 8468c2ecf20Sopenharmony_ci * block in the extent corresponding to the requested block */ 8478c2ecf20Sopenharmony_ci if ((laarr[c].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30)) 8488c2ecf20Sopenharmony_ci newblocknum = laarr[c].extLocation.logicalBlockNum + offset; 8498c2ecf20Sopenharmony_ci else { /* otherwise, allocate a new block */ 8508c2ecf20Sopenharmony_ci if (iinfo->i_next_alloc_block == block) 8518c2ecf20Sopenharmony_ci goal = iinfo->i_next_alloc_goal; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci if (!goal) { 8548c2ecf20Sopenharmony_ci if (!(goal = pgoal)) /* XXX: what was intended here? */ 8558c2ecf20Sopenharmony_ci goal = iinfo->i_location.logicalBlockNum + 1; 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci newblocknum = udf_new_block(inode->i_sb, inode, 8598c2ecf20Sopenharmony_ci iinfo->i_location.partitionReferenceNum, 8608c2ecf20Sopenharmony_ci goal, err); 8618c2ecf20Sopenharmony_ci if (!newblocknum) { 8628c2ecf20Sopenharmony_ci *err = -ENOSPC; 8638c2ecf20Sopenharmony_ci goto out_free; 8648c2ecf20Sopenharmony_ci } 8658c2ecf20Sopenharmony_ci if (isBeyondEOF) 8668c2ecf20Sopenharmony_ci iinfo->i_lenExtents += inode->i_sb->s_blocksize; 8678c2ecf20Sopenharmony_ci } 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci /* if the extent the requsted block is located in contains multiple 8708c2ecf20Sopenharmony_ci * blocks, split the extent into at most three extents. blocks prior 8718c2ecf20Sopenharmony_ci * to requested block, requested block, and blocks after requested 8728c2ecf20Sopenharmony_ci * block */ 8738c2ecf20Sopenharmony_ci udf_split_extents(inode, &c, offset, newblocknum, laarr, &endnum); 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci /* We preallocate blocks only for regular files. It also makes sense 8768c2ecf20Sopenharmony_ci * for directories but there's a problem when to drop the 8778c2ecf20Sopenharmony_ci * preallocation. We might use some delayed work for that but I feel 8788c2ecf20Sopenharmony_ci * it's overengineering for a filesystem like UDF. */ 8798c2ecf20Sopenharmony_ci if (S_ISREG(inode->i_mode)) 8808c2ecf20Sopenharmony_ci udf_prealloc_extents(inode, c, lastblock, laarr, &endnum); 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci /* merge any continuous blocks in laarr */ 8838c2ecf20Sopenharmony_ci udf_merge_extents(inode, laarr, &endnum); 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci /* write back the new extents, inserting new extents if the new number 8868c2ecf20Sopenharmony_ci * of extents is greater than the old number, and deleting extents if 8878c2ecf20Sopenharmony_ci * the new number of extents is less than the old number */ 8888c2ecf20Sopenharmony_ci *err = udf_update_extents(inode, laarr, startnum, endnum, &prev_epos); 8898c2ecf20Sopenharmony_ci if (*err < 0) 8908c2ecf20Sopenharmony_ci goto out_free; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci newblock = udf_get_pblock(inode->i_sb, newblocknum, 8938c2ecf20Sopenharmony_ci iinfo->i_location.partitionReferenceNum, 0); 8948c2ecf20Sopenharmony_ci if (!newblock) { 8958c2ecf20Sopenharmony_ci *err = -EIO; 8968c2ecf20Sopenharmony_ci goto out_free; 8978c2ecf20Sopenharmony_ci } 8988c2ecf20Sopenharmony_ci *new = 1; 8998c2ecf20Sopenharmony_ci iinfo->i_next_alloc_block = block; 9008c2ecf20Sopenharmony_ci iinfo->i_next_alloc_goal = newblocknum; 9018c2ecf20Sopenharmony_ci inode->i_ctime = current_time(inode); 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci if (IS_SYNC(inode)) 9048c2ecf20Sopenharmony_ci udf_sync_inode(inode); 9058c2ecf20Sopenharmony_ci else 9068c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 9078c2ecf20Sopenharmony_ciout_free: 9088c2ecf20Sopenharmony_ci brelse(prev_epos.bh); 9098c2ecf20Sopenharmony_ci brelse(cur_epos.bh); 9108c2ecf20Sopenharmony_ci brelse(next_epos.bh); 9118c2ecf20Sopenharmony_ci return newblock; 9128c2ecf20Sopenharmony_ci} 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_cistatic void udf_split_extents(struct inode *inode, int *c, int offset, 9158c2ecf20Sopenharmony_ci udf_pblk_t newblocknum, 9168c2ecf20Sopenharmony_ci struct kernel_long_ad *laarr, int *endnum) 9178c2ecf20Sopenharmony_ci{ 9188c2ecf20Sopenharmony_ci unsigned long blocksize = inode->i_sb->s_blocksize; 9198c2ecf20Sopenharmony_ci unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci if ((laarr[*c].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30) || 9228c2ecf20Sopenharmony_ci (laarr[*c].extLength >> 30) == 9238c2ecf20Sopenharmony_ci (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) { 9248c2ecf20Sopenharmony_ci int curr = *c; 9258c2ecf20Sopenharmony_ci int blen = ((laarr[curr].extLength & UDF_EXTENT_LENGTH_MASK) + 9268c2ecf20Sopenharmony_ci blocksize - 1) >> blocksize_bits; 9278c2ecf20Sopenharmony_ci int8_t etype = (laarr[curr].extLength >> 30); 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci if (blen == 1) 9308c2ecf20Sopenharmony_ci ; 9318c2ecf20Sopenharmony_ci else if (!offset || blen == offset + 1) { 9328c2ecf20Sopenharmony_ci laarr[curr + 2] = laarr[curr + 1]; 9338c2ecf20Sopenharmony_ci laarr[curr + 1] = laarr[curr]; 9348c2ecf20Sopenharmony_ci } else { 9358c2ecf20Sopenharmony_ci laarr[curr + 3] = laarr[curr + 1]; 9368c2ecf20Sopenharmony_ci laarr[curr + 2] = laarr[curr + 1] = laarr[curr]; 9378c2ecf20Sopenharmony_ci } 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci if (offset) { 9408c2ecf20Sopenharmony_ci if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) { 9418c2ecf20Sopenharmony_ci udf_free_blocks(inode->i_sb, inode, 9428c2ecf20Sopenharmony_ci &laarr[curr].extLocation, 9438c2ecf20Sopenharmony_ci 0, offset); 9448c2ecf20Sopenharmony_ci laarr[curr].extLength = 9458c2ecf20Sopenharmony_ci EXT_NOT_RECORDED_NOT_ALLOCATED | 9468c2ecf20Sopenharmony_ci (offset << blocksize_bits); 9478c2ecf20Sopenharmony_ci laarr[curr].extLocation.logicalBlockNum = 0; 9488c2ecf20Sopenharmony_ci laarr[curr].extLocation. 9498c2ecf20Sopenharmony_ci partitionReferenceNum = 0; 9508c2ecf20Sopenharmony_ci } else 9518c2ecf20Sopenharmony_ci laarr[curr].extLength = (etype << 30) | 9528c2ecf20Sopenharmony_ci (offset << blocksize_bits); 9538c2ecf20Sopenharmony_ci curr++; 9548c2ecf20Sopenharmony_ci (*c)++; 9558c2ecf20Sopenharmony_ci (*endnum)++; 9568c2ecf20Sopenharmony_ci } 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci laarr[curr].extLocation.logicalBlockNum = newblocknum; 9598c2ecf20Sopenharmony_ci if (etype == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) 9608c2ecf20Sopenharmony_ci laarr[curr].extLocation.partitionReferenceNum = 9618c2ecf20Sopenharmony_ci UDF_I(inode)->i_location.partitionReferenceNum; 9628c2ecf20Sopenharmony_ci laarr[curr].extLength = EXT_RECORDED_ALLOCATED | 9638c2ecf20Sopenharmony_ci blocksize; 9648c2ecf20Sopenharmony_ci curr++; 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci if (blen != offset + 1) { 9678c2ecf20Sopenharmony_ci if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) 9688c2ecf20Sopenharmony_ci laarr[curr].extLocation.logicalBlockNum += 9698c2ecf20Sopenharmony_ci offset + 1; 9708c2ecf20Sopenharmony_ci laarr[curr].extLength = (etype << 30) | 9718c2ecf20Sopenharmony_ci ((blen - (offset + 1)) << blocksize_bits); 9728c2ecf20Sopenharmony_ci curr++; 9738c2ecf20Sopenharmony_ci (*endnum)++; 9748c2ecf20Sopenharmony_ci } 9758c2ecf20Sopenharmony_ci } 9768c2ecf20Sopenharmony_ci} 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_cistatic void udf_prealloc_extents(struct inode *inode, int c, int lastblock, 9798c2ecf20Sopenharmony_ci struct kernel_long_ad *laarr, 9808c2ecf20Sopenharmony_ci int *endnum) 9818c2ecf20Sopenharmony_ci{ 9828c2ecf20Sopenharmony_ci int start, length = 0, currlength = 0, i; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci if (*endnum >= (c + 1)) { 9858c2ecf20Sopenharmony_ci if (!lastblock) 9868c2ecf20Sopenharmony_ci return; 9878c2ecf20Sopenharmony_ci else 9888c2ecf20Sopenharmony_ci start = c; 9898c2ecf20Sopenharmony_ci } else { 9908c2ecf20Sopenharmony_ci if ((laarr[c + 1].extLength >> 30) == 9918c2ecf20Sopenharmony_ci (EXT_NOT_RECORDED_ALLOCATED >> 30)) { 9928c2ecf20Sopenharmony_ci start = c + 1; 9938c2ecf20Sopenharmony_ci length = currlength = 9948c2ecf20Sopenharmony_ci (((laarr[c + 1].extLength & 9958c2ecf20Sopenharmony_ci UDF_EXTENT_LENGTH_MASK) + 9968c2ecf20Sopenharmony_ci inode->i_sb->s_blocksize - 1) >> 9978c2ecf20Sopenharmony_ci inode->i_sb->s_blocksize_bits); 9988c2ecf20Sopenharmony_ci } else 9998c2ecf20Sopenharmony_ci start = c; 10008c2ecf20Sopenharmony_ci } 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci for (i = start + 1; i <= *endnum; i++) { 10038c2ecf20Sopenharmony_ci if (i == *endnum) { 10048c2ecf20Sopenharmony_ci if (lastblock) 10058c2ecf20Sopenharmony_ci length += UDF_DEFAULT_PREALLOC_BLOCKS; 10068c2ecf20Sopenharmony_ci } else if ((laarr[i].extLength >> 30) == 10078c2ecf20Sopenharmony_ci (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) { 10088c2ecf20Sopenharmony_ci length += (((laarr[i].extLength & 10098c2ecf20Sopenharmony_ci UDF_EXTENT_LENGTH_MASK) + 10108c2ecf20Sopenharmony_ci inode->i_sb->s_blocksize - 1) >> 10118c2ecf20Sopenharmony_ci inode->i_sb->s_blocksize_bits); 10128c2ecf20Sopenharmony_ci } else 10138c2ecf20Sopenharmony_ci break; 10148c2ecf20Sopenharmony_ci } 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci if (length) { 10178c2ecf20Sopenharmony_ci int next = laarr[start].extLocation.logicalBlockNum + 10188c2ecf20Sopenharmony_ci (((laarr[start].extLength & UDF_EXTENT_LENGTH_MASK) + 10198c2ecf20Sopenharmony_ci inode->i_sb->s_blocksize - 1) >> 10208c2ecf20Sopenharmony_ci inode->i_sb->s_blocksize_bits); 10218c2ecf20Sopenharmony_ci int numalloc = udf_prealloc_blocks(inode->i_sb, inode, 10228c2ecf20Sopenharmony_ci laarr[start].extLocation.partitionReferenceNum, 10238c2ecf20Sopenharmony_ci next, (UDF_DEFAULT_PREALLOC_BLOCKS > length ? 10248c2ecf20Sopenharmony_ci length : UDF_DEFAULT_PREALLOC_BLOCKS) - 10258c2ecf20Sopenharmony_ci currlength); 10268c2ecf20Sopenharmony_ci if (numalloc) { 10278c2ecf20Sopenharmony_ci if (start == (c + 1)) 10288c2ecf20Sopenharmony_ci laarr[start].extLength += 10298c2ecf20Sopenharmony_ci (numalloc << 10308c2ecf20Sopenharmony_ci inode->i_sb->s_blocksize_bits); 10318c2ecf20Sopenharmony_ci else { 10328c2ecf20Sopenharmony_ci memmove(&laarr[c + 2], &laarr[c + 1], 10338c2ecf20Sopenharmony_ci sizeof(struct long_ad) * (*endnum - (c + 1))); 10348c2ecf20Sopenharmony_ci (*endnum)++; 10358c2ecf20Sopenharmony_ci laarr[c + 1].extLocation.logicalBlockNum = next; 10368c2ecf20Sopenharmony_ci laarr[c + 1].extLocation.partitionReferenceNum = 10378c2ecf20Sopenharmony_ci laarr[c].extLocation. 10388c2ecf20Sopenharmony_ci partitionReferenceNum; 10398c2ecf20Sopenharmony_ci laarr[c + 1].extLength = 10408c2ecf20Sopenharmony_ci EXT_NOT_RECORDED_ALLOCATED | 10418c2ecf20Sopenharmony_ci (numalloc << 10428c2ecf20Sopenharmony_ci inode->i_sb->s_blocksize_bits); 10438c2ecf20Sopenharmony_ci start = c + 1; 10448c2ecf20Sopenharmony_ci } 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci for (i = start + 1; numalloc && i < *endnum; i++) { 10478c2ecf20Sopenharmony_ci int elen = ((laarr[i].extLength & 10488c2ecf20Sopenharmony_ci UDF_EXTENT_LENGTH_MASK) + 10498c2ecf20Sopenharmony_ci inode->i_sb->s_blocksize - 1) >> 10508c2ecf20Sopenharmony_ci inode->i_sb->s_blocksize_bits; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci if (elen > numalloc) { 10538c2ecf20Sopenharmony_ci laarr[i].extLength -= 10548c2ecf20Sopenharmony_ci (numalloc << 10558c2ecf20Sopenharmony_ci inode->i_sb->s_blocksize_bits); 10568c2ecf20Sopenharmony_ci numalloc = 0; 10578c2ecf20Sopenharmony_ci } else { 10588c2ecf20Sopenharmony_ci numalloc -= elen; 10598c2ecf20Sopenharmony_ci if (*endnum > (i + 1)) 10608c2ecf20Sopenharmony_ci memmove(&laarr[i], 10618c2ecf20Sopenharmony_ci &laarr[i + 1], 10628c2ecf20Sopenharmony_ci sizeof(struct long_ad) * 10638c2ecf20Sopenharmony_ci (*endnum - (i + 1))); 10648c2ecf20Sopenharmony_ci i--; 10658c2ecf20Sopenharmony_ci (*endnum)--; 10668c2ecf20Sopenharmony_ci } 10678c2ecf20Sopenharmony_ci } 10688c2ecf20Sopenharmony_ci UDF_I(inode)->i_lenExtents += 10698c2ecf20Sopenharmony_ci numalloc << inode->i_sb->s_blocksize_bits; 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci } 10728c2ecf20Sopenharmony_ci} 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_cistatic void udf_merge_extents(struct inode *inode, struct kernel_long_ad *laarr, 10758c2ecf20Sopenharmony_ci int *endnum) 10768c2ecf20Sopenharmony_ci{ 10778c2ecf20Sopenharmony_ci int i; 10788c2ecf20Sopenharmony_ci unsigned long blocksize = inode->i_sb->s_blocksize; 10798c2ecf20Sopenharmony_ci unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci for (i = 0; i < (*endnum - 1); i++) { 10828c2ecf20Sopenharmony_ci struct kernel_long_ad *li /*l[i]*/ = &laarr[i]; 10838c2ecf20Sopenharmony_ci struct kernel_long_ad *lip1 /*l[i plus 1]*/ = &laarr[i + 1]; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci if (((li->extLength >> 30) == (lip1->extLength >> 30)) && 10868c2ecf20Sopenharmony_ci (((li->extLength >> 30) == 10878c2ecf20Sopenharmony_ci (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) || 10888c2ecf20Sopenharmony_ci ((lip1->extLocation.logicalBlockNum - 10898c2ecf20Sopenharmony_ci li->extLocation.logicalBlockNum) == 10908c2ecf20Sopenharmony_ci (((li->extLength & UDF_EXTENT_LENGTH_MASK) + 10918c2ecf20Sopenharmony_ci blocksize - 1) >> blocksize_bits)))) { 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci if (((li->extLength & UDF_EXTENT_LENGTH_MASK) + 10948c2ecf20Sopenharmony_ci (lip1->extLength & UDF_EXTENT_LENGTH_MASK) + 10958c2ecf20Sopenharmony_ci blocksize - 1) <= UDF_EXTENT_LENGTH_MASK) { 10968c2ecf20Sopenharmony_ci li->extLength = lip1->extLength + 10978c2ecf20Sopenharmony_ci (((li->extLength & 10988c2ecf20Sopenharmony_ci UDF_EXTENT_LENGTH_MASK) + 10998c2ecf20Sopenharmony_ci blocksize - 1) & ~(blocksize - 1)); 11008c2ecf20Sopenharmony_ci if (*endnum > (i + 2)) 11018c2ecf20Sopenharmony_ci memmove(&laarr[i + 1], &laarr[i + 2], 11028c2ecf20Sopenharmony_ci sizeof(struct long_ad) * 11038c2ecf20Sopenharmony_ci (*endnum - (i + 2))); 11048c2ecf20Sopenharmony_ci i--; 11058c2ecf20Sopenharmony_ci (*endnum)--; 11068c2ecf20Sopenharmony_ci } 11078c2ecf20Sopenharmony_ci } else if (((li->extLength >> 30) == 11088c2ecf20Sopenharmony_ci (EXT_NOT_RECORDED_ALLOCATED >> 30)) && 11098c2ecf20Sopenharmony_ci ((lip1->extLength >> 30) == 11108c2ecf20Sopenharmony_ci (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))) { 11118c2ecf20Sopenharmony_ci udf_free_blocks(inode->i_sb, inode, &li->extLocation, 0, 11128c2ecf20Sopenharmony_ci ((li->extLength & 11138c2ecf20Sopenharmony_ci UDF_EXTENT_LENGTH_MASK) + 11148c2ecf20Sopenharmony_ci blocksize - 1) >> blocksize_bits); 11158c2ecf20Sopenharmony_ci li->extLocation.logicalBlockNum = 0; 11168c2ecf20Sopenharmony_ci li->extLocation.partitionReferenceNum = 0; 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci if (((li->extLength & UDF_EXTENT_LENGTH_MASK) + 11198c2ecf20Sopenharmony_ci (lip1->extLength & UDF_EXTENT_LENGTH_MASK) + 11208c2ecf20Sopenharmony_ci blocksize - 1) & ~UDF_EXTENT_LENGTH_MASK) { 11218c2ecf20Sopenharmony_ci lip1->extLength = (lip1->extLength - 11228c2ecf20Sopenharmony_ci (li->extLength & 11238c2ecf20Sopenharmony_ci UDF_EXTENT_LENGTH_MASK) + 11248c2ecf20Sopenharmony_ci UDF_EXTENT_LENGTH_MASK) & 11258c2ecf20Sopenharmony_ci ~(blocksize - 1); 11268c2ecf20Sopenharmony_ci li->extLength = (li->extLength & 11278c2ecf20Sopenharmony_ci UDF_EXTENT_FLAG_MASK) + 11288c2ecf20Sopenharmony_ci (UDF_EXTENT_LENGTH_MASK + 1) - 11298c2ecf20Sopenharmony_ci blocksize; 11308c2ecf20Sopenharmony_ci } else { 11318c2ecf20Sopenharmony_ci li->extLength = lip1->extLength + 11328c2ecf20Sopenharmony_ci (((li->extLength & 11338c2ecf20Sopenharmony_ci UDF_EXTENT_LENGTH_MASK) + 11348c2ecf20Sopenharmony_ci blocksize - 1) & ~(blocksize - 1)); 11358c2ecf20Sopenharmony_ci if (*endnum > (i + 2)) 11368c2ecf20Sopenharmony_ci memmove(&laarr[i + 1], &laarr[i + 2], 11378c2ecf20Sopenharmony_ci sizeof(struct long_ad) * 11388c2ecf20Sopenharmony_ci (*endnum - (i + 2))); 11398c2ecf20Sopenharmony_ci i--; 11408c2ecf20Sopenharmony_ci (*endnum)--; 11418c2ecf20Sopenharmony_ci } 11428c2ecf20Sopenharmony_ci } else if ((li->extLength >> 30) == 11438c2ecf20Sopenharmony_ci (EXT_NOT_RECORDED_ALLOCATED >> 30)) { 11448c2ecf20Sopenharmony_ci udf_free_blocks(inode->i_sb, inode, 11458c2ecf20Sopenharmony_ci &li->extLocation, 0, 11468c2ecf20Sopenharmony_ci ((li->extLength & 11478c2ecf20Sopenharmony_ci UDF_EXTENT_LENGTH_MASK) + 11488c2ecf20Sopenharmony_ci blocksize - 1) >> blocksize_bits); 11498c2ecf20Sopenharmony_ci li->extLocation.logicalBlockNum = 0; 11508c2ecf20Sopenharmony_ci li->extLocation.partitionReferenceNum = 0; 11518c2ecf20Sopenharmony_ci li->extLength = (li->extLength & 11528c2ecf20Sopenharmony_ci UDF_EXTENT_LENGTH_MASK) | 11538c2ecf20Sopenharmony_ci EXT_NOT_RECORDED_NOT_ALLOCATED; 11548c2ecf20Sopenharmony_ci } 11558c2ecf20Sopenharmony_ci } 11568c2ecf20Sopenharmony_ci} 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_cistatic int udf_update_extents(struct inode *inode, struct kernel_long_ad *laarr, 11598c2ecf20Sopenharmony_ci int startnum, int endnum, 11608c2ecf20Sopenharmony_ci struct extent_position *epos) 11618c2ecf20Sopenharmony_ci{ 11628c2ecf20Sopenharmony_ci int start = 0, i; 11638c2ecf20Sopenharmony_ci struct kernel_lb_addr tmploc; 11648c2ecf20Sopenharmony_ci uint32_t tmplen; 11658c2ecf20Sopenharmony_ci int err; 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci if (startnum > endnum) { 11688c2ecf20Sopenharmony_ci for (i = 0; i < (startnum - endnum); i++) 11698c2ecf20Sopenharmony_ci udf_delete_aext(inode, *epos); 11708c2ecf20Sopenharmony_ci } else if (startnum < endnum) { 11718c2ecf20Sopenharmony_ci for (i = 0; i < (endnum - startnum); i++) { 11728c2ecf20Sopenharmony_ci err = udf_insert_aext(inode, *epos, 11738c2ecf20Sopenharmony_ci laarr[i].extLocation, 11748c2ecf20Sopenharmony_ci laarr[i].extLength); 11758c2ecf20Sopenharmony_ci /* 11768c2ecf20Sopenharmony_ci * If we fail here, we are likely corrupting the extent 11778c2ecf20Sopenharmony_ci * list and leaking blocks. At least stop early to 11788c2ecf20Sopenharmony_ci * limit the damage. 11798c2ecf20Sopenharmony_ci */ 11808c2ecf20Sopenharmony_ci if (err < 0) 11818c2ecf20Sopenharmony_ci return err; 11828c2ecf20Sopenharmony_ci udf_next_aext(inode, epos, &laarr[i].extLocation, 11838c2ecf20Sopenharmony_ci &laarr[i].extLength, 1); 11848c2ecf20Sopenharmony_ci start++; 11858c2ecf20Sopenharmony_ci } 11868c2ecf20Sopenharmony_ci } 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci for (i = start; i < endnum; i++) { 11898c2ecf20Sopenharmony_ci udf_next_aext(inode, epos, &tmploc, &tmplen, 0); 11908c2ecf20Sopenharmony_ci udf_write_aext(inode, epos, &laarr[i].extLocation, 11918c2ecf20Sopenharmony_ci laarr[i].extLength, 1); 11928c2ecf20Sopenharmony_ci } 11938c2ecf20Sopenharmony_ci return 0; 11948c2ecf20Sopenharmony_ci} 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_cistruct buffer_head *udf_bread(struct inode *inode, udf_pblk_t block, 11978c2ecf20Sopenharmony_ci int create, int *err) 11988c2ecf20Sopenharmony_ci{ 11998c2ecf20Sopenharmony_ci struct buffer_head *bh = NULL; 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci bh = udf_getblk(inode, block, create, err); 12028c2ecf20Sopenharmony_ci if (!bh) 12038c2ecf20Sopenharmony_ci return NULL; 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci if (buffer_uptodate(bh)) 12068c2ecf20Sopenharmony_ci return bh; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci ll_rw_block(REQ_OP_READ, 0, 1, &bh); 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci wait_on_buffer(bh); 12118c2ecf20Sopenharmony_ci if (buffer_uptodate(bh)) 12128c2ecf20Sopenharmony_ci return bh; 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci brelse(bh); 12158c2ecf20Sopenharmony_ci *err = -EIO; 12168c2ecf20Sopenharmony_ci return NULL; 12178c2ecf20Sopenharmony_ci} 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ciint udf_setsize(struct inode *inode, loff_t newsize) 12208c2ecf20Sopenharmony_ci{ 12218c2ecf20Sopenharmony_ci int err; 12228c2ecf20Sopenharmony_ci struct udf_inode_info *iinfo; 12238c2ecf20Sopenharmony_ci unsigned int bsize = i_blocksize(inode); 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || 12268c2ecf20Sopenharmony_ci S_ISLNK(inode->i_mode))) 12278c2ecf20Sopenharmony_ci return -EINVAL; 12288c2ecf20Sopenharmony_ci if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) 12298c2ecf20Sopenharmony_ci return -EPERM; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci iinfo = UDF_I(inode); 12328c2ecf20Sopenharmony_ci if (newsize > inode->i_size) { 12338c2ecf20Sopenharmony_ci down_write(&iinfo->i_data_sem); 12348c2ecf20Sopenharmony_ci if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { 12358c2ecf20Sopenharmony_ci if (bsize < 12368c2ecf20Sopenharmony_ci (udf_file_entry_alloc_offset(inode) + newsize)) { 12378c2ecf20Sopenharmony_ci err = udf_expand_file_adinicb(inode); 12388c2ecf20Sopenharmony_ci if (err) 12398c2ecf20Sopenharmony_ci return err; 12408c2ecf20Sopenharmony_ci down_write(&iinfo->i_data_sem); 12418c2ecf20Sopenharmony_ci } else { 12428c2ecf20Sopenharmony_ci iinfo->i_lenAlloc = newsize; 12438c2ecf20Sopenharmony_ci goto set_size; 12448c2ecf20Sopenharmony_ci } 12458c2ecf20Sopenharmony_ci } 12468c2ecf20Sopenharmony_ci err = udf_extend_file(inode, newsize); 12478c2ecf20Sopenharmony_ci if (err) { 12488c2ecf20Sopenharmony_ci up_write(&iinfo->i_data_sem); 12498c2ecf20Sopenharmony_ci return err; 12508c2ecf20Sopenharmony_ci } 12518c2ecf20Sopenharmony_ciset_size: 12528c2ecf20Sopenharmony_ci up_write(&iinfo->i_data_sem); 12538c2ecf20Sopenharmony_ci truncate_setsize(inode, newsize); 12548c2ecf20Sopenharmony_ci } else { 12558c2ecf20Sopenharmony_ci if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { 12568c2ecf20Sopenharmony_ci down_write(&iinfo->i_data_sem); 12578c2ecf20Sopenharmony_ci udf_clear_extent_cache(inode); 12588c2ecf20Sopenharmony_ci memset(iinfo->i_data + iinfo->i_lenEAttr + newsize, 12598c2ecf20Sopenharmony_ci 0x00, bsize - newsize - 12608c2ecf20Sopenharmony_ci udf_file_entry_alloc_offset(inode)); 12618c2ecf20Sopenharmony_ci iinfo->i_lenAlloc = newsize; 12628c2ecf20Sopenharmony_ci truncate_setsize(inode, newsize); 12638c2ecf20Sopenharmony_ci up_write(&iinfo->i_data_sem); 12648c2ecf20Sopenharmony_ci goto update_time; 12658c2ecf20Sopenharmony_ci } 12668c2ecf20Sopenharmony_ci err = block_truncate_page(inode->i_mapping, newsize, 12678c2ecf20Sopenharmony_ci udf_get_block); 12688c2ecf20Sopenharmony_ci if (err) 12698c2ecf20Sopenharmony_ci return err; 12708c2ecf20Sopenharmony_ci truncate_setsize(inode, newsize); 12718c2ecf20Sopenharmony_ci down_write(&iinfo->i_data_sem); 12728c2ecf20Sopenharmony_ci udf_clear_extent_cache(inode); 12738c2ecf20Sopenharmony_ci err = udf_truncate_extents(inode); 12748c2ecf20Sopenharmony_ci up_write(&iinfo->i_data_sem); 12758c2ecf20Sopenharmony_ci if (err) 12768c2ecf20Sopenharmony_ci return err; 12778c2ecf20Sopenharmony_ci } 12788c2ecf20Sopenharmony_ciupdate_time: 12798c2ecf20Sopenharmony_ci inode->i_mtime = inode->i_ctime = current_time(inode); 12808c2ecf20Sopenharmony_ci if (IS_SYNC(inode)) 12818c2ecf20Sopenharmony_ci udf_sync_inode(inode); 12828c2ecf20Sopenharmony_ci else 12838c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 12848c2ecf20Sopenharmony_ci return 0; 12858c2ecf20Sopenharmony_ci} 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci/* 12888c2ecf20Sopenharmony_ci * Maximum length of linked list formed by ICB hierarchy. The chosen number is 12898c2ecf20Sopenharmony_ci * arbitrary - just that we hopefully don't limit any real use of rewritten 12908c2ecf20Sopenharmony_ci * inode on write-once media but avoid looping for too long on corrupted media. 12918c2ecf20Sopenharmony_ci */ 12928c2ecf20Sopenharmony_ci#define UDF_MAX_ICB_NESTING 1024 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_cistatic int udf_read_inode(struct inode *inode, bool hidden_inode) 12958c2ecf20Sopenharmony_ci{ 12968c2ecf20Sopenharmony_ci struct buffer_head *bh = NULL; 12978c2ecf20Sopenharmony_ci struct fileEntry *fe; 12988c2ecf20Sopenharmony_ci struct extendedFileEntry *efe; 12998c2ecf20Sopenharmony_ci uint16_t ident; 13008c2ecf20Sopenharmony_ci struct udf_inode_info *iinfo = UDF_I(inode); 13018c2ecf20Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(inode->i_sb); 13028c2ecf20Sopenharmony_ci struct kernel_lb_addr *iloc = &iinfo->i_location; 13038c2ecf20Sopenharmony_ci unsigned int link_count; 13048c2ecf20Sopenharmony_ci unsigned int indirections = 0; 13058c2ecf20Sopenharmony_ci int bs = inode->i_sb->s_blocksize; 13068c2ecf20Sopenharmony_ci int ret = -EIO; 13078c2ecf20Sopenharmony_ci uint32_t uid, gid; 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_cireread: 13108c2ecf20Sopenharmony_ci if (iloc->partitionReferenceNum >= sbi->s_partitions) { 13118c2ecf20Sopenharmony_ci udf_debug("partition reference: %u > logical volume partitions: %u\n", 13128c2ecf20Sopenharmony_ci iloc->partitionReferenceNum, sbi->s_partitions); 13138c2ecf20Sopenharmony_ci return -EIO; 13148c2ecf20Sopenharmony_ci } 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci if (iloc->logicalBlockNum >= 13178c2ecf20Sopenharmony_ci sbi->s_partmaps[iloc->partitionReferenceNum].s_partition_len) { 13188c2ecf20Sopenharmony_ci udf_debug("block=%u, partition=%u out of range\n", 13198c2ecf20Sopenharmony_ci iloc->logicalBlockNum, iloc->partitionReferenceNum); 13208c2ecf20Sopenharmony_ci return -EIO; 13218c2ecf20Sopenharmony_ci } 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci /* 13248c2ecf20Sopenharmony_ci * Set defaults, but the inode is still incomplete! 13258c2ecf20Sopenharmony_ci * Note: get_new_inode() sets the following on a new inode: 13268c2ecf20Sopenharmony_ci * i_sb = sb 13278c2ecf20Sopenharmony_ci * i_no = ino 13288c2ecf20Sopenharmony_ci * i_flags = sb->s_flags 13298c2ecf20Sopenharmony_ci * i_state = 0 13308c2ecf20Sopenharmony_ci * clean_inode(): zero fills and sets 13318c2ecf20Sopenharmony_ci * i_count = 1 13328c2ecf20Sopenharmony_ci * i_nlink = 1 13338c2ecf20Sopenharmony_ci * i_op = NULL; 13348c2ecf20Sopenharmony_ci */ 13358c2ecf20Sopenharmony_ci bh = udf_read_ptagged(inode->i_sb, iloc, 0, &ident); 13368c2ecf20Sopenharmony_ci if (!bh) { 13378c2ecf20Sopenharmony_ci udf_err(inode->i_sb, "(ino %lu) failed !bh\n", inode->i_ino); 13388c2ecf20Sopenharmony_ci return -EIO; 13398c2ecf20Sopenharmony_ci } 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci if (ident != TAG_IDENT_FE && ident != TAG_IDENT_EFE && 13428c2ecf20Sopenharmony_ci ident != TAG_IDENT_USE) { 13438c2ecf20Sopenharmony_ci udf_err(inode->i_sb, "(ino %lu) failed ident=%u\n", 13448c2ecf20Sopenharmony_ci inode->i_ino, ident); 13458c2ecf20Sopenharmony_ci goto out; 13468c2ecf20Sopenharmony_ci } 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci fe = (struct fileEntry *)bh->b_data; 13498c2ecf20Sopenharmony_ci efe = (struct extendedFileEntry *)bh->b_data; 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci if (fe->icbTag.strategyType == cpu_to_le16(4096)) { 13528c2ecf20Sopenharmony_ci struct buffer_head *ibh; 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci ibh = udf_read_ptagged(inode->i_sb, iloc, 1, &ident); 13558c2ecf20Sopenharmony_ci if (ident == TAG_IDENT_IE && ibh) { 13568c2ecf20Sopenharmony_ci struct kernel_lb_addr loc; 13578c2ecf20Sopenharmony_ci struct indirectEntry *ie; 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci ie = (struct indirectEntry *)ibh->b_data; 13608c2ecf20Sopenharmony_ci loc = lelb_to_cpu(ie->indirectICB.extLocation); 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci if (ie->indirectICB.extLength) { 13638c2ecf20Sopenharmony_ci brelse(ibh); 13648c2ecf20Sopenharmony_ci memcpy(&iinfo->i_location, &loc, 13658c2ecf20Sopenharmony_ci sizeof(struct kernel_lb_addr)); 13668c2ecf20Sopenharmony_ci if (++indirections > UDF_MAX_ICB_NESTING) { 13678c2ecf20Sopenharmony_ci udf_err(inode->i_sb, 13688c2ecf20Sopenharmony_ci "too many ICBs in ICB hierarchy" 13698c2ecf20Sopenharmony_ci " (max %d supported)\n", 13708c2ecf20Sopenharmony_ci UDF_MAX_ICB_NESTING); 13718c2ecf20Sopenharmony_ci goto out; 13728c2ecf20Sopenharmony_ci } 13738c2ecf20Sopenharmony_ci brelse(bh); 13748c2ecf20Sopenharmony_ci goto reread; 13758c2ecf20Sopenharmony_ci } 13768c2ecf20Sopenharmony_ci } 13778c2ecf20Sopenharmony_ci brelse(ibh); 13788c2ecf20Sopenharmony_ci } else if (fe->icbTag.strategyType != cpu_to_le16(4)) { 13798c2ecf20Sopenharmony_ci udf_err(inode->i_sb, "unsupported strategy type: %u\n", 13808c2ecf20Sopenharmony_ci le16_to_cpu(fe->icbTag.strategyType)); 13818c2ecf20Sopenharmony_ci goto out; 13828c2ecf20Sopenharmony_ci } 13838c2ecf20Sopenharmony_ci if (fe->icbTag.strategyType == cpu_to_le16(4)) 13848c2ecf20Sopenharmony_ci iinfo->i_strat4096 = 0; 13858c2ecf20Sopenharmony_ci else /* if (fe->icbTag.strategyType == cpu_to_le16(4096)) */ 13868c2ecf20Sopenharmony_ci iinfo->i_strat4096 = 1; 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci iinfo->i_alloc_type = le16_to_cpu(fe->icbTag.flags) & 13898c2ecf20Sopenharmony_ci ICBTAG_FLAG_AD_MASK; 13908c2ecf20Sopenharmony_ci if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_SHORT && 13918c2ecf20Sopenharmony_ci iinfo->i_alloc_type != ICBTAG_FLAG_AD_LONG && 13928c2ecf20Sopenharmony_ci iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { 13938c2ecf20Sopenharmony_ci ret = -EIO; 13948c2ecf20Sopenharmony_ci goto out; 13958c2ecf20Sopenharmony_ci } 13968c2ecf20Sopenharmony_ci iinfo->i_hidden = hidden_inode; 13978c2ecf20Sopenharmony_ci iinfo->i_unique = 0; 13988c2ecf20Sopenharmony_ci iinfo->i_lenEAttr = 0; 13998c2ecf20Sopenharmony_ci iinfo->i_lenExtents = 0; 14008c2ecf20Sopenharmony_ci iinfo->i_lenAlloc = 0; 14018c2ecf20Sopenharmony_ci iinfo->i_next_alloc_block = 0; 14028c2ecf20Sopenharmony_ci iinfo->i_next_alloc_goal = 0; 14038c2ecf20Sopenharmony_ci if (fe->descTag.tagIdent == cpu_to_le16(TAG_IDENT_EFE)) { 14048c2ecf20Sopenharmony_ci iinfo->i_efe = 1; 14058c2ecf20Sopenharmony_ci iinfo->i_use = 0; 14068c2ecf20Sopenharmony_ci ret = udf_alloc_i_data(inode, bs - 14078c2ecf20Sopenharmony_ci sizeof(struct extendedFileEntry)); 14088c2ecf20Sopenharmony_ci if (ret) 14098c2ecf20Sopenharmony_ci goto out; 14108c2ecf20Sopenharmony_ci memcpy(iinfo->i_data, 14118c2ecf20Sopenharmony_ci bh->b_data + sizeof(struct extendedFileEntry), 14128c2ecf20Sopenharmony_ci bs - sizeof(struct extendedFileEntry)); 14138c2ecf20Sopenharmony_ci } else if (fe->descTag.tagIdent == cpu_to_le16(TAG_IDENT_FE)) { 14148c2ecf20Sopenharmony_ci iinfo->i_efe = 0; 14158c2ecf20Sopenharmony_ci iinfo->i_use = 0; 14168c2ecf20Sopenharmony_ci ret = udf_alloc_i_data(inode, bs - sizeof(struct fileEntry)); 14178c2ecf20Sopenharmony_ci if (ret) 14188c2ecf20Sopenharmony_ci goto out; 14198c2ecf20Sopenharmony_ci memcpy(iinfo->i_data, 14208c2ecf20Sopenharmony_ci bh->b_data + sizeof(struct fileEntry), 14218c2ecf20Sopenharmony_ci bs - sizeof(struct fileEntry)); 14228c2ecf20Sopenharmony_ci } else if (fe->descTag.tagIdent == cpu_to_le16(TAG_IDENT_USE)) { 14238c2ecf20Sopenharmony_ci iinfo->i_efe = 0; 14248c2ecf20Sopenharmony_ci iinfo->i_use = 1; 14258c2ecf20Sopenharmony_ci iinfo->i_lenAlloc = le32_to_cpu( 14268c2ecf20Sopenharmony_ci ((struct unallocSpaceEntry *)bh->b_data)-> 14278c2ecf20Sopenharmony_ci lengthAllocDescs); 14288c2ecf20Sopenharmony_ci ret = udf_alloc_i_data(inode, bs - 14298c2ecf20Sopenharmony_ci sizeof(struct unallocSpaceEntry)); 14308c2ecf20Sopenharmony_ci if (ret) 14318c2ecf20Sopenharmony_ci goto out; 14328c2ecf20Sopenharmony_ci memcpy(iinfo->i_data, 14338c2ecf20Sopenharmony_ci bh->b_data + sizeof(struct unallocSpaceEntry), 14348c2ecf20Sopenharmony_ci bs - sizeof(struct unallocSpaceEntry)); 14358c2ecf20Sopenharmony_ci return 0; 14368c2ecf20Sopenharmony_ci } 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci ret = -EIO; 14398c2ecf20Sopenharmony_ci read_lock(&sbi->s_cred_lock); 14408c2ecf20Sopenharmony_ci uid = le32_to_cpu(fe->uid); 14418c2ecf20Sopenharmony_ci if (uid == UDF_INVALID_ID || 14428c2ecf20Sopenharmony_ci UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_UID_SET)) 14438c2ecf20Sopenharmony_ci inode->i_uid = sbi->s_uid; 14448c2ecf20Sopenharmony_ci else 14458c2ecf20Sopenharmony_ci i_uid_write(inode, uid); 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci gid = le32_to_cpu(fe->gid); 14488c2ecf20Sopenharmony_ci if (gid == UDF_INVALID_ID || 14498c2ecf20Sopenharmony_ci UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_GID_SET)) 14508c2ecf20Sopenharmony_ci inode->i_gid = sbi->s_gid; 14518c2ecf20Sopenharmony_ci else 14528c2ecf20Sopenharmony_ci i_gid_write(inode, gid); 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci if (fe->icbTag.fileType != ICBTAG_FILE_TYPE_DIRECTORY && 14558c2ecf20Sopenharmony_ci sbi->s_fmode != UDF_INVALID_MODE) 14568c2ecf20Sopenharmony_ci inode->i_mode = sbi->s_fmode; 14578c2ecf20Sopenharmony_ci else if (fe->icbTag.fileType == ICBTAG_FILE_TYPE_DIRECTORY && 14588c2ecf20Sopenharmony_ci sbi->s_dmode != UDF_INVALID_MODE) 14598c2ecf20Sopenharmony_ci inode->i_mode = sbi->s_dmode; 14608c2ecf20Sopenharmony_ci else 14618c2ecf20Sopenharmony_ci inode->i_mode = udf_convert_permissions(fe); 14628c2ecf20Sopenharmony_ci inode->i_mode &= ~sbi->s_umask; 14638c2ecf20Sopenharmony_ci iinfo->i_extraPerms = le32_to_cpu(fe->permissions) & ~FE_MAPPED_PERMS; 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci read_unlock(&sbi->s_cred_lock); 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci link_count = le16_to_cpu(fe->fileLinkCount); 14688c2ecf20Sopenharmony_ci if (!link_count) { 14698c2ecf20Sopenharmony_ci if (!hidden_inode) { 14708c2ecf20Sopenharmony_ci ret = -ESTALE; 14718c2ecf20Sopenharmony_ci goto out; 14728c2ecf20Sopenharmony_ci } 14738c2ecf20Sopenharmony_ci link_count = 1; 14748c2ecf20Sopenharmony_ci } 14758c2ecf20Sopenharmony_ci set_nlink(inode, link_count); 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci inode->i_size = le64_to_cpu(fe->informationLength); 14788c2ecf20Sopenharmony_ci iinfo->i_lenExtents = inode->i_size; 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci if (iinfo->i_efe == 0) { 14818c2ecf20Sopenharmony_ci inode->i_blocks = le64_to_cpu(fe->logicalBlocksRecorded) << 14828c2ecf20Sopenharmony_ci (inode->i_sb->s_blocksize_bits - 9); 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci udf_disk_stamp_to_time(&inode->i_atime, fe->accessTime); 14858c2ecf20Sopenharmony_ci udf_disk_stamp_to_time(&inode->i_mtime, fe->modificationTime); 14868c2ecf20Sopenharmony_ci udf_disk_stamp_to_time(&inode->i_ctime, fe->attrTime); 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci iinfo->i_unique = le64_to_cpu(fe->uniqueID); 14898c2ecf20Sopenharmony_ci iinfo->i_lenEAttr = le32_to_cpu(fe->lengthExtendedAttr); 14908c2ecf20Sopenharmony_ci iinfo->i_lenAlloc = le32_to_cpu(fe->lengthAllocDescs); 14918c2ecf20Sopenharmony_ci iinfo->i_checkpoint = le32_to_cpu(fe->checkpoint); 14928c2ecf20Sopenharmony_ci iinfo->i_streamdir = 0; 14938c2ecf20Sopenharmony_ci iinfo->i_lenStreams = 0; 14948c2ecf20Sopenharmony_ci } else { 14958c2ecf20Sopenharmony_ci inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) << 14968c2ecf20Sopenharmony_ci (inode->i_sb->s_blocksize_bits - 9); 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci udf_disk_stamp_to_time(&inode->i_atime, efe->accessTime); 14998c2ecf20Sopenharmony_ci udf_disk_stamp_to_time(&inode->i_mtime, efe->modificationTime); 15008c2ecf20Sopenharmony_ci udf_disk_stamp_to_time(&iinfo->i_crtime, efe->createTime); 15018c2ecf20Sopenharmony_ci udf_disk_stamp_to_time(&inode->i_ctime, efe->attrTime); 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci iinfo->i_unique = le64_to_cpu(efe->uniqueID); 15048c2ecf20Sopenharmony_ci iinfo->i_lenEAttr = le32_to_cpu(efe->lengthExtendedAttr); 15058c2ecf20Sopenharmony_ci iinfo->i_lenAlloc = le32_to_cpu(efe->lengthAllocDescs); 15068c2ecf20Sopenharmony_ci iinfo->i_checkpoint = le32_to_cpu(efe->checkpoint); 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci /* Named streams */ 15098c2ecf20Sopenharmony_ci iinfo->i_streamdir = (efe->streamDirectoryICB.extLength != 0); 15108c2ecf20Sopenharmony_ci iinfo->i_locStreamdir = 15118c2ecf20Sopenharmony_ci lelb_to_cpu(efe->streamDirectoryICB.extLocation); 15128c2ecf20Sopenharmony_ci iinfo->i_lenStreams = le64_to_cpu(efe->objectSize); 15138c2ecf20Sopenharmony_ci if (iinfo->i_lenStreams >= inode->i_size) 15148c2ecf20Sopenharmony_ci iinfo->i_lenStreams -= inode->i_size; 15158c2ecf20Sopenharmony_ci else 15168c2ecf20Sopenharmony_ci iinfo->i_lenStreams = 0; 15178c2ecf20Sopenharmony_ci } 15188c2ecf20Sopenharmony_ci inode->i_generation = iinfo->i_unique; 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci /* 15218c2ecf20Sopenharmony_ci * Sanity check length of allocation descriptors and extended attrs to 15228c2ecf20Sopenharmony_ci * avoid integer overflows 15238c2ecf20Sopenharmony_ci */ 15248c2ecf20Sopenharmony_ci if (iinfo->i_lenEAttr > bs || iinfo->i_lenAlloc > bs) 15258c2ecf20Sopenharmony_ci goto out; 15268c2ecf20Sopenharmony_ci /* Now do exact checks */ 15278c2ecf20Sopenharmony_ci if (udf_file_entry_alloc_offset(inode) + iinfo->i_lenAlloc > bs) 15288c2ecf20Sopenharmony_ci goto out; 15298c2ecf20Sopenharmony_ci /* Sanity checks for files in ICB so that we don't get confused later */ 15308c2ecf20Sopenharmony_ci if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { 15318c2ecf20Sopenharmony_ci /* 15328c2ecf20Sopenharmony_ci * For file in ICB data is stored in allocation descriptor 15338c2ecf20Sopenharmony_ci * so sizes should match 15348c2ecf20Sopenharmony_ci */ 15358c2ecf20Sopenharmony_ci if (iinfo->i_lenAlloc != inode->i_size) 15368c2ecf20Sopenharmony_ci goto out; 15378c2ecf20Sopenharmony_ci /* File in ICB has to fit in there... */ 15388c2ecf20Sopenharmony_ci if (inode->i_size > bs - udf_file_entry_alloc_offset(inode)) 15398c2ecf20Sopenharmony_ci goto out; 15408c2ecf20Sopenharmony_ci } 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci switch (fe->icbTag.fileType) { 15438c2ecf20Sopenharmony_ci case ICBTAG_FILE_TYPE_DIRECTORY: 15448c2ecf20Sopenharmony_ci inode->i_op = &udf_dir_inode_operations; 15458c2ecf20Sopenharmony_ci inode->i_fop = &udf_dir_operations; 15468c2ecf20Sopenharmony_ci inode->i_mode |= S_IFDIR; 15478c2ecf20Sopenharmony_ci inc_nlink(inode); 15488c2ecf20Sopenharmony_ci break; 15498c2ecf20Sopenharmony_ci case ICBTAG_FILE_TYPE_REALTIME: 15508c2ecf20Sopenharmony_ci case ICBTAG_FILE_TYPE_REGULAR: 15518c2ecf20Sopenharmony_ci case ICBTAG_FILE_TYPE_UNDEF: 15528c2ecf20Sopenharmony_ci case ICBTAG_FILE_TYPE_VAT20: 15538c2ecf20Sopenharmony_ci if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) 15548c2ecf20Sopenharmony_ci inode->i_data.a_ops = &udf_adinicb_aops; 15558c2ecf20Sopenharmony_ci else 15568c2ecf20Sopenharmony_ci inode->i_data.a_ops = &udf_aops; 15578c2ecf20Sopenharmony_ci inode->i_op = &udf_file_inode_operations; 15588c2ecf20Sopenharmony_ci inode->i_fop = &udf_file_operations; 15598c2ecf20Sopenharmony_ci inode->i_mode |= S_IFREG; 15608c2ecf20Sopenharmony_ci break; 15618c2ecf20Sopenharmony_ci case ICBTAG_FILE_TYPE_BLOCK: 15628c2ecf20Sopenharmony_ci inode->i_mode |= S_IFBLK; 15638c2ecf20Sopenharmony_ci break; 15648c2ecf20Sopenharmony_ci case ICBTAG_FILE_TYPE_CHAR: 15658c2ecf20Sopenharmony_ci inode->i_mode |= S_IFCHR; 15668c2ecf20Sopenharmony_ci break; 15678c2ecf20Sopenharmony_ci case ICBTAG_FILE_TYPE_FIFO: 15688c2ecf20Sopenharmony_ci init_special_inode(inode, inode->i_mode | S_IFIFO, 0); 15698c2ecf20Sopenharmony_ci break; 15708c2ecf20Sopenharmony_ci case ICBTAG_FILE_TYPE_SOCKET: 15718c2ecf20Sopenharmony_ci init_special_inode(inode, inode->i_mode | S_IFSOCK, 0); 15728c2ecf20Sopenharmony_ci break; 15738c2ecf20Sopenharmony_ci case ICBTAG_FILE_TYPE_SYMLINK: 15748c2ecf20Sopenharmony_ci inode->i_data.a_ops = &udf_symlink_aops; 15758c2ecf20Sopenharmony_ci inode->i_op = &udf_symlink_inode_operations; 15768c2ecf20Sopenharmony_ci inode_nohighmem(inode); 15778c2ecf20Sopenharmony_ci inode->i_mode = S_IFLNK | 0777; 15788c2ecf20Sopenharmony_ci break; 15798c2ecf20Sopenharmony_ci case ICBTAG_FILE_TYPE_MAIN: 15808c2ecf20Sopenharmony_ci udf_debug("METADATA FILE-----\n"); 15818c2ecf20Sopenharmony_ci break; 15828c2ecf20Sopenharmony_ci case ICBTAG_FILE_TYPE_MIRROR: 15838c2ecf20Sopenharmony_ci udf_debug("METADATA MIRROR FILE-----\n"); 15848c2ecf20Sopenharmony_ci break; 15858c2ecf20Sopenharmony_ci case ICBTAG_FILE_TYPE_BITMAP: 15868c2ecf20Sopenharmony_ci udf_debug("METADATA BITMAP FILE-----\n"); 15878c2ecf20Sopenharmony_ci break; 15888c2ecf20Sopenharmony_ci default: 15898c2ecf20Sopenharmony_ci udf_err(inode->i_sb, "(ino %lu) failed unknown file type=%u\n", 15908c2ecf20Sopenharmony_ci inode->i_ino, fe->icbTag.fileType); 15918c2ecf20Sopenharmony_ci goto out; 15928c2ecf20Sopenharmony_ci } 15938c2ecf20Sopenharmony_ci if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { 15948c2ecf20Sopenharmony_ci struct deviceSpec *dsea = 15958c2ecf20Sopenharmony_ci (struct deviceSpec *)udf_get_extendedattr(inode, 12, 1); 15968c2ecf20Sopenharmony_ci if (dsea) { 15978c2ecf20Sopenharmony_ci init_special_inode(inode, inode->i_mode, 15988c2ecf20Sopenharmony_ci MKDEV(le32_to_cpu(dsea->majorDeviceIdent), 15998c2ecf20Sopenharmony_ci le32_to_cpu(dsea->minorDeviceIdent))); 16008c2ecf20Sopenharmony_ci /* Developer ID ??? */ 16018c2ecf20Sopenharmony_ci } else 16028c2ecf20Sopenharmony_ci goto out; 16038c2ecf20Sopenharmony_ci } 16048c2ecf20Sopenharmony_ci ret = 0; 16058c2ecf20Sopenharmony_ciout: 16068c2ecf20Sopenharmony_ci brelse(bh); 16078c2ecf20Sopenharmony_ci return ret; 16088c2ecf20Sopenharmony_ci} 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_cistatic int udf_alloc_i_data(struct inode *inode, size_t size) 16118c2ecf20Sopenharmony_ci{ 16128c2ecf20Sopenharmony_ci struct udf_inode_info *iinfo = UDF_I(inode); 16138c2ecf20Sopenharmony_ci iinfo->i_data = kmalloc(size, GFP_KERNEL); 16148c2ecf20Sopenharmony_ci if (!iinfo->i_data) 16158c2ecf20Sopenharmony_ci return -ENOMEM; 16168c2ecf20Sopenharmony_ci return 0; 16178c2ecf20Sopenharmony_ci} 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_cistatic umode_t udf_convert_permissions(struct fileEntry *fe) 16208c2ecf20Sopenharmony_ci{ 16218c2ecf20Sopenharmony_ci umode_t mode; 16228c2ecf20Sopenharmony_ci uint32_t permissions; 16238c2ecf20Sopenharmony_ci uint32_t flags; 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci permissions = le32_to_cpu(fe->permissions); 16268c2ecf20Sopenharmony_ci flags = le16_to_cpu(fe->icbTag.flags); 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci mode = ((permissions) & 0007) | 16298c2ecf20Sopenharmony_ci ((permissions >> 2) & 0070) | 16308c2ecf20Sopenharmony_ci ((permissions >> 4) & 0700) | 16318c2ecf20Sopenharmony_ci ((flags & ICBTAG_FLAG_SETUID) ? S_ISUID : 0) | 16328c2ecf20Sopenharmony_ci ((flags & ICBTAG_FLAG_SETGID) ? S_ISGID : 0) | 16338c2ecf20Sopenharmony_ci ((flags & ICBTAG_FLAG_STICKY) ? S_ISVTX : 0); 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci return mode; 16368c2ecf20Sopenharmony_ci} 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_civoid udf_update_extra_perms(struct inode *inode, umode_t mode) 16398c2ecf20Sopenharmony_ci{ 16408c2ecf20Sopenharmony_ci struct udf_inode_info *iinfo = UDF_I(inode); 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci /* 16438c2ecf20Sopenharmony_ci * UDF 2.01 sec. 3.3.3.3 Note 2: 16448c2ecf20Sopenharmony_ci * In Unix, delete permission tracks write 16458c2ecf20Sopenharmony_ci */ 16468c2ecf20Sopenharmony_ci iinfo->i_extraPerms &= ~FE_DELETE_PERMS; 16478c2ecf20Sopenharmony_ci if (mode & 0200) 16488c2ecf20Sopenharmony_ci iinfo->i_extraPerms |= FE_PERM_U_DELETE; 16498c2ecf20Sopenharmony_ci if (mode & 0020) 16508c2ecf20Sopenharmony_ci iinfo->i_extraPerms |= FE_PERM_G_DELETE; 16518c2ecf20Sopenharmony_ci if (mode & 0002) 16528c2ecf20Sopenharmony_ci iinfo->i_extraPerms |= FE_PERM_O_DELETE; 16538c2ecf20Sopenharmony_ci} 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_ciint udf_write_inode(struct inode *inode, struct writeback_control *wbc) 16568c2ecf20Sopenharmony_ci{ 16578c2ecf20Sopenharmony_ci return udf_update_inode(inode, wbc->sync_mode == WB_SYNC_ALL); 16588c2ecf20Sopenharmony_ci} 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_cistatic int udf_sync_inode(struct inode *inode) 16618c2ecf20Sopenharmony_ci{ 16628c2ecf20Sopenharmony_ci return udf_update_inode(inode, 1); 16638c2ecf20Sopenharmony_ci} 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_cistatic void udf_adjust_time(struct udf_inode_info *iinfo, struct timespec64 time) 16668c2ecf20Sopenharmony_ci{ 16678c2ecf20Sopenharmony_ci if (iinfo->i_crtime.tv_sec > time.tv_sec || 16688c2ecf20Sopenharmony_ci (iinfo->i_crtime.tv_sec == time.tv_sec && 16698c2ecf20Sopenharmony_ci iinfo->i_crtime.tv_nsec > time.tv_nsec)) 16708c2ecf20Sopenharmony_ci iinfo->i_crtime = time; 16718c2ecf20Sopenharmony_ci} 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_cistatic int udf_update_inode(struct inode *inode, int do_sync) 16748c2ecf20Sopenharmony_ci{ 16758c2ecf20Sopenharmony_ci struct buffer_head *bh = NULL; 16768c2ecf20Sopenharmony_ci struct fileEntry *fe; 16778c2ecf20Sopenharmony_ci struct extendedFileEntry *efe; 16788c2ecf20Sopenharmony_ci uint64_t lb_recorded; 16798c2ecf20Sopenharmony_ci uint32_t udfperms; 16808c2ecf20Sopenharmony_ci uint16_t icbflags; 16818c2ecf20Sopenharmony_ci uint16_t crclen; 16828c2ecf20Sopenharmony_ci int err = 0; 16838c2ecf20Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(inode->i_sb); 16848c2ecf20Sopenharmony_ci unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits; 16858c2ecf20Sopenharmony_ci struct udf_inode_info *iinfo = UDF_I(inode); 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci bh = udf_tgetblk(inode->i_sb, 16888c2ecf20Sopenharmony_ci udf_get_lb_pblock(inode->i_sb, &iinfo->i_location, 0)); 16898c2ecf20Sopenharmony_ci if (!bh) { 16908c2ecf20Sopenharmony_ci udf_debug("getblk failure\n"); 16918c2ecf20Sopenharmony_ci return -EIO; 16928c2ecf20Sopenharmony_ci } 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci lock_buffer(bh); 16958c2ecf20Sopenharmony_ci memset(bh->b_data, 0, inode->i_sb->s_blocksize); 16968c2ecf20Sopenharmony_ci fe = (struct fileEntry *)bh->b_data; 16978c2ecf20Sopenharmony_ci efe = (struct extendedFileEntry *)bh->b_data; 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci if (iinfo->i_use) { 17008c2ecf20Sopenharmony_ci struct unallocSpaceEntry *use = 17018c2ecf20Sopenharmony_ci (struct unallocSpaceEntry *)bh->b_data; 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci use->lengthAllocDescs = cpu_to_le32(iinfo->i_lenAlloc); 17048c2ecf20Sopenharmony_ci memcpy(bh->b_data + sizeof(struct unallocSpaceEntry), 17058c2ecf20Sopenharmony_ci iinfo->i_data, inode->i_sb->s_blocksize - 17068c2ecf20Sopenharmony_ci sizeof(struct unallocSpaceEntry)); 17078c2ecf20Sopenharmony_ci use->descTag.tagIdent = cpu_to_le16(TAG_IDENT_USE); 17088c2ecf20Sopenharmony_ci crclen = sizeof(struct unallocSpaceEntry); 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci goto finish; 17118c2ecf20Sopenharmony_ci } 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_UID_FORGET)) 17148c2ecf20Sopenharmony_ci fe->uid = cpu_to_le32(UDF_INVALID_ID); 17158c2ecf20Sopenharmony_ci else 17168c2ecf20Sopenharmony_ci fe->uid = cpu_to_le32(i_uid_read(inode)); 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_GID_FORGET)) 17198c2ecf20Sopenharmony_ci fe->gid = cpu_to_le32(UDF_INVALID_ID); 17208c2ecf20Sopenharmony_ci else 17218c2ecf20Sopenharmony_ci fe->gid = cpu_to_le32(i_gid_read(inode)); 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci udfperms = ((inode->i_mode & 0007)) | 17248c2ecf20Sopenharmony_ci ((inode->i_mode & 0070) << 2) | 17258c2ecf20Sopenharmony_ci ((inode->i_mode & 0700) << 4); 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci udfperms |= iinfo->i_extraPerms; 17288c2ecf20Sopenharmony_ci fe->permissions = cpu_to_le32(udfperms); 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci if (S_ISDIR(inode->i_mode) && inode->i_nlink > 0) 17318c2ecf20Sopenharmony_ci fe->fileLinkCount = cpu_to_le16(inode->i_nlink - 1); 17328c2ecf20Sopenharmony_ci else { 17338c2ecf20Sopenharmony_ci if (iinfo->i_hidden) 17348c2ecf20Sopenharmony_ci fe->fileLinkCount = cpu_to_le16(0); 17358c2ecf20Sopenharmony_ci else 17368c2ecf20Sopenharmony_ci fe->fileLinkCount = cpu_to_le16(inode->i_nlink); 17378c2ecf20Sopenharmony_ci } 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci fe->informationLength = cpu_to_le64(inode->i_size); 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { 17428c2ecf20Sopenharmony_ci struct regid *eid; 17438c2ecf20Sopenharmony_ci struct deviceSpec *dsea = 17448c2ecf20Sopenharmony_ci (struct deviceSpec *)udf_get_extendedattr(inode, 12, 1); 17458c2ecf20Sopenharmony_ci if (!dsea) { 17468c2ecf20Sopenharmony_ci dsea = (struct deviceSpec *) 17478c2ecf20Sopenharmony_ci udf_add_extendedattr(inode, 17488c2ecf20Sopenharmony_ci sizeof(struct deviceSpec) + 17498c2ecf20Sopenharmony_ci sizeof(struct regid), 12, 0x3); 17508c2ecf20Sopenharmony_ci dsea->attrType = cpu_to_le32(12); 17518c2ecf20Sopenharmony_ci dsea->attrSubtype = 1; 17528c2ecf20Sopenharmony_ci dsea->attrLength = cpu_to_le32( 17538c2ecf20Sopenharmony_ci sizeof(struct deviceSpec) + 17548c2ecf20Sopenharmony_ci sizeof(struct regid)); 17558c2ecf20Sopenharmony_ci dsea->impUseLength = cpu_to_le32(sizeof(struct regid)); 17568c2ecf20Sopenharmony_ci } 17578c2ecf20Sopenharmony_ci eid = (struct regid *)dsea->impUse; 17588c2ecf20Sopenharmony_ci memset(eid, 0, sizeof(*eid)); 17598c2ecf20Sopenharmony_ci strcpy(eid->ident, UDF_ID_DEVELOPER); 17608c2ecf20Sopenharmony_ci eid->identSuffix[0] = UDF_OS_CLASS_UNIX; 17618c2ecf20Sopenharmony_ci eid->identSuffix[1] = UDF_OS_ID_LINUX; 17628c2ecf20Sopenharmony_ci dsea->majorDeviceIdent = cpu_to_le32(imajor(inode)); 17638c2ecf20Sopenharmony_ci dsea->minorDeviceIdent = cpu_to_le32(iminor(inode)); 17648c2ecf20Sopenharmony_ci } 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) 17678c2ecf20Sopenharmony_ci lb_recorded = 0; /* No extents => no blocks! */ 17688c2ecf20Sopenharmony_ci else 17698c2ecf20Sopenharmony_ci lb_recorded = 17708c2ecf20Sopenharmony_ci (inode->i_blocks + (1 << (blocksize_bits - 9)) - 1) >> 17718c2ecf20Sopenharmony_ci (blocksize_bits - 9); 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ci if (iinfo->i_efe == 0) { 17748c2ecf20Sopenharmony_ci memcpy(bh->b_data + sizeof(struct fileEntry), 17758c2ecf20Sopenharmony_ci iinfo->i_data, 17768c2ecf20Sopenharmony_ci inode->i_sb->s_blocksize - sizeof(struct fileEntry)); 17778c2ecf20Sopenharmony_ci fe->logicalBlocksRecorded = cpu_to_le64(lb_recorded); 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci udf_time_to_disk_stamp(&fe->accessTime, inode->i_atime); 17808c2ecf20Sopenharmony_ci udf_time_to_disk_stamp(&fe->modificationTime, inode->i_mtime); 17818c2ecf20Sopenharmony_ci udf_time_to_disk_stamp(&fe->attrTime, inode->i_ctime); 17828c2ecf20Sopenharmony_ci memset(&(fe->impIdent), 0, sizeof(struct regid)); 17838c2ecf20Sopenharmony_ci strcpy(fe->impIdent.ident, UDF_ID_DEVELOPER); 17848c2ecf20Sopenharmony_ci fe->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; 17858c2ecf20Sopenharmony_ci fe->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; 17868c2ecf20Sopenharmony_ci fe->uniqueID = cpu_to_le64(iinfo->i_unique); 17878c2ecf20Sopenharmony_ci fe->lengthExtendedAttr = cpu_to_le32(iinfo->i_lenEAttr); 17888c2ecf20Sopenharmony_ci fe->lengthAllocDescs = cpu_to_le32(iinfo->i_lenAlloc); 17898c2ecf20Sopenharmony_ci fe->checkpoint = cpu_to_le32(iinfo->i_checkpoint); 17908c2ecf20Sopenharmony_ci fe->descTag.tagIdent = cpu_to_le16(TAG_IDENT_FE); 17918c2ecf20Sopenharmony_ci crclen = sizeof(struct fileEntry); 17928c2ecf20Sopenharmony_ci } else { 17938c2ecf20Sopenharmony_ci memcpy(bh->b_data + sizeof(struct extendedFileEntry), 17948c2ecf20Sopenharmony_ci iinfo->i_data, 17958c2ecf20Sopenharmony_ci inode->i_sb->s_blocksize - 17968c2ecf20Sopenharmony_ci sizeof(struct extendedFileEntry)); 17978c2ecf20Sopenharmony_ci efe->objectSize = 17988c2ecf20Sopenharmony_ci cpu_to_le64(inode->i_size + iinfo->i_lenStreams); 17998c2ecf20Sopenharmony_ci efe->logicalBlocksRecorded = cpu_to_le64(lb_recorded); 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci if (iinfo->i_streamdir) { 18028c2ecf20Sopenharmony_ci struct long_ad *icb_lad = &efe->streamDirectoryICB; 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_ci icb_lad->extLocation = 18058c2ecf20Sopenharmony_ci cpu_to_lelb(iinfo->i_locStreamdir); 18068c2ecf20Sopenharmony_ci icb_lad->extLength = 18078c2ecf20Sopenharmony_ci cpu_to_le32(inode->i_sb->s_blocksize); 18088c2ecf20Sopenharmony_ci } 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci udf_adjust_time(iinfo, inode->i_atime); 18118c2ecf20Sopenharmony_ci udf_adjust_time(iinfo, inode->i_mtime); 18128c2ecf20Sopenharmony_ci udf_adjust_time(iinfo, inode->i_ctime); 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_ci udf_time_to_disk_stamp(&efe->accessTime, inode->i_atime); 18158c2ecf20Sopenharmony_ci udf_time_to_disk_stamp(&efe->modificationTime, inode->i_mtime); 18168c2ecf20Sopenharmony_ci udf_time_to_disk_stamp(&efe->createTime, iinfo->i_crtime); 18178c2ecf20Sopenharmony_ci udf_time_to_disk_stamp(&efe->attrTime, inode->i_ctime); 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci memset(&(efe->impIdent), 0, sizeof(efe->impIdent)); 18208c2ecf20Sopenharmony_ci strcpy(efe->impIdent.ident, UDF_ID_DEVELOPER); 18218c2ecf20Sopenharmony_ci efe->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; 18228c2ecf20Sopenharmony_ci efe->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; 18238c2ecf20Sopenharmony_ci efe->uniqueID = cpu_to_le64(iinfo->i_unique); 18248c2ecf20Sopenharmony_ci efe->lengthExtendedAttr = cpu_to_le32(iinfo->i_lenEAttr); 18258c2ecf20Sopenharmony_ci efe->lengthAllocDescs = cpu_to_le32(iinfo->i_lenAlloc); 18268c2ecf20Sopenharmony_ci efe->checkpoint = cpu_to_le32(iinfo->i_checkpoint); 18278c2ecf20Sopenharmony_ci efe->descTag.tagIdent = cpu_to_le16(TAG_IDENT_EFE); 18288c2ecf20Sopenharmony_ci crclen = sizeof(struct extendedFileEntry); 18298c2ecf20Sopenharmony_ci } 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_cifinish: 18328c2ecf20Sopenharmony_ci if (iinfo->i_strat4096) { 18338c2ecf20Sopenharmony_ci fe->icbTag.strategyType = cpu_to_le16(4096); 18348c2ecf20Sopenharmony_ci fe->icbTag.strategyParameter = cpu_to_le16(1); 18358c2ecf20Sopenharmony_ci fe->icbTag.numEntries = cpu_to_le16(2); 18368c2ecf20Sopenharmony_ci } else { 18378c2ecf20Sopenharmony_ci fe->icbTag.strategyType = cpu_to_le16(4); 18388c2ecf20Sopenharmony_ci fe->icbTag.numEntries = cpu_to_le16(1); 18398c2ecf20Sopenharmony_ci } 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci if (iinfo->i_use) 18428c2ecf20Sopenharmony_ci fe->icbTag.fileType = ICBTAG_FILE_TYPE_USE; 18438c2ecf20Sopenharmony_ci else if (S_ISDIR(inode->i_mode)) 18448c2ecf20Sopenharmony_ci fe->icbTag.fileType = ICBTAG_FILE_TYPE_DIRECTORY; 18458c2ecf20Sopenharmony_ci else if (S_ISREG(inode->i_mode)) 18468c2ecf20Sopenharmony_ci fe->icbTag.fileType = ICBTAG_FILE_TYPE_REGULAR; 18478c2ecf20Sopenharmony_ci else if (S_ISLNK(inode->i_mode)) 18488c2ecf20Sopenharmony_ci fe->icbTag.fileType = ICBTAG_FILE_TYPE_SYMLINK; 18498c2ecf20Sopenharmony_ci else if (S_ISBLK(inode->i_mode)) 18508c2ecf20Sopenharmony_ci fe->icbTag.fileType = ICBTAG_FILE_TYPE_BLOCK; 18518c2ecf20Sopenharmony_ci else if (S_ISCHR(inode->i_mode)) 18528c2ecf20Sopenharmony_ci fe->icbTag.fileType = ICBTAG_FILE_TYPE_CHAR; 18538c2ecf20Sopenharmony_ci else if (S_ISFIFO(inode->i_mode)) 18548c2ecf20Sopenharmony_ci fe->icbTag.fileType = ICBTAG_FILE_TYPE_FIFO; 18558c2ecf20Sopenharmony_ci else if (S_ISSOCK(inode->i_mode)) 18568c2ecf20Sopenharmony_ci fe->icbTag.fileType = ICBTAG_FILE_TYPE_SOCKET; 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci icbflags = iinfo->i_alloc_type | 18598c2ecf20Sopenharmony_ci ((inode->i_mode & S_ISUID) ? ICBTAG_FLAG_SETUID : 0) | 18608c2ecf20Sopenharmony_ci ((inode->i_mode & S_ISGID) ? ICBTAG_FLAG_SETGID : 0) | 18618c2ecf20Sopenharmony_ci ((inode->i_mode & S_ISVTX) ? ICBTAG_FLAG_STICKY : 0) | 18628c2ecf20Sopenharmony_ci (le16_to_cpu(fe->icbTag.flags) & 18638c2ecf20Sopenharmony_ci ~(ICBTAG_FLAG_AD_MASK | ICBTAG_FLAG_SETUID | 18648c2ecf20Sopenharmony_ci ICBTAG_FLAG_SETGID | ICBTAG_FLAG_STICKY)); 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci fe->icbTag.flags = cpu_to_le16(icbflags); 18678c2ecf20Sopenharmony_ci if (sbi->s_udfrev >= 0x0200) 18688c2ecf20Sopenharmony_ci fe->descTag.descVersion = cpu_to_le16(3); 18698c2ecf20Sopenharmony_ci else 18708c2ecf20Sopenharmony_ci fe->descTag.descVersion = cpu_to_le16(2); 18718c2ecf20Sopenharmony_ci fe->descTag.tagSerialNum = cpu_to_le16(sbi->s_serial_number); 18728c2ecf20Sopenharmony_ci fe->descTag.tagLocation = cpu_to_le32( 18738c2ecf20Sopenharmony_ci iinfo->i_location.logicalBlockNum); 18748c2ecf20Sopenharmony_ci crclen += iinfo->i_lenEAttr + iinfo->i_lenAlloc - sizeof(struct tag); 18758c2ecf20Sopenharmony_ci fe->descTag.descCRCLength = cpu_to_le16(crclen); 18768c2ecf20Sopenharmony_ci fe->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)fe + sizeof(struct tag), 18778c2ecf20Sopenharmony_ci crclen)); 18788c2ecf20Sopenharmony_ci fe->descTag.tagChecksum = udf_tag_checksum(&fe->descTag); 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_ci set_buffer_uptodate(bh); 18818c2ecf20Sopenharmony_ci unlock_buffer(bh); 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci /* write the data blocks */ 18848c2ecf20Sopenharmony_ci mark_buffer_dirty(bh); 18858c2ecf20Sopenharmony_ci if (do_sync) { 18868c2ecf20Sopenharmony_ci sync_dirty_buffer(bh); 18878c2ecf20Sopenharmony_ci if (buffer_write_io_error(bh)) { 18888c2ecf20Sopenharmony_ci udf_warn(inode->i_sb, "IO error syncing udf inode [%08lx]\n", 18898c2ecf20Sopenharmony_ci inode->i_ino); 18908c2ecf20Sopenharmony_ci err = -EIO; 18918c2ecf20Sopenharmony_ci } 18928c2ecf20Sopenharmony_ci } 18938c2ecf20Sopenharmony_ci brelse(bh); 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci return err; 18968c2ecf20Sopenharmony_ci} 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_cistruct inode *__udf_iget(struct super_block *sb, struct kernel_lb_addr *ino, 18998c2ecf20Sopenharmony_ci bool hidden_inode) 19008c2ecf20Sopenharmony_ci{ 19018c2ecf20Sopenharmony_ci unsigned long block = udf_get_lb_pblock(sb, ino, 0); 19028c2ecf20Sopenharmony_ci struct inode *inode = iget_locked(sb, block); 19038c2ecf20Sopenharmony_ci int err; 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci if (!inode) 19068c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci if (!(inode->i_state & I_NEW)) { 19098c2ecf20Sopenharmony_ci if (UDF_I(inode)->i_hidden != hidden_inode) { 19108c2ecf20Sopenharmony_ci iput(inode); 19118c2ecf20Sopenharmony_ci return ERR_PTR(-EFSCORRUPTED); 19128c2ecf20Sopenharmony_ci } 19138c2ecf20Sopenharmony_ci return inode; 19148c2ecf20Sopenharmony_ci } 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci memcpy(&UDF_I(inode)->i_location, ino, sizeof(struct kernel_lb_addr)); 19178c2ecf20Sopenharmony_ci err = udf_read_inode(inode, hidden_inode); 19188c2ecf20Sopenharmony_ci if (err < 0) { 19198c2ecf20Sopenharmony_ci iget_failed(inode); 19208c2ecf20Sopenharmony_ci return ERR_PTR(err); 19218c2ecf20Sopenharmony_ci } 19228c2ecf20Sopenharmony_ci unlock_new_inode(inode); 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci return inode; 19258c2ecf20Sopenharmony_ci} 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ciint udf_setup_indirect_aext(struct inode *inode, udf_pblk_t block, 19288c2ecf20Sopenharmony_ci struct extent_position *epos) 19298c2ecf20Sopenharmony_ci{ 19308c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 19318c2ecf20Sopenharmony_ci struct buffer_head *bh; 19328c2ecf20Sopenharmony_ci struct allocExtDesc *aed; 19338c2ecf20Sopenharmony_ci struct extent_position nepos; 19348c2ecf20Sopenharmony_ci struct kernel_lb_addr neloc; 19358c2ecf20Sopenharmony_ci int ver, adsize; 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_SHORT) 19388c2ecf20Sopenharmony_ci adsize = sizeof(struct short_ad); 19398c2ecf20Sopenharmony_ci else if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_LONG) 19408c2ecf20Sopenharmony_ci adsize = sizeof(struct long_ad); 19418c2ecf20Sopenharmony_ci else 19428c2ecf20Sopenharmony_ci return -EIO; 19438c2ecf20Sopenharmony_ci 19448c2ecf20Sopenharmony_ci neloc.logicalBlockNum = block; 19458c2ecf20Sopenharmony_ci neloc.partitionReferenceNum = epos->block.partitionReferenceNum; 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci bh = udf_tgetblk(sb, udf_get_lb_pblock(sb, &neloc, 0)); 19488c2ecf20Sopenharmony_ci if (!bh) 19498c2ecf20Sopenharmony_ci return -EIO; 19508c2ecf20Sopenharmony_ci lock_buffer(bh); 19518c2ecf20Sopenharmony_ci memset(bh->b_data, 0x00, sb->s_blocksize); 19528c2ecf20Sopenharmony_ci set_buffer_uptodate(bh); 19538c2ecf20Sopenharmony_ci unlock_buffer(bh); 19548c2ecf20Sopenharmony_ci mark_buffer_dirty_inode(bh, inode); 19558c2ecf20Sopenharmony_ci 19568c2ecf20Sopenharmony_ci aed = (struct allocExtDesc *)(bh->b_data); 19578c2ecf20Sopenharmony_ci if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT)) { 19588c2ecf20Sopenharmony_ci aed->previousAllocExtLocation = 19598c2ecf20Sopenharmony_ci cpu_to_le32(epos->block.logicalBlockNum); 19608c2ecf20Sopenharmony_ci } 19618c2ecf20Sopenharmony_ci aed->lengthAllocDescs = cpu_to_le32(0); 19628c2ecf20Sopenharmony_ci if (UDF_SB(sb)->s_udfrev >= 0x0200) 19638c2ecf20Sopenharmony_ci ver = 3; 19648c2ecf20Sopenharmony_ci else 19658c2ecf20Sopenharmony_ci ver = 2; 19668c2ecf20Sopenharmony_ci udf_new_tag(bh->b_data, TAG_IDENT_AED, ver, 1, block, 19678c2ecf20Sopenharmony_ci sizeof(struct tag)); 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci nepos.block = neloc; 19708c2ecf20Sopenharmony_ci nepos.offset = sizeof(struct allocExtDesc); 19718c2ecf20Sopenharmony_ci nepos.bh = bh; 19728c2ecf20Sopenharmony_ci 19738c2ecf20Sopenharmony_ci /* 19748c2ecf20Sopenharmony_ci * Do we have to copy current last extent to make space for indirect 19758c2ecf20Sopenharmony_ci * one? 19768c2ecf20Sopenharmony_ci */ 19778c2ecf20Sopenharmony_ci if (epos->offset + adsize > sb->s_blocksize) { 19788c2ecf20Sopenharmony_ci struct kernel_lb_addr cp_loc; 19798c2ecf20Sopenharmony_ci uint32_t cp_len; 19808c2ecf20Sopenharmony_ci int cp_type; 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci epos->offset -= adsize; 19838c2ecf20Sopenharmony_ci cp_type = udf_current_aext(inode, epos, &cp_loc, &cp_len, 0); 19848c2ecf20Sopenharmony_ci cp_len |= ((uint32_t)cp_type) << 30; 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci __udf_add_aext(inode, &nepos, &cp_loc, cp_len, 1); 19878c2ecf20Sopenharmony_ci udf_write_aext(inode, epos, &nepos.block, 19888c2ecf20Sopenharmony_ci sb->s_blocksize | EXT_NEXT_EXTENT_ALLOCDESCS, 0); 19898c2ecf20Sopenharmony_ci } else { 19908c2ecf20Sopenharmony_ci __udf_add_aext(inode, epos, &nepos.block, 19918c2ecf20Sopenharmony_ci sb->s_blocksize | EXT_NEXT_EXTENT_ALLOCDESCS, 0); 19928c2ecf20Sopenharmony_ci } 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_ci brelse(epos->bh); 19958c2ecf20Sopenharmony_ci *epos = nepos; 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci return 0; 19988c2ecf20Sopenharmony_ci} 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci/* 20018c2ecf20Sopenharmony_ci * Append extent at the given position - should be the first free one in inode 20028c2ecf20Sopenharmony_ci * / indirect extent. This function assumes there is enough space in the inode 20038c2ecf20Sopenharmony_ci * or indirect extent. Use udf_add_aext() if you didn't check for this before. 20048c2ecf20Sopenharmony_ci */ 20058c2ecf20Sopenharmony_ciint __udf_add_aext(struct inode *inode, struct extent_position *epos, 20068c2ecf20Sopenharmony_ci struct kernel_lb_addr *eloc, uint32_t elen, int inc) 20078c2ecf20Sopenharmony_ci{ 20088c2ecf20Sopenharmony_ci struct udf_inode_info *iinfo = UDF_I(inode); 20098c2ecf20Sopenharmony_ci struct allocExtDesc *aed; 20108c2ecf20Sopenharmony_ci int adsize; 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) 20138c2ecf20Sopenharmony_ci adsize = sizeof(struct short_ad); 20148c2ecf20Sopenharmony_ci else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG) 20158c2ecf20Sopenharmony_ci adsize = sizeof(struct long_ad); 20168c2ecf20Sopenharmony_ci else 20178c2ecf20Sopenharmony_ci return -EIO; 20188c2ecf20Sopenharmony_ci 20198c2ecf20Sopenharmony_ci if (!epos->bh) { 20208c2ecf20Sopenharmony_ci WARN_ON(iinfo->i_lenAlloc != 20218c2ecf20Sopenharmony_ci epos->offset - udf_file_entry_alloc_offset(inode)); 20228c2ecf20Sopenharmony_ci } else { 20238c2ecf20Sopenharmony_ci aed = (struct allocExtDesc *)epos->bh->b_data; 20248c2ecf20Sopenharmony_ci WARN_ON(le32_to_cpu(aed->lengthAllocDescs) != 20258c2ecf20Sopenharmony_ci epos->offset - sizeof(struct allocExtDesc)); 20268c2ecf20Sopenharmony_ci WARN_ON(epos->offset + adsize > inode->i_sb->s_blocksize); 20278c2ecf20Sopenharmony_ci } 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ci udf_write_aext(inode, epos, eloc, elen, inc); 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ci if (!epos->bh) { 20328c2ecf20Sopenharmony_ci iinfo->i_lenAlloc += adsize; 20338c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 20348c2ecf20Sopenharmony_ci } else { 20358c2ecf20Sopenharmony_ci aed = (struct allocExtDesc *)epos->bh->b_data; 20368c2ecf20Sopenharmony_ci le32_add_cpu(&aed->lengthAllocDescs, adsize); 20378c2ecf20Sopenharmony_ci if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || 20388c2ecf20Sopenharmony_ci UDF_SB(inode->i_sb)->s_udfrev >= 0x0201) 20398c2ecf20Sopenharmony_ci udf_update_tag(epos->bh->b_data, 20408c2ecf20Sopenharmony_ci epos->offset + (inc ? 0 : adsize)); 20418c2ecf20Sopenharmony_ci else 20428c2ecf20Sopenharmony_ci udf_update_tag(epos->bh->b_data, 20438c2ecf20Sopenharmony_ci sizeof(struct allocExtDesc)); 20448c2ecf20Sopenharmony_ci mark_buffer_dirty_inode(epos->bh, inode); 20458c2ecf20Sopenharmony_ci } 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci return 0; 20488c2ecf20Sopenharmony_ci} 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci/* 20518c2ecf20Sopenharmony_ci * Append extent at given position - should be the first free one in inode 20528c2ecf20Sopenharmony_ci * / indirect extent. Takes care of allocating and linking indirect blocks. 20538c2ecf20Sopenharmony_ci */ 20548c2ecf20Sopenharmony_ciint udf_add_aext(struct inode *inode, struct extent_position *epos, 20558c2ecf20Sopenharmony_ci struct kernel_lb_addr *eloc, uint32_t elen, int inc) 20568c2ecf20Sopenharmony_ci{ 20578c2ecf20Sopenharmony_ci int adsize; 20588c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_SHORT) 20618c2ecf20Sopenharmony_ci adsize = sizeof(struct short_ad); 20628c2ecf20Sopenharmony_ci else if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_LONG) 20638c2ecf20Sopenharmony_ci adsize = sizeof(struct long_ad); 20648c2ecf20Sopenharmony_ci else 20658c2ecf20Sopenharmony_ci return -EIO; 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci if (epos->offset + (2 * adsize) > sb->s_blocksize) { 20688c2ecf20Sopenharmony_ci int err; 20698c2ecf20Sopenharmony_ci udf_pblk_t new_block; 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci new_block = udf_new_block(sb, NULL, 20728c2ecf20Sopenharmony_ci epos->block.partitionReferenceNum, 20738c2ecf20Sopenharmony_ci epos->block.logicalBlockNum, &err); 20748c2ecf20Sopenharmony_ci if (!new_block) 20758c2ecf20Sopenharmony_ci return -ENOSPC; 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci err = udf_setup_indirect_aext(inode, new_block, epos); 20788c2ecf20Sopenharmony_ci if (err) 20798c2ecf20Sopenharmony_ci return err; 20808c2ecf20Sopenharmony_ci } 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci return __udf_add_aext(inode, epos, eloc, elen, inc); 20838c2ecf20Sopenharmony_ci} 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_civoid udf_write_aext(struct inode *inode, struct extent_position *epos, 20868c2ecf20Sopenharmony_ci struct kernel_lb_addr *eloc, uint32_t elen, int inc) 20878c2ecf20Sopenharmony_ci{ 20888c2ecf20Sopenharmony_ci int adsize; 20898c2ecf20Sopenharmony_ci uint8_t *ptr; 20908c2ecf20Sopenharmony_ci struct short_ad *sad; 20918c2ecf20Sopenharmony_ci struct long_ad *lad; 20928c2ecf20Sopenharmony_ci struct udf_inode_info *iinfo = UDF_I(inode); 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci if (!epos->bh) 20958c2ecf20Sopenharmony_ci ptr = iinfo->i_data + epos->offset - 20968c2ecf20Sopenharmony_ci udf_file_entry_alloc_offset(inode) + 20978c2ecf20Sopenharmony_ci iinfo->i_lenEAttr; 20988c2ecf20Sopenharmony_ci else 20998c2ecf20Sopenharmony_ci ptr = epos->bh->b_data + epos->offset; 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci switch (iinfo->i_alloc_type) { 21028c2ecf20Sopenharmony_ci case ICBTAG_FLAG_AD_SHORT: 21038c2ecf20Sopenharmony_ci sad = (struct short_ad *)ptr; 21048c2ecf20Sopenharmony_ci sad->extLength = cpu_to_le32(elen); 21058c2ecf20Sopenharmony_ci sad->extPosition = cpu_to_le32(eloc->logicalBlockNum); 21068c2ecf20Sopenharmony_ci adsize = sizeof(struct short_ad); 21078c2ecf20Sopenharmony_ci break; 21088c2ecf20Sopenharmony_ci case ICBTAG_FLAG_AD_LONG: 21098c2ecf20Sopenharmony_ci lad = (struct long_ad *)ptr; 21108c2ecf20Sopenharmony_ci lad->extLength = cpu_to_le32(elen); 21118c2ecf20Sopenharmony_ci lad->extLocation = cpu_to_lelb(*eloc); 21128c2ecf20Sopenharmony_ci memset(lad->impUse, 0x00, sizeof(lad->impUse)); 21138c2ecf20Sopenharmony_ci adsize = sizeof(struct long_ad); 21148c2ecf20Sopenharmony_ci break; 21158c2ecf20Sopenharmony_ci default: 21168c2ecf20Sopenharmony_ci return; 21178c2ecf20Sopenharmony_ci } 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci if (epos->bh) { 21208c2ecf20Sopenharmony_ci if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || 21218c2ecf20Sopenharmony_ci UDF_SB(inode->i_sb)->s_udfrev >= 0x0201) { 21228c2ecf20Sopenharmony_ci struct allocExtDesc *aed = 21238c2ecf20Sopenharmony_ci (struct allocExtDesc *)epos->bh->b_data; 21248c2ecf20Sopenharmony_ci udf_update_tag(epos->bh->b_data, 21258c2ecf20Sopenharmony_ci le32_to_cpu(aed->lengthAllocDescs) + 21268c2ecf20Sopenharmony_ci sizeof(struct allocExtDesc)); 21278c2ecf20Sopenharmony_ci } 21288c2ecf20Sopenharmony_ci mark_buffer_dirty_inode(epos->bh, inode); 21298c2ecf20Sopenharmony_ci } else { 21308c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 21318c2ecf20Sopenharmony_ci } 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci if (inc) 21348c2ecf20Sopenharmony_ci epos->offset += adsize; 21358c2ecf20Sopenharmony_ci} 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci/* 21388c2ecf20Sopenharmony_ci * Only 1 indirect extent in a row really makes sense but allow upto 16 in case 21398c2ecf20Sopenharmony_ci * someone does some weird stuff. 21408c2ecf20Sopenharmony_ci */ 21418c2ecf20Sopenharmony_ci#define UDF_MAX_INDIR_EXTS 16 21428c2ecf20Sopenharmony_ci 21438c2ecf20Sopenharmony_ciint8_t udf_next_aext(struct inode *inode, struct extent_position *epos, 21448c2ecf20Sopenharmony_ci struct kernel_lb_addr *eloc, uint32_t *elen, int inc) 21458c2ecf20Sopenharmony_ci{ 21468c2ecf20Sopenharmony_ci int8_t etype; 21478c2ecf20Sopenharmony_ci unsigned int indirections = 0; 21488c2ecf20Sopenharmony_ci 21498c2ecf20Sopenharmony_ci while ((etype = udf_current_aext(inode, epos, eloc, elen, inc)) == 21508c2ecf20Sopenharmony_ci (EXT_NEXT_EXTENT_ALLOCDESCS >> 30)) { 21518c2ecf20Sopenharmony_ci udf_pblk_t block; 21528c2ecf20Sopenharmony_ci 21538c2ecf20Sopenharmony_ci if (++indirections > UDF_MAX_INDIR_EXTS) { 21548c2ecf20Sopenharmony_ci udf_err(inode->i_sb, 21558c2ecf20Sopenharmony_ci "too many indirect extents in inode %lu\n", 21568c2ecf20Sopenharmony_ci inode->i_ino); 21578c2ecf20Sopenharmony_ci return -1; 21588c2ecf20Sopenharmony_ci } 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci epos->block = *eloc; 21618c2ecf20Sopenharmony_ci epos->offset = sizeof(struct allocExtDesc); 21628c2ecf20Sopenharmony_ci brelse(epos->bh); 21638c2ecf20Sopenharmony_ci block = udf_get_lb_pblock(inode->i_sb, &epos->block, 0); 21648c2ecf20Sopenharmony_ci epos->bh = udf_tread(inode->i_sb, block); 21658c2ecf20Sopenharmony_ci if (!epos->bh) { 21668c2ecf20Sopenharmony_ci udf_debug("reading block %u failed!\n", block); 21678c2ecf20Sopenharmony_ci return -1; 21688c2ecf20Sopenharmony_ci } 21698c2ecf20Sopenharmony_ci } 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci return etype; 21728c2ecf20Sopenharmony_ci} 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ciint8_t udf_current_aext(struct inode *inode, struct extent_position *epos, 21758c2ecf20Sopenharmony_ci struct kernel_lb_addr *eloc, uint32_t *elen, int inc) 21768c2ecf20Sopenharmony_ci{ 21778c2ecf20Sopenharmony_ci int alen; 21788c2ecf20Sopenharmony_ci int8_t etype; 21798c2ecf20Sopenharmony_ci uint8_t *ptr; 21808c2ecf20Sopenharmony_ci struct short_ad *sad; 21818c2ecf20Sopenharmony_ci struct long_ad *lad; 21828c2ecf20Sopenharmony_ci struct udf_inode_info *iinfo = UDF_I(inode); 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_ci if (!epos->bh) { 21858c2ecf20Sopenharmony_ci if (!epos->offset) 21868c2ecf20Sopenharmony_ci epos->offset = udf_file_entry_alloc_offset(inode); 21878c2ecf20Sopenharmony_ci ptr = iinfo->i_data + epos->offset - 21888c2ecf20Sopenharmony_ci udf_file_entry_alloc_offset(inode) + 21898c2ecf20Sopenharmony_ci iinfo->i_lenEAttr; 21908c2ecf20Sopenharmony_ci alen = udf_file_entry_alloc_offset(inode) + 21918c2ecf20Sopenharmony_ci iinfo->i_lenAlloc; 21928c2ecf20Sopenharmony_ci } else { 21938c2ecf20Sopenharmony_ci if (!epos->offset) 21948c2ecf20Sopenharmony_ci epos->offset = sizeof(struct allocExtDesc); 21958c2ecf20Sopenharmony_ci ptr = epos->bh->b_data + epos->offset; 21968c2ecf20Sopenharmony_ci alen = sizeof(struct allocExtDesc) + 21978c2ecf20Sopenharmony_ci le32_to_cpu(((struct allocExtDesc *)epos->bh->b_data)-> 21988c2ecf20Sopenharmony_ci lengthAllocDescs); 21998c2ecf20Sopenharmony_ci } 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ci switch (iinfo->i_alloc_type) { 22028c2ecf20Sopenharmony_ci case ICBTAG_FLAG_AD_SHORT: 22038c2ecf20Sopenharmony_ci sad = udf_get_fileshortad(ptr, alen, &epos->offset, inc); 22048c2ecf20Sopenharmony_ci if (!sad) 22058c2ecf20Sopenharmony_ci return -1; 22068c2ecf20Sopenharmony_ci etype = le32_to_cpu(sad->extLength) >> 30; 22078c2ecf20Sopenharmony_ci eloc->logicalBlockNum = le32_to_cpu(sad->extPosition); 22088c2ecf20Sopenharmony_ci eloc->partitionReferenceNum = 22098c2ecf20Sopenharmony_ci iinfo->i_location.partitionReferenceNum; 22108c2ecf20Sopenharmony_ci *elen = le32_to_cpu(sad->extLength) & UDF_EXTENT_LENGTH_MASK; 22118c2ecf20Sopenharmony_ci break; 22128c2ecf20Sopenharmony_ci case ICBTAG_FLAG_AD_LONG: 22138c2ecf20Sopenharmony_ci lad = udf_get_filelongad(ptr, alen, &epos->offset, inc); 22148c2ecf20Sopenharmony_ci if (!lad) 22158c2ecf20Sopenharmony_ci return -1; 22168c2ecf20Sopenharmony_ci etype = le32_to_cpu(lad->extLength) >> 30; 22178c2ecf20Sopenharmony_ci *eloc = lelb_to_cpu(lad->extLocation); 22188c2ecf20Sopenharmony_ci *elen = le32_to_cpu(lad->extLength) & UDF_EXTENT_LENGTH_MASK; 22198c2ecf20Sopenharmony_ci break; 22208c2ecf20Sopenharmony_ci default: 22218c2ecf20Sopenharmony_ci udf_debug("alloc_type = %u unsupported\n", iinfo->i_alloc_type); 22228c2ecf20Sopenharmony_ci return -1; 22238c2ecf20Sopenharmony_ci } 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_ci return etype; 22268c2ecf20Sopenharmony_ci} 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_cistatic int udf_insert_aext(struct inode *inode, struct extent_position epos, 22298c2ecf20Sopenharmony_ci struct kernel_lb_addr neloc, uint32_t nelen) 22308c2ecf20Sopenharmony_ci{ 22318c2ecf20Sopenharmony_ci struct kernel_lb_addr oeloc; 22328c2ecf20Sopenharmony_ci uint32_t oelen; 22338c2ecf20Sopenharmony_ci int8_t etype; 22348c2ecf20Sopenharmony_ci int err; 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_ci if (epos.bh) 22378c2ecf20Sopenharmony_ci get_bh(epos.bh); 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci while ((etype = udf_next_aext(inode, &epos, &oeloc, &oelen, 0)) != -1) { 22408c2ecf20Sopenharmony_ci udf_write_aext(inode, &epos, &neloc, nelen, 1); 22418c2ecf20Sopenharmony_ci neloc = oeloc; 22428c2ecf20Sopenharmony_ci nelen = (etype << 30) | oelen; 22438c2ecf20Sopenharmony_ci } 22448c2ecf20Sopenharmony_ci err = udf_add_aext(inode, &epos, &neloc, nelen, 1); 22458c2ecf20Sopenharmony_ci brelse(epos.bh); 22468c2ecf20Sopenharmony_ci 22478c2ecf20Sopenharmony_ci return err; 22488c2ecf20Sopenharmony_ci} 22498c2ecf20Sopenharmony_ci 22508c2ecf20Sopenharmony_ciint8_t udf_delete_aext(struct inode *inode, struct extent_position epos) 22518c2ecf20Sopenharmony_ci{ 22528c2ecf20Sopenharmony_ci struct extent_position oepos; 22538c2ecf20Sopenharmony_ci int adsize; 22548c2ecf20Sopenharmony_ci int8_t etype; 22558c2ecf20Sopenharmony_ci struct allocExtDesc *aed; 22568c2ecf20Sopenharmony_ci struct udf_inode_info *iinfo; 22578c2ecf20Sopenharmony_ci struct kernel_lb_addr eloc; 22588c2ecf20Sopenharmony_ci uint32_t elen; 22598c2ecf20Sopenharmony_ci 22608c2ecf20Sopenharmony_ci if (epos.bh) { 22618c2ecf20Sopenharmony_ci get_bh(epos.bh); 22628c2ecf20Sopenharmony_ci get_bh(epos.bh); 22638c2ecf20Sopenharmony_ci } 22648c2ecf20Sopenharmony_ci 22658c2ecf20Sopenharmony_ci iinfo = UDF_I(inode); 22668c2ecf20Sopenharmony_ci if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) 22678c2ecf20Sopenharmony_ci adsize = sizeof(struct short_ad); 22688c2ecf20Sopenharmony_ci else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG) 22698c2ecf20Sopenharmony_ci adsize = sizeof(struct long_ad); 22708c2ecf20Sopenharmony_ci else 22718c2ecf20Sopenharmony_ci adsize = 0; 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_ci oepos = epos; 22748c2ecf20Sopenharmony_ci if (udf_next_aext(inode, &epos, &eloc, &elen, 1) == -1) 22758c2ecf20Sopenharmony_ci return -1; 22768c2ecf20Sopenharmony_ci 22778c2ecf20Sopenharmony_ci while ((etype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) { 22788c2ecf20Sopenharmony_ci udf_write_aext(inode, &oepos, &eloc, (etype << 30) | elen, 1); 22798c2ecf20Sopenharmony_ci if (oepos.bh != epos.bh) { 22808c2ecf20Sopenharmony_ci oepos.block = epos.block; 22818c2ecf20Sopenharmony_ci brelse(oepos.bh); 22828c2ecf20Sopenharmony_ci get_bh(epos.bh); 22838c2ecf20Sopenharmony_ci oepos.bh = epos.bh; 22848c2ecf20Sopenharmony_ci oepos.offset = epos.offset - adsize; 22858c2ecf20Sopenharmony_ci } 22868c2ecf20Sopenharmony_ci } 22878c2ecf20Sopenharmony_ci memset(&eloc, 0x00, sizeof(struct kernel_lb_addr)); 22888c2ecf20Sopenharmony_ci elen = 0; 22898c2ecf20Sopenharmony_ci 22908c2ecf20Sopenharmony_ci if (epos.bh != oepos.bh) { 22918c2ecf20Sopenharmony_ci udf_free_blocks(inode->i_sb, inode, &epos.block, 0, 1); 22928c2ecf20Sopenharmony_ci udf_write_aext(inode, &oepos, &eloc, elen, 1); 22938c2ecf20Sopenharmony_ci udf_write_aext(inode, &oepos, &eloc, elen, 1); 22948c2ecf20Sopenharmony_ci if (!oepos.bh) { 22958c2ecf20Sopenharmony_ci iinfo->i_lenAlloc -= (adsize * 2); 22968c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 22978c2ecf20Sopenharmony_ci } else { 22988c2ecf20Sopenharmony_ci aed = (struct allocExtDesc *)oepos.bh->b_data; 22998c2ecf20Sopenharmony_ci le32_add_cpu(&aed->lengthAllocDescs, -(2 * adsize)); 23008c2ecf20Sopenharmony_ci if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || 23018c2ecf20Sopenharmony_ci UDF_SB(inode->i_sb)->s_udfrev >= 0x0201) 23028c2ecf20Sopenharmony_ci udf_update_tag(oepos.bh->b_data, 23038c2ecf20Sopenharmony_ci oepos.offset - (2 * adsize)); 23048c2ecf20Sopenharmony_ci else 23058c2ecf20Sopenharmony_ci udf_update_tag(oepos.bh->b_data, 23068c2ecf20Sopenharmony_ci sizeof(struct allocExtDesc)); 23078c2ecf20Sopenharmony_ci mark_buffer_dirty_inode(oepos.bh, inode); 23088c2ecf20Sopenharmony_ci } 23098c2ecf20Sopenharmony_ci } else { 23108c2ecf20Sopenharmony_ci udf_write_aext(inode, &oepos, &eloc, elen, 1); 23118c2ecf20Sopenharmony_ci if (!oepos.bh) { 23128c2ecf20Sopenharmony_ci iinfo->i_lenAlloc -= adsize; 23138c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 23148c2ecf20Sopenharmony_ci } else { 23158c2ecf20Sopenharmony_ci aed = (struct allocExtDesc *)oepos.bh->b_data; 23168c2ecf20Sopenharmony_ci le32_add_cpu(&aed->lengthAllocDescs, -adsize); 23178c2ecf20Sopenharmony_ci if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || 23188c2ecf20Sopenharmony_ci UDF_SB(inode->i_sb)->s_udfrev >= 0x0201) 23198c2ecf20Sopenharmony_ci udf_update_tag(oepos.bh->b_data, 23208c2ecf20Sopenharmony_ci epos.offset - adsize); 23218c2ecf20Sopenharmony_ci else 23228c2ecf20Sopenharmony_ci udf_update_tag(oepos.bh->b_data, 23238c2ecf20Sopenharmony_ci sizeof(struct allocExtDesc)); 23248c2ecf20Sopenharmony_ci mark_buffer_dirty_inode(oepos.bh, inode); 23258c2ecf20Sopenharmony_ci } 23268c2ecf20Sopenharmony_ci } 23278c2ecf20Sopenharmony_ci 23288c2ecf20Sopenharmony_ci brelse(epos.bh); 23298c2ecf20Sopenharmony_ci brelse(oepos.bh); 23308c2ecf20Sopenharmony_ci 23318c2ecf20Sopenharmony_ci return (elen >> 30); 23328c2ecf20Sopenharmony_ci} 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ciint8_t inode_bmap(struct inode *inode, sector_t block, 23358c2ecf20Sopenharmony_ci struct extent_position *pos, struct kernel_lb_addr *eloc, 23368c2ecf20Sopenharmony_ci uint32_t *elen, sector_t *offset) 23378c2ecf20Sopenharmony_ci{ 23388c2ecf20Sopenharmony_ci unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits; 23398c2ecf20Sopenharmony_ci loff_t lbcount = 0, bcount = (loff_t) block << blocksize_bits; 23408c2ecf20Sopenharmony_ci int8_t etype; 23418c2ecf20Sopenharmony_ci struct udf_inode_info *iinfo; 23428c2ecf20Sopenharmony_ci 23438c2ecf20Sopenharmony_ci iinfo = UDF_I(inode); 23448c2ecf20Sopenharmony_ci if (!udf_read_extent_cache(inode, bcount, &lbcount, pos)) { 23458c2ecf20Sopenharmony_ci pos->offset = 0; 23468c2ecf20Sopenharmony_ci pos->block = iinfo->i_location; 23478c2ecf20Sopenharmony_ci pos->bh = NULL; 23488c2ecf20Sopenharmony_ci } 23498c2ecf20Sopenharmony_ci *elen = 0; 23508c2ecf20Sopenharmony_ci do { 23518c2ecf20Sopenharmony_ci etype = udf_next_aext(inode, pos, eloc, elen, 1); 23528c2ecf20Sopenharmony_ci if (etype == -1) { 23538c2ecf20Sopenharmony_ci *offset = (bcount - lbcount) >> blocksize_bits; 23548c2ecf20Sopenharmony_ci iinfo->i_lenExtents = lbcount; 23558c2ecf20Sopenharmony_ci return -1; 23568c2ecf20Sopenharmony_ci } 23578c2ecf20Sopenharmony_ci lbcount += *elen; 23588c2ecf20Sopenharmony_ci } while (lbcount <= bcount); 23598c2ecf20Sopenharmony_ci /* update extent cache */ 23608c2ecf20Sopenharmony_ci udf_update_extent_cache(inode, lbcount - *elen, pos); 23618c2ecf20Sopenharmony_ci *offset = (bcount + *elen - lbcount) >> blocksize_bits; 23628c2ecf20Sopenharmony_ci 23638c2ecf20Sopenharmony_ci return etype; 23648c2ecf20Sopenharmony_ci} 23658c2ecf20Sopenharmony_ci 23668c2ecf20Sopenharmony_ciudf_pblk_t udf_block_map(struct inode *inode, sector_t block) 23678c2ecf20Sopenharmony_ci{ 23688c2ecf20Sopenharmony_ci struct kernel_lb_addr eloc; 23698c2ecf20Sopenharmony_ci uint32_t elen; 23708c2ecf20Sopenharmony_ci sector_t offset; 23718c2ecf20Sopenharmony_ci struct extent_position epos = {}; 23728c2ecf20Sopenharmony_ci udf_pblk_t ret; 23738c2ecf20Sopenharmony_ci 23748c2ecf20Sopenharmony_ci down_read(&UDF_I(inode)->i_data_sem); 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_ci if (inode_bmap(inode, block, &epos, &eloc, &elen, &offset) == 23778c2ecf20Sopenharmony_ci (EXT_RECORDED_ALLOCATED >> 30)) 23788c2ecf20Sopenharmony_ci ret = udf_get_lb_pblock(inode->i_sb, &eloc, offset); 23798c2ecf20Sopenharmony_ci else 23808c2ecf20Sopenharmony_ci ret = 0; 23818c2ecf20Sopenharmony_ci 23828c2ecf20Sopenharmony_ci up_read(&UDF_I(inode)->i_data_sem); 23838c2ecf20Sopenharmony_ci brelse(epos.bh); 23848c2ecf20Sopenharmony_ci 23858c2ecf20Sopenharmony_ci if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_VARCONV)) 23868c2ecf20Sopenharmony_ci return udf_fixed_to_variable(ret); 23878c2ecf20Sopenharmony_ci else 23888c2ecf20Sopenharmony_ci return ret; 23898c2ecf20Sopenharmony_ci} 2390