Commit 274978f1 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'fixes_for_v6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs

Pull UDF and ext2 fixes from Jan Kara:

 - Rewrite of udf directory iteration code to address multiple syzbot
   reports

 - Fixes to udf extent handling and block mapping code to address
   several syzbot reports and filesystem corruption issues uncovered by
   fsx & fsstress

 - Convert udf to kmap_local()

 - Add sanity checks when loading udf bitmaps

 - Drop old VARCONV support which I've never seen used and which was
   broken for quite some years without anybody noticing

 - Finish conversion of ext2 to kmap_local()

 - One fix to mpage_writepages() on which other udf fixes depend

* tag 'fixes_for_v6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs: (78 commits)
  udf: Avoid directory type conversion failure due to ENOMEM
  udf: Use unsigned variables for size calculations
  udf: remove reporting loc in debug output
  udf: Check consistency of Space Bitmap Descriptor
  udf: Fix file counting in LVID
  udf: Limit file size to 4TB
  udf: Don't return bh from udf_expand_dir_adinicb()
  udf: Convert udf_expand_file_adinicb() to avoid kmap_atomic()
  udf: Convert udf_adinicb_writepage() to memcpy_to_page()
  udf: Switch udf_adinicb_readpage() to kmap_local_page()
  udf: Move udf_adinicb_readpage() to inode.c
  udf: Mark aops implementation static
  udf: Switch to single address_space_operations
  udf: Add handling of in-ICB files to udf_bmap()
  udf: Convert all file types to use udf_write_end()
  udf: Convert in-ICB files to use udf_write_begin()
  udf: Convert in-ICB files to use udf_direct_IO()
  udf: Convert in-ICB files to use udf_writepages()
  udf: Unify .read_folio for normal and in-ICB files
  udf: Fix off-by-one error when discarding preallocation
  ...
parents cd776a43 df97f64d
...@@ -461,9 +461,9 @@ static int ext2_handle_dirsync(struct inode *dir) ...@@ -461,9 +461,9 @@ static int ext2_handle_dirsync(struct inode *dir)
return err; return err;
} }
void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de, int ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de,
struct page *page, void *page_addr, struct inode *inode, struct page *page, void *page_addr, struct inode *inode,
int update_times) bool update_times)
{ {
loff_t pos = page_offset(page) + loff_t pos = page_offset(page) +
(char *) de - (char *) page_addr; (char *) de - (char *) page_addr;
...@@ -472,7 +472,10 @@ void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de, ...@@ -472,7 +472,10 @@ void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de,
lock_page(page); lock_page(page);
err = ext2_prepare_chunk(page, pos, len); err = ext2_prepare_chunk(page, pos, len);
BUG_ON(err); if (err) {
unlock_page(page);
return err;
}
de->inode = cpu_to_le32(inode->i_ino); de->inode = cpu_to_le32(inode->i_ino);
ext2_set_de_type(de, inode); ext2_set_de_type(de, inode);
ext2_commit_chunk(page, pos, len); ext2_commit_chunk(page, pos, len);
...@@ -480,7 +483,7 @@ void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de, ...@@ -480,7 +483,7 @@ void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de,
dir->i_mtime = dir->i_ctime = current_time(dir); dir->i_mtime = dir->i_ctime = current_time(dir);
EXT2_I(dir)->i_flags &= ~EXT2_BTREE_FL; EXT2_I(dir)->i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(dir); mark_inode_dirty(dir);
ext2_handle_dirsync(dir); return ext2_handle_dirsync(dir);
} }
/* /*
...@@ -646,7 +649,7 @@ int ext2_make_empty(struct inode *inode, struct inode *parent) ...@@ -646,7 +649,7 @@ int ext2_make_empty(struct inode *inode, struct inode *parent)
unlock_page(page); unlock_page(page);
goto fail; goto fail;
} }
kaddr = kmap_atomic(page); kaddr = kmap_local_page(page);
memset(kaddr, 0, chunk_size); memset(kaddr, 0, chunk_size);
de = (struct ext2_dir_entry_2 *)kaddr; de = (struct ext2_dir_entry_2 *)kaddr;
de->name_len = 1; de->name_len = 1;
...@@ -661,7 +664,7 @@ int ext2_make_empty(struct inode *inode, struct inode *parent) ...@@ -661,7 +664,7 @@ int ext2_make_empty(struct inode *inode, struct inode *parent)
de->inode = cpu_to_le32(parent->i_ino); de->inode = cpu_to_le32(parent->i_ino);
memcpy (de->name, "..\0", 4); memcpy (de->name, "..\0", 4);
ext2_set_de_type (de, inode); ext2_set_de_type (de, inode);
kunmap_atomic(kaddr); kunmap_local(kaddr);
ext2_commit_chunk(page, 0, chunk_size); ext2_commit_chunk(page, 0, chunk_size);
err = ext2_handle_dirsync(inode); err = ext2_handle_dirsync(inode);
fail: fail:
......
...@@ -734,8 +734,9 @@ extern int ext2_delete_entry(struct ext2_dir_entry_2 *dir, struct page *page, ...@@ -734,8 +734,9 @@ extern int ext2_delete_entry(struct ext2_dir_entry_2 *dir, struct page *page,
char *kaddr); char *kaddr);
extern int ext2_empty_dir (struct inode *); extern int ext2_empty_dir (struct inode *);
extern struct ext2_dir_entry_2 *ext2_dotdot(struct inode *dir, struct page **p, void **pa); extern struct ext2_dir_entry_2 *ext2_dotdot(struct inode *dir, struct page **p, void **pa);
extern void ext2_set_link(struct inode *, struct ext2_dir_entry_2 *, struct page *, void *, int ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de,
struct inode *, int); struct page *page, void *page_addr, struct inode *inode,
bool update_times);
static inline void ext2_put_page(struct page *page, void *page_addr) static inline void ext2_put_page(struct page *page, void *page_addr)
{ {
kunmap_local(page_addr); kunmap_local(page_addr);
......
...@@ -370,8 +370,11 @@ static int ext2_rename (struct mnt_idmap * idmap, ...@@ -370,8 +370,11 @@ static int ext2_rename (struct mnt_idmap * idmap,
err = PTR_ERR(new_de); err = PTR_ERR(new_de);
goto out_dir; goto out_dir;
} }
ext2_set_link(new_dir, new_de, new_page, page_addr, old_inode, 1); err = ext2_set_link(new_dir, new_de, new_page, page_addr,
old_inode, true);
ext2_put_page(new_page, page_addr); ext2_put_page(new_page, page_addr);
if (err)
goto out_dir;
new_inode->i_ctime = current_time(new_inode); new_inode->i_ctime = current_time(new_inode);
if (dir_de) if (dir_de)
drop_nlink(new_inode); drop_nlink(new_inode);
...@@ -394,24 +397,24 @@ static int ext2_rename (struct mnt_idmap * idmap, ...@@ -394,24 +397,24 @@ static int ext2_rename (struct mnt_idmap * idmap,
ext2_delete_entry(old_de, old_page, old_page_addr); ext2_delete_entry(old_de, old_page, old_page_addr);
if (dir_de) { if (dir_de) {
if (old_dir != new_dir) if (old_dir != new_dir) {
ext2_set_link(old_inode, dir_de, dir_page, err = ext2_set_link(old_inode, dir_de, dir_page,
dir_page_addr, new_dir, 0); dir_page_addr, new_dir, false);
}
ext2_put_page(dir_page, dir_page_addr); ext2_put_page(dir_page, dir_page_addr);
inode_dec_link_count(old_dir); inode_dec_link_count(old_dir);
} }
out_old:
ext2_put_page(old_page, old_page_addr); ext2_put_page(old_page, old_page_addr);
return 0; out:
return err;
out_dir: out_dir:
if (dir_de) if (dir_de)
ext2_put_page(dir_page, dir_page_addr); ext2_put_page(dir_page, dir_page_addr);
out_old: goto out_old;
ext2_put_page(old_page, old_page_addr);
out:
return err;
} }
const struct inode_operations ext2_dir_inode_operations = { const struct inode_operations ext2_dir_inode_operations = {
......
...@@ -532,6 +532,8 @@ static int __mpage_writepage(struct page *page, struct writeback_control *wbc, ...@@ -532,6 +532,8 @@ static int __mpage_writepage(struct page *page, struct writeback_control *wbc,
map_bh.b_size = 1 << blkbits; map_bh.b_size = 1 << blkbits;
if (mpd->get_block(inode, block_in_file, &map_bh, 1)) if (mpd->get_block(inode, block_in_file, &map_bh, 1))
goto confused; goto confused;
if (!buffer_mapped(&map_bh))
goto confused;
if (buffer_new(&map_bh)) if (buffer_new(&map_bh))
clean_bdev_bh_alias(&map_bh); clean_bdev_bh_alias(&map_bh);
if (buffer_boundary(&map_bh)) { if (buffer_boundary(&map_bh)) {
......
...@@ -36,18 +36,41 @@ static int read_block_bitmap(struct super_block *sb, ...@@ -36,18 +36,41 @@ static int read_block_bitmap(struct super_block *sb,
unsigned long bitmap_nr) unsigned long bitmap_nr)
{ {
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
int retval = 0; int i;
int max_bits, off, count;
struct kernel_lb_addr loc; struct kernel_lb_addr loc;
loc.logicalBlockNum = bitmap->s_extPosition; loc.logicalBlockNum = bitmap->s_extPosition;
loc.partitionReferenceNum = UDF_SB(sb)->s_partition; loc.partitionReferenceNum = UDF_SB(sb)->s_partition;
bh = udf_tread(sb, udf_get_lb_pblock(sb, &loc, block)); bh = sb_bread(sb, udf_get_lb_pblock(sb, &loc, block));
bitmap->s_block_bitmap[bitmap_nr] = bh;
if (!bh) if (!bh)
retval = -EIO; return -EIO;
bitmap->s_block_bitmap[bitmap_nr] = bh; /* Check consistency of Space Bitmap buffer. */
return retval; max_bits = sb->s_blocksize * 8;
if (!bitmap_nr) {
off = sizeof(struct spaceBitmapDesc) << 3;
count = min(max_bits - off, bitmap->s_nr_groups);
} else {
/*
* Rough check if bitmap number is too big to have any bitmap
* blocks reserved.
*/
if (bitmap_nr >
(bitmap->s_nr_groups >> (sb->s_blocksize_bits + 3)) + 2)
return 0;
off = 0;
count = bitmap->s_nr_groups - bitmap_nr * max_bits +
(sizeof(struct spaceBitmapDesc) << 3);
count = min(count, max_bits);
}
for (i = 0; i < count; i++)
if (udf_test_bit(i + off, bh->b_data))
return -EFSCORRUPTED;
return 0;
} }
static int __load_block_bitmap(struct super_block *sb, static int __load_block_bitmap(struct super_block *sb,
......
...@@ -39,26 +39,13 @@ ...@@ -39,26 +39,13 @@
static int udf_readdir(struct file *file, struct dir_context *ctx) static int udf_readdir(struct file *file, struct dir_context *ctx)
{ {
struct inode *dir = file_inode(file); struct inode *dir = file_inode(file);
struct udf_inode_info *iinfo = UDF_I(dir);
struct udf_fileident_bh fibh = { .sbh = NULL, .ebh = NULL};
struct fileIdentDesc *fi = NULL;
struct fileIdentDesc cfi;
udf_pblk_t block, iblock;
loff_t nf_pos, emit_pos = 0; loff_t nf_pos, emit_pos = 0;
int flen; int flen;
unsigned char *fname = NULL, *copy_name = NULL; unsigned char *fname = NULL;
unsigned char *nameptr; int ret = 0;
uint16_t liu;
uint8_t lfi;
loff_t size = udf_ext0_offset(dir) + dir->i_size;
struct buffer_head *tmp, *bha[16];
struct kernel_lb_addr eloc;
uint32_t elen;
sector_t offset;
int i, num, ret = 0;
struct extent_position epos = { NULL, 0, {0, 0} };
struct super_block *sb = dir->i_sb; struct super_block *sb = dir->i_sb;
bool pos_valid = false; bool pos_valid = false;
struct udf_fileident_iter iter;
if (ctx->pos == 0) { if (ctx->pos == 0) {
if (!dir_emit_dot(file, ctx)) if (!dir_emit_dot(file, ctx))
...@@ -66,7 +53,7 @@ static int udf_readdir(struct file *file, struct dir_context *ctx) ...@@ -66,7 +53,7 @@ static int udf_readdir(struct file *file, struct dir_context *ctx)
ctx->pos = 1; ctx->pos = 1;
} }
nf_pos = (ctx->pos - 1) << 2; nf_pos = (ctx->pos - 1) << 2;
if (nf_pos >= size) if (nf_pos >= dir->i_size)
goto out; goto out;
/* /*
...@@ -90,138 +77,57 @@ static int udf_readdir(struct file *file, struct dir_context *ctx) ...@@ -90,138 +77,57 @@ static int udf_readdir(struct file *file, struct dir_context *ctx)
goto out; goto out;
} }
if (nf_pos == 0) for (ret = udf_fiiter_init(&iter, dir, nf_pos);
nf_pos = udf_ext0_offset(dir); !ret && iter.pos < dir->i_size;
ret = udf_fiiter_advance(&iter)) {
fibh.soffset = fibh.eoffset = nf_pos & (sb->s_blocksize - 1);
if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
if (inode_bmap(dir, nf_pos >> sb->s_blocksize_bits,
&epos, &eloc, &elen, &offset)
!= (EXT_RECORDED_ALLOCATED >> 30)) {
ret = -ENOENT;
goto out;
}
block = udf_get_lb_pblock(sb, &eloc, offset);
if ((++offset << sb->s_blocksize_bits) < elen) {
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
epos.offset -= sizeof(struct short_ad);
else if (iinfo->i_alloc_type ==
ICBTAG_FLAG_AD_LONG)
epos.offset -= sizeof(struct long_ad);
} else {
offset = 0;
}
if (!(fibh.sbh = fibh.ebh = udf_tread(sb, block))) {
ret = -EIO;
goto out;
}
if (!(offset & ((16 >> (sb->s_blocksize_bits - 9)) - 1))) {
i = 16 >> (sb->s_blocksize_bits - 9);
if (i + offset > (elen >> sb->s_blocksize_bits))
i = (elen >> sb->s_blocksize_bits) - offset;
for (num = 0; i > 0; i--) {
block = udf_get_lb_pblock(sb, &eloc, offset + i);
tmp = udf_tgetblk(sb, block);
if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp))
bha[num++] = tmp;
else
brelse(tmp);
}
if (num) {
bh_readahead_batch(num, bha, REQ_RAHEAD);
for (i = 0; i < num; i++)
brelse(bha[i]);
}
}
}
while (nf_pos < size) {
struct kernel_lb_addr tloc; struct kernel_lb_addr tloc;
loff_t cur_pos = nf_pos; udf_pblk_t iblock;
/* Update file position only if we got past the current one */
if (nf_pos >= emit_pos) {
ctx->pos = (nf_pos >> 2) + 1;
pos_valid = true;
}
fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &epos, &eloc,
&elen, &offset);
if (!fi)
goto out;
/* Still not at offset where user asked us to read from? */ /* Still not at offset where user asked us to read from? */
if (cur_pos < emit_pos) if (iter.pos < emit_pos)
continue; continue;
liu = le16_to_cpu(cfi.lengthOfImpUse); /* Update file position only if we got past the current one */
lfi = cfi.lengthFileIdent; pos_valid = true;
ctx->pos = (iter.pos >> 2) + 1;
if (fibh.sbh == fibh.ebh) {
nameptr = udf_get_fi_ident(fi);
} else {
int poffset; /* Unpaded ending offset */
poffset = fibh.soffset + sizeof(struct fileIdentDesc) + liu + lfi;
if (poffset >= lfi) {
nameptr = (char *)(fibh.ebh->b_data + poffset - lfi);
} else {
if (!copy_name) {
copy_name = kmalloc(UDF_NAME_LEN,
GFP_NOFS);
if (!copy_name) {
ret = -ENOMEM;
goto out;
}
}
nameptr = copy_name;
memcpy(nameptr, udf_get_fi_ident(fi),
lfi - poffset);
memcpy(nameptr + lfi - poffset,
fibh.ebh->b_data, poffset);
}
}
if ((cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) { if (iter.fi.fileCharacteristics & FID_FILE_CHAR_DELETED) {
if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNDELETE)) if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNDELETE))
continue; continue;
} }
if ((cfi.fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0) { if (iter.fi.fileCharacteristics & FID_FILE_CHAR_HIDDEN) {
if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNHIDE)) if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNHIDE))
continue; continue;
} }
if (cfi.fileCharacteristics & FID_FILE_CHAR_PARENT) { if (iter.fi.fileCharacteristics & FID_FILE_CHAR_PARENT) {
if (!dir_emit_dotdot(file, ctx)) if (!dir_emit_dotdot(file, ctx))
goto out; goto out_iter;
continue; continue;
} }
flen = udf_get_filename(sb, nameptr, lfi, fname, UDF_NAME_LEN); flen = udf_get_filename(sb, iter.name,
iter.fi.lengthFileIdent, fname, UDF_NAME_LEN);
if (flen < 0) if (flen < 0)
continue; continue;
tloc = lelb_to_cpu(cfi.icb.extLocation); tloc = lelb_to_cpu(iter.fi.icb.extLocation);
iblock = udf_get_lb_pblock(sb, &tloc, 0); iblock = udf_get_lb_pblock(sb, &tloc, 0);
if (!dir_emit(ctx, fname, flen, iblock, DT_UNKNOWN)) if (!dir_emit(ctx, fname, flen, iblock, DT_UNKNOWN))
goto out; goto out_iter;
} /* end while */ }
ctx->pos = (nf_pos >> 2) + 1;
pos_valid = true;
if (!ret) {
ctx->pos = (iter.pos >> 2) + 1;
pos_valid = true;
}
out_iter:
udf_fiiter_release(&iter);
out: out:
if (pos_valid) if (pos_valid)
file->f_version = inode_query_iversion(dir); file->f_version = inode_query_iversion(dir);
if (fibh.sbh != fibh.ebh)
brelse(fibh.ebh);
brelse(fibh.sbh);
brelse(epos.bh);
kfree(fname); kfree(fname);
kfree(copy_name);
return ret; return ret;
} }
......
This diff is collapsed.
...@@ -38,100 +38,55 @@ ...@@ -38,100 +38,55 @@
#include "udf_i.h" #include "udf_i.h"
#include "udf_sb.h" #include "udf_sb.h"
static void __udf_adinicb_readpage(struct page *page) static vm_fault_t udf_page_mkwrite(struct vm_fault *vmf)
{ {
struct inode *inode = page->mapping->host; struct vm_area_struct *vma = vmf->vma;
char *kaddr; struct inode *inode = file_inode(vma->vm_file);
struct udf_inode_info *iinfo = UDF_I(inode); struct address_space *mapping = inode->i_mapping;
loff_t isize = i_size_read(inode); struct page *page = vmf->page;
loff_t size;
/* unsigned int end;
* We have to be careful here as truncate can change i_size under us. vm_fault_t ret = VM_FAULT_LOCKED;
* So just sample it once and use the same value everywhere. int err;
*/
kaddr = kmap_atomic(page);
memcpy(kaddr, iinfo->i_data + iinfo->i_lenEAttr, isize);
memset(kaddr + isize, 0, PAGE_SIZE - isize);
flush_dcache_page(page);
SetPageUptodate(page);
kunmap_atomic(kaddr);
}
static int udf_adinicb_read_folio(struct file *file, struct folio *folio)
{
BUG_ON(!folio_test_locked(folio));
__udf_adinicb_readpage(&folio->page);
folio_unlock(folio);
return 0;
}
static int udf_adinicb_writepage(struct page *page,
struct writeback_control *wbc)
{
struct inode *inode = page->mapping->host;
char *kaddr;
struct udf_inode_info *iinfo = UDF_I(inode);
BUG_ON(!PageLocked(page));
kaddr = kmap_atomic(page);
memcpy(iinfo->i_data + iinfo->i_lenEAttr, kaddr, i_size_read(inode));
SetPageUptodate(page);
kunmap_atomic(kaddr);
mark_inode_dirty(inode);
unlock_page(page);
return 0;
}
static int udf_adinicb_write_begin(struct file *file,
struct address_space *mapping, loff_t pos,
unsigned len, struct page **pagep,
void **fsdata)
{
struct page *page;
if (WARN_ON_ONCE(pos >= PAGE_SIZE))
return -EIO;
page = grab_cache_page_write_begin(mapping, 0);
if (!page)
return -ENOMEM;
*pagep = page;
if (!PageUptodate(page))
__udf_adinicb_readpage(page);
return 0;
}
static ssize_t udf_adinicb_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
{
/* Fallback to buffered I/O. */
return 0;
}
static int udf_adinicb_write_end(struct file *file, struct address_space *mapping, sb_start_pagefault(inode->i_sb);
loff_t pos, unsigned len, unsigned copied, file_update_time(vma->vm_file);
struct page *page, void *fsdata) filemap_invalidate_lock_shared(mapping);
{ lock_page(page);
struct inode *inode = page->mapping->host; size = i_size_read(inode);
loff_t last_pos = pos + copied; if (page->mapping != inode->i_mapping || page_offset(page) >= size) {
if (last_pos > inode->i_size) unlock_page(page);
i_size_write(inode, last_pos); ret = VM_FAULT_NOPAGE;
goto out_unlock;
}
/* Space is already allocated for in-ICB file */
if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
goto out_dirty;
if (page->index == size >> PAGE_SHIFT)
end = size & ~PAGE_MASK;
else
end = PAGE_SIZE;
err = __block_write_begin(page, 0, end, udf_get_block);
if (!err)
err = block_commit_write(page, 0, end);
if (err < 0) {
unlock_page(page);
ret = block_page_mkwrite_return(err);
goto out_unlock;
}
out_dirty:
set_page_dirty(page); set_page_dirty(page);
unlock_page(page); wait_for_stable_page(page);
put_page(page); out_unlock:
return copied; filemap_invalidate_unlock_shared(mapping);
sb_end_pagefault(inode->i_sb);
return ret;
} }
const struct address_space_operations udf_adinicb_aops = { static const struct vm_operations_struct udf_file_vm_ops = {
.dirty_folio = block_dirty_folio, .fault = filemap_fault,
.invalidate_folio = block_invalidate_folio, .map_pages = filemap_map_pages,
.read_folio = udf_adinicb_read_folio, .page_mkwrite = udf_page_mkwrite,
.writepage = udf_adinicb_writepage,
.write_begin = udf_adinicb_write_begin,
.write_end = udf_adinicb_write_end,
.direct_IO = udf_adinicb_direct_IO,
}; };
static ssize_t udf_file_write_iter(struct kiocb *iocb, struct iov_iter *from) static ssize_t udf_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
...@@ -140,7 +95,6 @@ static ssize_t udf_file_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -140,7 +95,6 @@ static ssize_t udf_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
struct file *file = iocb->ki_filp; struct file *file = iocb->ki_filp;
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
struct udf_inode_info *iinfo = UDF_I(inode); struct udf_inode_info *iinfo = UDF_I(inode);
int err;
inode_lock(inode); inode_lock(inode);
...@@ -148,27 +102,23 @@ static ssize_t udf_file_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -148,27 +102,23 @@ static ssize_t udf_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
if (retval <= 0) if (retval <= 0)
goto out; goto out;
down_write(&iinfo->i_data_sem); if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB &&
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) +
loff_t end = iocb->ki_pos + iov_iter_count(from); iocb->ki_pos + iov_iter_count(from))) {
filemap_invalidate_lock(inode->i_mapping);
if (inode->i_sb->s_blocksize < retval = udf_expand_file_adinicb(inode);
(udf_file_entry_alloc_offset(inode) + end)) { filemap_invalidate_unlock(inode->i_mapping);
err = udf_expand_file_adinicb(inode); if (retval)
if (err) { goto out;
inode_unlock(inode); }
udf_debug("udf_expand_adinicb: err=%d\n", err);
return err;
}
} else {
iinfo->i_lenAlloc = max(end, inode->i_size);
up_write(&iinfo->i_data_sem);
}
} else
up_write(&iinfo->i_data_sem);
retval = __generic_file_write_iter(iocb, from); retval = __generic_file_write_iter(iocb, from);
out: out:
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB && retval > 0) {
down_write(&iinfo->i_data_sem);
iinfo->i_lenAlloc = inode->i_size;
up_write(&iinfo->i_data_sem);
}
inode_unlock(inode); inode_unlock(inode);
if (retval > 0) { if (retval > 0) {
...@@ -243,11 +193,19 @@ static int udf_release_file(struct inode *inode, struct file *filp) ...@@ -243,11 +193,19 @@ static int udf_release_file(struct inode *inode, struct file *filp)
return 0; return 0;
} }
static int udf_file_mmap(struct file *file, struct vm_area_struct *vma)
{
file_accessed(file);
vma->vm_ops = &udf_file_vm_ops;
return 0;
}
const struct file_operations udf_file_operations = { const struct file_operations udf_file_operations = {
.read_iter = generic_file_read_iter, .read_iter = generic_file_read_iter,
.unlocked_ioctl = udf_ioctl, .unlocked_ioctl = udf_ioctl,
.open = generic_file_open, .open = generic_file_open,
.mmap = generic_file_mmap, .mmap = udf_file_mmap,
.write_iter = udf_file_write_iter, .write_iter = udf_file_write_iter,
.release = udf_release_file, .release = udf_release_file,
.fsync = generic_file_fsync, .fsync = generic_file_fsync,
......
...@@ -28,21 +28,7 @@ ...@@ -28,21 +28,7 @@
void udf_free_inode(struct inode *inode) void udf_free_inode(struct inode *inode)
{ {
struct super_block *sb = inode->i_sb; udf_free_blocks(inode->i_sb, NULL, &UDF_I(inode)->i_location, 0, 1);
struct udf_sb_info *sbi = UDF_SB(sb);
struct logicalVolIntegrityDescImpUse *lvidiu = udf_sb_lvidiu(sb);
if (lvidiu) {
mutex_lock(&sbi->s_alloc_mutex);
if (S_ISDIR(inode->i_mode))
le32_add_cpu(&lvidiu->numDirs, -1);
else
le32_add_cpu(&lvidiu->numFiles, -1);
udf_updated_lvid(sb);
mutex_unlock(&sbi->s_alloc_mutex);
}
udf_free_blocks(sb, NULL, &UDF_I(inode)->i_location, 0, 1);
} }
struct inode *udf_new_inode(struct inode *dir, umode_t mode) struct inode *udf_new_inode(struct inode *dir, umode_t mode)
...@@ -54,7 +40,6 @@ struct inode *udf_new_inode(struct inode *dir, umode_t mode) ...@@ -54,7 +40,6 @@ struct inode *udf_new_inode(struct inode *dir, umode_t mode)
uint32_t start = UDF_I(dir)->i_location.logicalBlockNum; uint32_t start = UDF_I(dir)->i_location.logicalBlockNum;
struct udf_inode_info *iinfo; struct udf_inode_info *iinfo;
struct udf_inode_info *dinfo = UDF_I(dir); struct udf_inode_info *dinfo = UDF_I(dir);
struct logicalVolIntegrityDescImpUse *lvidiu;
int err; int err;
inode = new_inode(sb); inode = new_inode(sb);
...@@ -92,18 +77,8 @@ struct inode *udf_new_inode(struct inode *dir, umode_t mode) ...@@ -92,18 +77,8 @@ struct inode *udf_new_inode(struct inode *dir, umode_t mode)
return ERR_PTR(err); return ERR_PTR(err);
} }
lvidiu = udf_sb_lvidiu(sb); iinfo->i_unique = lvid_get_unique_id(sb);
if (lvidiu) { inode->i_generation = iinfo->i_unique;
iinfo->i_unique = lvid_get_unique_id(sb);
inode->i_generation = iinfo->i_unique;
mutex_lock(&sbi->s_alloc_mutex);
if (S_ISDIR(mode))
le32_add_cpu(&lvidiu->numDirs, 1);
else
le32_add_cpu(&lvidiu->numFiles, 1);
udf_updated_lvid(sb);
mutex_unlock(&sbi->s_alloc_mutex);
}
inode_init_owner(&nop_mnt_idmap, inode, dir, mode); inode_init_owner(&nop_mnt_idmap, inode, dir, mode);
if (UDF_QUERY_FLAG(sb, UDF_FLAG_UID_SET)) if (UDF_QUERY_FLAG(sb, UDF_FLAG_UID_SET))
......
This diff is collapsed.
...@@ -45,7 +45,7 @@ unsigned int udf_get_last_session(struct super_block *sb) ...@@ -45,7 +45,7 @@ unsigned int udf_get_last_session(struct super_block *sb)
return 0; return 0;
} }
unsigned long udf_get_last_block(struct super_block *sb) udf_pblk_t udf_get_last_block(struct super_block *sb)
{ {
struct cdrom_device_info *cdi = disk_to_cdi(sb->s_bdev->bd_disk); struct cdrom_device_info *cdi = disk_to_cdi(sb->s_bdev->bd_disk);
unsigned long lblock = 0; unsigned long lblock = 0;
...@@ -54,8 +54,11 @@ unsigned long udf_get_last_block(struct super_block *sb) ...@@ -54,8 +54,11 @@ unsigned long udf_get_last_block(struct super_block *sb)
* The cdrom layer call failed or returned obviously bogus value? * The cdrom layer call failed or returned obviously bogus value?
* Try using the device size... * Try using the device size...
*/ */
if (!cdi || cdrom_get_last_written(cdi, &lblock) || lblock == 0) if (!cdi || cdrom_get_last_written(cdi, &lblock) || lblock == 0) {
if (sb_bdev_nr_blocks(sb) > ~(udf_pblk_t)0)
return 0;
lblock = sb_bdev_nr_blocks(sb); lblock = sb_bdev_nr_blocks(sb);
}
if (lblock) if (lblock)
return lblock - 1; return lblock - 1;
......
...@@ -28,22 +28,6 @@ ...@@ -28,22 +28,6 @@
#include "udf_i.h" #include "udf_i.h"
#include "udf_sb.h" #include "udf_sb.h"
struct buffer_head *udf_tgetblk(struct super_block *sb, udf_pblk_t block)
{
if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV))
return sb_getblk(sb, udf_fixed_to_variable(block));
else
return sb_getblk(sb, block);
}
struct buffer_head *udf_tread(struct super_block *sb, udf_pblk_t block)
{
if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV))
return sb_bread(sb, udf_fixed_to_variable(block));
else
return sb_bread(sb, block);
}
struct genericFormat *udf_add_extendedattr(struct inode *inode, uint32_t size, struct genericFormat *udf_add_extendedattr(struct inode *inode, uint32_t size,
uint32_t type, uint8_t loc) uint32_t type, uint8_t loc)
{ {
...@@ -216,7 +200,7 @@ struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block, ...@@ -216,7 +200,7 @@ struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block,
if (block == 0xFFFFFFFF) if (block == 0xFFFFFFFF)
return NULL; return NULL;
bh = udf_tread(sb, block); bh = sb_bread(sb, block);
if (!bh) { if (!bh) {
udf_err(sb, "read failed, block=%u, location=%u\n", udf_err(sb, "read failed, block=%u, location=%u\n",
block, location); block, location);
......
This diff is collapsed.
...@@ -54,6 +54,7 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, ...@@ -54,6 +54,7 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block,
struct udf_part_map *map; struct udf_part_map *map;
struct udf_virtual_data *vdata; struct udf_virtual_data *vdata;
struct udf_inode_info *iinfo = UDF_I(sbi->s_vat_inode); struct udf_inode_info *iinfo = UDF_I(sbi->s_vat_inode);
int err;
map = &sbi->s_partmaps[partition]; map = &sbi->s_partmaps[partition];
vdata = &map->s_type_specific.s_virtual; vdata = &map->s_type_specific.s_virtual;
...@@ -79,12 +80,10 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, ...@@ -79,12 +80,10 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block,
index = vdata->s_start_offset / sizeof(uint32_t) + block; index = vdata->s_start_offset / sizeof(uint32_t) + block;
} }
loc = udf_block_map(sbi->s_vat_inode, newblock); bh = udf_bread(sbi->s_vat_inode, newblock, 0, &err);
bh = sb_bread(sb, loc);
if (!bh) { if (!bh) {
udf_debug("get_pblock(UDF_VIRTUAL_MAP:%p,%u,%u) VAT: %u[%u]\n", udf_debug("get_pblock(UDF_VIRTUAL_MAP:%p,%u,%u)\n",
sb, block, partition, loc, index); sb, block, partition);
return 0xFFFFFFFF; return 0xFFFFFFFF;
} }
......
...@@ -86,6 +86,13 @@ enum { ...@@ -86,6 +86,13 @@ enum {
#define UDF_MAX_LVID_NESTING 1000 #define UDF_MAX_LVID_NESTING 1000
enum { UDF_MAX_LINKS = 0xffff }; enum { UDF_MAX_LINKS = 0xffff };
/*
* We limit filesize to 4TB. This is arbitrary as the on-disk format supports
* more but because the file space is described by a linked list of extents,
* each of which can have at most 1GB, the creation and handling of extents
* gets unusably slow beyond certain point...
*/
#define UDF_MAX_FILESIZE (1ULL << 42)
/* These are the "meat" - everything else is stuffing */ /* These are the "meat" - everything else is stuffing */
static int udf_fill_super(struct super_block *, void *, int); static int udf_fill_super(struct super_block *, void *, int);
...@@ -147,6 +154,7 @@ static struct inode *udf_alloc_inode(struct super_block *sb) ...@@ -147,6 +154,7 @@ static struct inode *udf_alloc_inode(struct super_block *sb)
ei->i_next_alloc_goal = 0; ei->i_next_alloc_goal = 0;
ei->i_strat4096 = 0; ei->i_strat4096 = 0;
ei->i_streamdir = 0; ei->i_streamdir = 0;
ei->i_hidden = 0;
init_rwsem(&ei->i_data_sem); init_rwsem(&ei->i_data_sem);
ei->cached_extent.lstart = -1; ei->cached_extent.lstart = -1;
spin_lock_init(&ei->i_extent_cache_lock); spin_lock_init(&ei->i_extent_cache_lock);
...@@ -733,7 +741,7 @@ static int udf_check_vsd(struct super_block *sb) ...@@ -733,7 +741,7 @@ static int udf_check_vsd(struct super_block *sb)
* added */ * added */
for (; !nsr && sector < VSD_MAX_SECTOR_OFFSET; sector += sectorsize) { for (; !nsr && sector < VSD_MAX_SECTOR_OFFSET; sector += sectorsize) {
/* Read a block */ /* Read a block */
bh = udf_tread(sb, sector >> sb->s_blocksize_bits); bh = sb_bread(sb, sector >> sb->s_blocksize_bits);
if (!bh) if (!bh)
break; break;
...@@ -1175,7 +1183,6 @@ static int udf_load_vat(struct super_block *sb, int p_index, int type1_index) ...@@ -1175,7 +1183,6 @@ static int udf_load_vat(struct super_block *sb, int p_index, int type1_index)
struct udf_part_map *map = &sbi->s_partmaps[p_index]; struct udf_part_map *map = &sbi->s_partmaps[p_index];
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
struct udf_inode_info *vati; struct udf_inode_info *vati;
uint32_t pos;
struct virtualAllocationTable20 *vat20; struct virtualAllocationTable20 *vat20;
sector_t blocks = sb_bdev_nr_blocks(sb); sector_t blocks = sb_bdev_nr_blocks(sb);
...@@ -1197,10 +1204,14 @@ static int udf_load_vat(struct super_block *sb, int p_index, int type1_index) ...@@ -1197,10 +1204,14 @@ static int udf_load_vat(struct super_block *sb, int p_index, int type1_index)
} else if (map->s_partition_type == UDF_VIRTUAL_MAP20) { } else if (map->s_partition_type == UDF_VIRTUAL_MAP20) {
vati = UDF_I(sbi->s_vat_inode); vati = UDF_I(sbi->s_vat_inode);
if (vati->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { if (vati->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
pos = udf_block_map(sbi->s_vat_inode, 0); int err = 0;
bh = sb_bread(sb, pos);
if (!bh) bh = udf_bread(sbi->s_vat_inode, 0, 0, &err);
return -EIO; if (!bh) {
if (!err)
err = -EFSCORRUPTED;
return err;
}
vat20 = (struct virtualAllocationTable20 *)bh->b_data; vat20 = (struct virtualAllocationTable20 *)bh->b_data;
} else { } else {
vat20 = (struct virtualAllocationTable20 *) vat20 = (struct virtualAllocationTable20 *)
...@@ -1838,10 +1849,6 @@ static int udf_check_anchor_block(struct super_block *sb, sector_t block, ...@@ -1838,10 +1849,6 @@ static int udf_check_anchor_block(struct super_block *sb, sector_t block,
uint16_t ident; uint16_t ident;
int ret; int ret;
if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV) &&
udf_fixed_to_variable(block) >= sb_bdev_nr_blocks(sb))
return -EAGAIN;
bh = udf_read_tagged(sb, block, block, &ident); bh = udf_read_tagged(sb, block, block, &ident);
if (!bh) if (!bh)
return -EAGAIN; return -EAGAIN;
...@@ -1860,10 +1867,10 @@ static int udf_check_anchor_block(struct super_block *sb, sector_t block, ...@@ -1860,10 +1867,10 @@ static int udf_check_anchor_block(struct super_block *sb, sector_t block,
* Returns < 0 on error, 0 on success. -EAGAIN is special - try next set * Returns < 0 on error, 0 on success. -EAGAIN is special - try next set
* of anchors. * of anchors.
*/ */
static int udf_scan_anchors(struct super_block *sb, sector_t *lastblock, static int udf_scan_anchors(struct super_block *sb, udf_pblk_t *lastblock,
struct kernel_lb_addr *fileset) struct kernel_lb_addr *fileset)
{ {
sector_t last[6]; udf_pblk_t last[6];
int i; int i;
struct udf_sb_info *sbi = UDF_SB(sb); struct udf_sb_info *sbi = UDF_SB(sb);
int last_count = 0; int last_count = 0;
...@@ -1923,46 +1930,6 @@ static int udf_scan_anchors(struct super_block *sb, sector_t *lastblock, ...@@ -1923,46 +1930,6 @@ static int udf_scan_anchors(struct super_block *sb, sector_t *lastblock,
return udf_check_anchor_block(sb, sbi->s_session + 512, fileset); return udf_check_anchor_block(sb, sbi->s_session + 512, fileset);
} }
/*
* Find an anchor volume descriptor and load Volume Descriptor Sequence from
* area specified by it. The function expects sbi->s_lastblock to be the last
* block on the media.
*
* Return <0 on error, 0 if anchor found. -EAGAIN is special meaning anchor
* was not found.
*/
static int udf_find_anchor(struct super_block *sb,
struct kernel_lb_addr *fileset)
{
struct udf_sb_info *sbi = UDF_SB(sb);
sector_t lastblock = sbi->s_last_block;
int ret;
ret = udf_scan_anchors(sb, &lastblock, fileset);
if (ret != -EAGAIN)
goto out;
/* No anchor found? Try VARCONV conversion of block numbers */
UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
lastblock = udf_variable_to_fixed(sbi->s_last_block);
/* Firstly, we try to not convert number of the last block */
ret = udf_scan_anchors(sb, &lastblock, fileset);
if (ret != -EAGAIN)
goto out;
lastblock = sbi->s_last_block;
/* Secondly, we try with converted number of the last block */
ret = udf_scan_anchors(sb, &lastblock, fileset);
if (ret < 0) {
/* VARCONV didn't help. Clear it. */
UDF_CLEAR_FLAG(sb, UDF_FLAG_VARCONV);
}
out:
if (ret == 0)
sbi->s_last_block = lastblock;
return ret;
}
/* /*
* Check Volume Structure Descriptor, find Anchor block and load Volume * Check Volume Structure Descriptor, find Anchor block and load Volume
* Descriptor Sequence. * Descriptor Sequence.
...@@ -2003,7 +1970,7 @@ static int udf_load_vrs(struct super_block *sb, struct udf_options *uopt, ...@@ -2003,7 +1970,7 @@ static int udf_load_vrs(struct super_block *sb, struct udf_options *uopt,
/* Look for anchor block and load Volume Descriptor Sequence */ /* Look for anchor block and load Volume Descriptor Sequence */
sbi->s_anchor = uopt->anchor; sbi->s_anchor = uopt->anchor;
ret = udf_find_anchor(sb, fileset); ret = udf_scan_anchors(sb, &sbi->s_last_block, fileset);
if (ret < 0) { if (ret < 0) {
if (!silent && ret == -EAGAIN) if (!silent && ret == -EAGAIN)
udf_warn(sb, "No anchor found\n"); udf_warn(sb, "No anchor found\n");
...@@ -2297,7 +2264,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) ...@@ -2297,7 +2264,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
ret = -ENOMEM; ret = -ENOMEM;
goto error_out; goto error_out;
} }
sb->s_maxbytes = MAX_LFS_FILESIZE; sb->s_maxbytes = UDF_MAX_FILESIZE;
sb->s_max_links = UDF_MAX_LINKS; sb->s_max_links = UDF_MAX_LINKS;
return 0; return 0;
...@@ -2454,7 +2421,7 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb, ...@@ -2454,7 +2421,7 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb,
if (bytes) { if (bytes) {
brelse(bh); brelse(bh);
newblock = udf_get_lb_pblock(sb, &loc, ++block); newblock = udf_get_lb_pblock(sb, &loc, ++block);
bh = udf_tread(sb, newblock); bh = sb_bread(sb, newblock);
if (!bh) { if (!bh) {
udf_debug("read failed\n"); udf_debug("read failed\n");
goto out; goto out;
......
...@@ -107,48 +107,40 @@ static int udf_symlink_filler(struct file *file, struct folio *folio) ...@@ -107,48 +107,40 @@ static int udf_symlink_filler(struct file *file, struct folio *folio)
struct inode *inode = page->mapping->host; struct inode *inode = page->mapping->host;
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
unsigned char *symlink; unsigned char *symlink;
int err; int err = 0;
unsigned char *p = page_address(page); unsigned char *p = page_address(page);
struct udf_inode_info *iinfo; struct udf_inode_info *iinfo = UDF_I(inode);
uint32_t pos;
/* We don't support symlinks longer than one block */ /* We don't support symlinks longer than one block */
if (inode->i_size > inode->i_sb->s_blocksize) { if (inode->i_size > inode->i_sb->s_blocksize) {
err = -ENAMETOOLONG; err = -ENAMETOOLONG;
goto out_unmap; goto out_unlock;
} }
iinfo = UDF_I(inode);
pos = udf_block_map(inode, 0);
down_read(&iinfo->i_data_sem);
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
symlink = iinfo->i_data + iinfo->i_lenEAttr; symlink = iinfo->i_data + iinfo->i_lenEAttr;
} else { } else {
bh = sb_bread(inode->i_sb, pos); bh = udf_bread(inode, 0, 0, &err);
if (!bh) { if (!bh) {
err = -EIO; if (!err)
goto out_unlock_inode; err = -EFSCORRUPTED;
goto out_err;
} }
symlink = bh->b_data; symlink = bh->b_data;
} }
err = udf_pc_to_char(inode->i_sb, symlink, inode->i_size, p, PAGE_SIZE); err = udf_pc_to_char(inode->i_sb, symlink, inode->i_size, p, PAGE_SIZE);
brelse(bh); brelse(bh);
if (err) if (err)
goto out_unlock_inode; goto out_err;
up_read(&iinfo->i_data_sem);
SetPageUptodate(page); SetPageUptodate(page);
unlock_page(page); unlock_page(page);
return 0; return 0;
out_unlock_inode: out_err:
up_read(&iinfo->i_data_sem);
SetPageError(page); SetPageError(page);
out_unmap: out_unlock:
unlock_page(page); unlock_page(page);
return err; return err;
} }
......
...@@ -125,7 +125,7 @@ void udf_discard_prealloc(struct inode *inode) ...@@ -125,7 +125,7 @@ void udf_discard_prealloc(struct inode *inode)
struct kernel_lb_addr eloc; struct kernel_lb_addr eloc;
uint32_t elen; uint32_t elen;
uint64_t lbcount = 0; uint64_t lbcount = 0;
int8_t etype = -1, netype; int8_t etype = -1;
struct udf_inode_info *iinfo = UDF_I(inode); struct udf_inode_info *iinfo = UDF_I(inode);
int bsize = 1 << inode->i_blkbits; int bsize = 1 << inode->i_blkbits;
...@@ -136,7 +136,7 @@ void udf_discard_prealloc(struct inode *inode) ...@@ -136,7 +136,7 @@ void udf_discard_prealloc(struct inode *inode)
epos.block = iinfo->i_location; epos.block = iinfo->i_location;
/* Find the last extent in the file */ /* Find the last extent in the file */
while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 0)) != -1) { while (udf_next_aext(inode, &epos, &eloc, &elen, 0) != -1) {
brelse(prev_epos.bh); brelse(prev_epos.bh);
prev_epos = epos; prev_epos = epos;
if (prev_epos.bh) if (prev_epos.bh)
...@@ -240,7 +240,7 @@ int udf_truncate_extents(struct inode *inode) ...@@ -240,7 +240,7 @@ int udf_truncate_extents(struct inode *inode)
brelse(epos.bh); brelse(epos.bh);
epos.offset = sizeof(struct allocExtDesc); epos.offset = sizeof(struct allocExtDesc);
epos.block = eloc; epos.block = eloc;
epos.bh = udf_tread(sb, epos.bh = sb_bread(sb,
udf_get_lb_pblock(sb, &eloc, 0)); udf_get_lb_pblock(sb, &eloc, 0));
/* Error reading indirect block? */ /* Error reading indirect block? */
if (!epos.bh) if (!epos.bh)
......
...@@ -44,7 +44,8 @@ struct udf_inode_info { ...@@ -44,7 +44,8 @@ struct udf_inode_info {
unsigned i_use : 1; /* unallocSpaceEntry */ unsigned i_use : 1; /* unallocSpaceEntry */
unsigned i_strat4096 : 1; unsigned i_strat4096 : 1;
unsigned i_streamdir : 1; unsigned i_streamdir : 1;
unsigned reserved : 25; unsigned i_hidden : 1; /* hidden system inode */
unsigned reserved : 24;
__u8 *i_data; __u8 *i_data;
struct kernel_lb_addr i_locStreamdir; struct kernel_lb_addr i_locStreamdir;
__u64 i_lenStreams; __u64 i_lenStreams;
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#define UDF_FLAG_STRICT 5 #define UDF_FLAG_STRICT 5
#define UDF_FLAG_UNDELETE 6 #define UDF_FLAG_UNDELETE 6
#define UDF_FLAG_UNHIDE 7 #define UDF_FLAG_UNHIDE 7
#define UDF_FLAG_VARCONV 8
#define UDF_FLAG_UID_FORGET 11 /* save -1 for uid to disk */ #define UDF_FLAG_UID_FORGET 11 /* save -1 for uid to disk */
#define UDF_FLAG_GID_FORGET 12 #define UDF_FLAG_GID_FORGET 12
#define UDF_FLAG_UID_SET 13 #define UDF_FLAG_UID_SET 13
...@@ -55,6 +54,8 @@ ...@@ -55,6 +54,8 @@
#define MF_DUPLICATE_MD 0x01 #define MF_DUPLICATE_MD 0x01
#define MF_MIRROR_FE_LOADED 0x02 #define MF_MIRROR_FE_LOADED 0x02
#define EFSCORRUPTED EUCLEAN
struct udf_meta_data { struct udf_meta_data {
__u32 s_meta_file_loc; __u32 s_meta_file_loc;
__u32 s_mirror_file_loc; __u32 s_mirror_file_loc;
......
...@@ -34,9 +34,6 @@ extern __printf(3, 4) void _udf_warn(struct super_block *sb, ...@@ -34,9 +34,6 @@ extern __printf(3, 4) void _udf_warn(struct super_block *sb,
#define udf_debug(fmt, ...) \ #define udf_debug(fmt, ...) \
pr_debug("%s:%d:%s: " fmt, __FILE__, __LINE__, __func__, ##__VA_ARGS__) pr_debug("%s:%d:%s: " fmt, __FILE__, __LINE__, __func__, ##__VA_ARGS__)
#define udf_fixed_to_variable(x) ( ( ( (x) >> 5 ) * 39 ) + ( (x) & 0x0000001F ) )
#define udf_variable_to_fixed(x) ( ( ( (x) / 39 ) << 5 ) + ( (x) % 39 ) )
#define UDF_EXTENT_LENGTH_MASK 0x3FFFFFFF #define UDF_EXTENT_LENGTH_MASK 0x3FFFFFFF
#define UDF_EXTENT_FLAG_MASK 0xC0000000 #define UDF_EXTENT_FLAG_MASK 0xC0000000
...@@ -83,14 +80,24 @@ extern const struct inode_operations udf_file_inode_operations; ...@@ -83,14 +80,24 @@ extern const struct inode_operations udf_file_inode_operations;
extern const struct file_operations udf_file_operations; extern const struct file_operations udf_file_operations;
extern const struct inode_operations udf_symlink_inode_operations; extern const struct inode_operations udf_symlink_inode_operations;
extern const struct address_space_operations udf_aops; extern const struct address_space_operations udf_aops;
extern const struct address_space_operations udf_adinicb_aops;
extern const struct address_space_operations udf_symlink_aops; extern const struct address_space_operations udf_symlink_aops;
struct udf_fileident_bh { struct udf_fileident_iter {
struct buffer_head *sbh; struct inode *dir; /* Directory we are working with */
struct buffer_head *ebh; loff_t pos; /* Logical position in a dir */
int soffset; struct buffer_head *bh[2]; /* Buffer containing 'pos' and possibly
int eoffset; * next buffer if entry straddles
* blocks */
struct kernel_lb_addr eloc; /* Start of extent containing 'pos' */
uint32_t elen; /* Length of extent containing 'pos' */
sector_t loffset; /* Block offset of 'pos' within above
* extent */
struct extent_position epos; /* Position after the above extent */
struct fileIdentDesc fi; /* Copied directory entry */
uint8_t *name; /* Pointer to entry name */
uint8_t *namebuf; /* Storage for entry name in case
* the name is split between two blocks
*/
}; };
struct udf_vds_record { struct udf_vds_record {
...@@ -121,22 +128,16 @@ struct inode *udf_find_metadata_inode_efe(struct super_block *sb, ...@@ -121,22 +128,16 @@ struct inode *udf_find_metadata_inode_efe(struct super_block *sb,
u32 meta_file_loc, u32 partition_num); u32 meta_file_loc, u32 partition_num);
/* namei.c */ /* namei.c */
extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *,
struct fileIdentDesc *, struct udf_fileident_bh *,
uint8_t *, uint8_t *);
static inline unsigned int udf_dir_entry_len(struct fileIdentDesc *cfi) static inline unsigned int udf_dir_entry_len(struct fileIdentDesc *cfi)
{ {
return ALIGN(sizeof(struct fileIdentDesc) + return ALIGN(sizeof(struct fileIdentDesc) +
le16_to_cpu(cfi->lengthOfImpUse) + cfi->lengthFileIdent, le16_to_cpu(cfi->lengthOfImpUse) + cfi->lengthFileIdent,
UDF_NAME_PAD); UDF_NAME_PAD);
} }
static inline uint8_t *udf_get_fi_ident(struct fileIdentDesc *fi)
{
return ((uint8_t *)(fi + 1)) + le16_to_cpu(fi->lengthOfImpUse);
}
/* file.c */ /* file.c */
extern long udf_ioctl(struct file *, unsigned int, unsigned long); extern long udf_ioctl(struct file *, unsigned int, unsigned long);
/* inode.c */ /* inode.c */
extern struct inode *__udf_iget(struct super_block *, struct kernel_lb_addr *, extern struct inode *__udf_iget(struct super_block *, struct kernel_lb_addr *,
bool hidden_inode); bool hidden_inode);
...@@ -151,16 +152,14 @@ static inline struct inode *udf_iget(struct super_block *sb, ...@@ -151,16 +152,14 @@ static inline struct inode *udf_iget(struct super_block *sb,
return __udf_iget(sb, ino, false); return __udf_iget(sb, ino, false);
} }
extern int udf_expand_file_adinicb(struct inode *); extern int udf_expand_file_adinicb(struct inode *);
extern struct buffer_head *udf_expand_dir_adinicb(struct inode *inode,
udf_pblk_t *block, int *err);
extern struct buffer_head *udf_bread(struct inode *inode, udf_pblk_t block, extern struct buffer_head *udf_bread(struct inode *inode, udf_pblk_t block,
int create, int *err); int create, int *err);
extern int udf_setsize(struct inode *, loff_t); extern int udf_setsize(struct inode *, loff_t);
extern void udf_evict_inode(struct inode *); extern void udf_evict_inode(struct inode *);
extern int udf_write_inode(struct inode *, struct writeback_control *wbc); extern int udf_write_inode(struct inode *, struct writeback_control *wbc);
extern udf_pblk_t udf_block_map(struct inode *inode, sector_t block);
extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *, extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *,
struct kernel_lb_addr *, uint32_t *, sector_t *); struct kernel_lb_addr *, uint32_t *, sector_t *);
int udf_get_block(struct inode *, sector_t, struct buffer_head *, int);
extern int udf_setup_indirect_aext(struct inode *inode, udf_pblk_t block, extern int udf_setup_indirect_aext(struct inode *inode, udf_pblk_t block,
struct extent_position *epos); struct extent_position *epos);
extern int __udf_add_aext(struct inode *inode, struct extent_position *epos, extern int __udf_add_aext(struct inode *inode, struct extent_position *epos,
...@@ -177,9 +176,6 @@ extern int8_t udf_current_aext(struct inode *, struct extent_position *, ...@@ -177,9 +176,6 @@ extern int8_t udf_current_aext(struct inode *, struct extent_position *,
extern void udf_update_extra_perms(struct inode *inode, umode_t mode); extern void udf_update_extra_perms(struct inode *inode, umode_t mode);
/* misc.c */ /* misc.c */
extern struct buffer_head *udf_tgetblk(struct super_block *sb,
udf_pblk_t block);
extern struct buffer_head *udf_tread(struct super_block *sb, udf_pblk_t block);
extern struct genericFormat *udf_add_extendedattr(struct inode *, uint32_t, extern struct genericFormat *udf_add_extendedattr(struct inode *, uint32_t,
uint32_t, uint8_t); uint32_t, uint8_t);
extern struct genericFormat *udf_get_extendedattr(struct inode *, uint32_t, extern struct genericFormat *udf_get_extendedattr(struct inode *, uint32_t,
...@@ -194,7 +190,7 @@ extern void udf_new_tag(char *, uint16_t, uint16_t, uint16_t, uint32_t, int); ...@@ -194,7 +190,7 @@ extern void udf_new_tag(char *, uint16_t, uint16_t, uint16_t, uint32_t, int);
/* lowlevel.c */ /* lowlevel.c */
extern unsigned int udf_get_last_session(struct super_block *); extern unsigned int udf_get_last_session(struct super_block *);
extern unsigned long udf_get_last_block(struct super_block *); udf_pblk_t udf_get_last_block(struct super_block *);
/* partition.c */ /* partition.c */
extern uint32_t udf_get_pblock(struct super_block *, uint32_t, uint16_t, extern uint32_t udf_get_pblock(struct super_block *, uint32_t, uint16_t,
...@@ -243,14 +239,13 @@ extern udf_pblk_t udf_new_block(struct super_block *sb, struct inode *inode, ...@@ -243,14 +239,13 @@ extern udf_pblk_t udf_new_block(struct super_block *sb, struct inode *inode,
uint16_t partition, uint32_t goal, int *err); uint16_t partition, uint32_t goal, int *err);
/* directory.c */ /* directory.c */
extern struct fileIdentDesc *udf_fileident_read(struct inode *, loff_t *, int udf_fiiter_init(struct udf_fileident_iter *iter, struct inode *dir,
struct udf_fileident_bh *, loff_t pos);
struct fileIdentDesc *, int udf_fiiter_advance(struct udf_fileident_iter *iter);
struct extent_position *, void udf_fiiter_release(struct udf_fileident_iter *iter);
struct kernel_lb_addr *, uint32_t *, void udf_fiiter_write_fi(struct udf_fileident_iter *iter, uint8_t *impuse);
sector_t *); void udf_fiiter_update_elen(struct udf_fileident_iter *iter, uint32_t new_elen);
extern struct fileIdentDesc *udf_get_fileident(void *buffer, int bufsize, int udf_fiiter_append_blk(struct udf_fileident_iter *iter);
int *offset);
extern struct long_ad *udf_get_filelongad(uint8_t *, int, uint32_t *, int); extern struct long_ad *udf_get_filelongad(uint8_t *, int, uint32_t *, int);
extern struct short_ad *udf_get_fileshortad(uint8_t *, int, uint32_t *, int); extern struct short_ad *udf_get_fileshortad(uint8_t *, int, uint32_t *, int);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment