mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 04:33:26 +02:00
Merge tag 'fs_for_v6.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
Pull misc filesystem updates from Jan Kara: - Rewrite kmap_local() handling in ext2 - Convert ext2 direct IO path to iomap (with some infrastructure tweaks associated with that) - Convert two boilerplate licenses in udf to SPDX identifiers - Other small udf, ext2, and quota fixes and cleanups * tag 'fs_for_v6.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs: udf: Fix uninitialized array access for some pathnames ext2: Drop fragment support quota: fix warning in dqgrab() quota: Properly disable quotas when add_dquot_ref() fails fs: udf: udftime: Replace LGPL boilerplate with SPDX identifier fs: udf: Replace GPL 2.0 boilerplate license notice with SPDX identifier fs: Drop wait_unfrozen wait queue ext2_find_entry()/ext2_dotdot(): callers don't need page_addr anymore ext2_{set_link,delete_entry}(): don't bother with page_addr ext2_put_page(): accept any pointer within the page ext2_get_page(): saner type ext2: use offset_in_page() instead of open-coding it as subtraction ext2_rename(): set_link and delete_entry may fail ext2: Add direct-io trace points ext2: Move direct-io to use iomap ext2: Use generic_buffers_fsync() implementation ext4: Use generic_buffers_fsync_noflush() implementation fs/buffer.c: Add generic_buffers_fsync*() implementation ext2/dax: Fix ext2_setsize when len is page aligned
This commit is contained in:
70
fs/buffer.c
70
fs/buffer.c
@@ -591,6 +591,76 @@ int sync_mapping_buffers(struct address_space *mapping)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(sync_mapping_buffers);
|
EXPORT_SYMBOL(sync_mapping_buffers);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* generic_buffers_fsync_noflush - generic buffer fsync implementation
|
||||||
|
* for simple filesystems with no inode lock
|
||||||
|
*
|
||||||
|
* @file: file to synchronize
|
||||||
|
* @start: start offset in bytes
|
||||||
|
* @end: end offset in bytes (inclusive)
|
||||||
|
* @datasync: only synchronize essential metadata if true
|
||||||
|
*
|
||||||
|
* This is a generic implementation of the fsync method for simple
|
||||||
|
* filesystems which track all non-inode metadata in the buffers list
|
||||||
|
* hanging off the address_space structure.
|
||||||
|
*/
|
||||||
|
int generic_buffers_fsync_noflush(struct file *file, loff_t start, loff_t end,
|
||||||
|
bool datasync)
|
||||||
|
{
|
||||||
|
struct inode *inode = file->f_mapping->host;
|
||||||
|
int err;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
err = file_write_and_wait_range(file, start, end);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
ret = sync_mapping_buffers(inode->i_mapping);
|
||||||
|
if (!(inode->i_state & I_DIRTY_ALL))
|
||||||
|
goto out;
|
||||||
|
if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
err = sync_inode_metadata(inode, 1);
|
||||||
|
if (ret == 0)
|
||||||
|
ret = err;
|
||||||
|
|
||||||
|
out:
|
||||||
|
/* check and advance again to catch errors after syncing out buffers */
|
||||||
|
err = file_check_and_advance_wb_err(file);
|
||||||
|
if (ret == 0)
|
||||||
|
ret = err;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(generic_buffers_fsync_noflush);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* generic_buffers_fsync - generic buffer fsync implementation
|
||||||
|
* for simple filesystems with no inode lock
|
||||||
|
*
|
||||||
|
* @file: file to synchronize
|
||||||
|
* @start: start offset in bytes
|
||||||
|
* @end: end offset in bytes (inclusive)
|
||||||
|
* @datasync: only synchronize essential metadata if true
|
||||||
|
*
|
||||||
|
* This is a generic implementation of the fsync method for simple
|
||||||
|
* filesystems which track all non-inode metadata in the buffers list
|
||||||
|
* hanging off the address_space structure. This also makes sure that
|
||||||
|
* a device cache flush operation is called at the end.
|
||||||
|
*/
|
||||||
|
int generic_buffers_fsync(struct file *file, loff_t start, loff_t end,
|
||||||
|
bool datasync)
|
||||||
|
{
|
||||||
|
struct inode *inode = file->f_mapping->host;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = generic_buffers_fsync_noflush(file, start, end, datasync);
|
||||||
|
if (!ret)
|
||||||
|
ret = blkdev_issue_flush(inode->i_sb->s_bdev);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(generic_buffers_fsync);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called when we've recently written block `bblock', and it is known that
|
* Called when we've recently written block `bblock', and it is known that
|
||||||
* `bblock' was for a buffer_boundary() buffer. This means that the block at
|
* `bblock' was for a buffer_boundary() buffer. This means that the block at
|
||||||
|
@@ -6,7 +6,10 @@
|
|||||||
obj-$(CONFIG_EXT2_FS) += ext2.o
|
obj-$(CONFIG_EXT2_FS) += ext2.o
|
||||||
|
|
||||||
ext2-y := balloc.o dir.o file.o ialloc.o inode.o \
|
ext2-y := balloc.o dir.o file.o ialloc.o inode.o \
|
||||||
ioctl.o namei.o super.o symlink.o
|
ioctl.o namei.o super.o symlink.o trace.o
|
||||||
|
|
||||||
|
# For tracepoints to include our trace.h from tracepoint infrastructure
|
||||||
|
CFLAGS_trace.o := -I$(src)
|
||||||
|
|
||||||
ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o
|
ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o
|
||||||
ext2-$(CONFIG_EXT2_FS_POSIX_ACL) += acl.o
|
ext2-$(CONFIG_EXT2_FS_POSIX_ACL) += acl.o
|
||||||
|
136
fs/ext2/dir.c
136
fs/ext2/dir.c
@@ -186,23 +186,25 @@ fail:
|
|||||||
* NOTE: ext2_find_entry() and ext2_dotdot() act as a call to ext2_get_page()
|
* NOTE: ext2_find_entry() and ext2_dotdot() act as a call to ext2_get_page()
|
||||||
* and should be treated as a call to ext2_get_page() for nesting purposes.
|
* and should be treated as a call to ext2_get_page() for nesting purposes.
|
||||||
*/
|
*/
|
||||||
static struct page * ext2_get_page(struct inode *dir, unsigned long n,
|
static void *ext2_get_page(struct inode *dir, unsigned long n,
|
||||||
int quiet, void **page_addr)
|
int quiet, struct page **page)
|
||||||
{
|
{
|
||||||
struct address_space *mapping = dir->i_mapping;
|
struct address_space *mapping = dir->i_mapping;
|
||||||
struct folio *folio = read_mapping_folio(mapping, n, NULL);
|
struct folio *folio = read_mapping_folio(mapping, n, NULL);
|
||||||
|
void *page_addr;
|
||||||
|
|
||||||
if (IS_ERR(folio))
|
if (IS_ERR(folio))
|
||||||
return &folio->page;
|
return ERR_CAST(folio);
|
||||||
*page_addr = kmap_local_folio(folio, n & (folio_nr_pages(folio) - 1));
|
page_addr = kmap_local_folio(folio, n & (folio_nr_pages(folio) - 1));
|
||||||
if (unlikely(!folio_test_checked(folio))) {
|
if (unlikely(!folio_test_checked(folio))) {
|
||||||
if (!ext2_check_page(&folio->page, quiet, *page_addr))
|
if (!ext2_check_page(&folio->page, quiet, page_addr))
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
return &folio->page;
|
*page = &folio->page;
|
||||||
|
return page_addr;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
ext2_put_page(&folio->page, *page_addr);
|
ext2_put_page(&folio->page, page_addr);
|
||||||
return ERR_PTR(-EIO);
|
return ERR_PTR(-EIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,7 +242,7 @@ ext2_validate_entry(char *base, unsigned offset, unsigned mask)
|
|||||||
break;
|
break;
|
||||||
p = ext2_next_entry(p);
|
p = ext2_next_entry(p);
|
||||||
}
|
}
|
||||||
return (char *)p - base;
|
return offset_in_page(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void ext2_set_de_type(ext2_dirent *de, struct inode *inode)
|
static inline void ext2_set_de_type(ext2_dirent *de, struct inode *inode)
|
||||||
@@ -271,16 +273,17 @@ ext2_readdir(struct file *file, struct dir_context *ctx)
|
|||||||
EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_FILETYPE);
|
EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_FILETYPE);
|
||||||
|
|
||||||
for ( ; n < npages; n++, offset = 0) {
|
for ( ; n < npages; n++, offset = 0) {
|
||||||
char *kaddr, *limit;
|
|
||||||
ext2_dirent *de;
|
ext2_dirent *de;
|
||||||
struct page *page = ext2_get_page(inode, n, 0, (void **)&kaddr);
|
struct page *page;
|
||||||
|
char *kaddr = ext2_get_page(inode, n, 0, &page);
|
||||||
|
char *limit;
|
||||||
|
|
||||||
if (IS_ERR(page)) {
|
if (IS_ERR(kaddr)) {
|
||||||
ext2_error(sb, __func__,
|
ext2_error(sb, __func__,
|
||||||
"bad page in #%lu",
|
"bad page in #%lu",
|
||||||
inode->i_ino);
|
inode->i_ino);
|
||||||
ctx->pos += PAGE_SIZE - offset;
|
ctx->pos += PAGE_SIZE - offset;
|
||||||
return PTR_ERR(page);
|
return PTR_ERR(kaddr);
|
||||||
}
|
}
|
||||||
if (unlikely(need_revalidate)) {
|
if (unlikely(need_revalidate)) {
|
||||||
if (offset) {
|
if (offset) {
|
||||||
@@ -296,7 +299,7 @@ ext2_readdir(struct file *file, struct dir_context *ctx)
|
|||||||
if (de->rec_len == 0) {
|
if (de->rec_len == 0) {
|
||||||
ext2_error(sb, __func__,
|
ext2_error(sb, __func__,
|
||||||
"zero-length directory entry");
|
"zero-length directory entry");
|
||||||
ext2_put_page(page, kaddr);
|
ext2_put_page(page, de);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
if (de->inode) {
|
if (de->inode) {
|
||||||
@@ -308,7 +311,7 @@ ext2_readdir(struct file *file, struct dir_context *ctx)
|
|||||||
if (!dir_emit(ctx, de->name, de->name_len,
|
if (!dir_emit(ctx, de->name, de->name_len,
|
||||||
le32_to_cpu(de->inode),
|
le32_to_cpu(de->inode),
|
||||||
d_type)) {
|
d_type)) {
|
||||||
ext2_put_page(page, kaddr);
|
ext2_put_page(page, de);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -336,8 +339,7 @@ ext2_readdir(struct file *file, struct dir_context *ctx)
|
|||||||
* should be treated as a call to ext2_get_page() for nesting purposes.
|
* should be treated as a call to ext2_get_page() for nesting purposes.
|
||||||
*/
|
*/
|
||||||
struct ext2_dir_entry_2 *ext2_find_entry (struct inode *dir,
|
struct ext2_dir_entry_2 *ext2_find_entry (struct inode *dir,
|
||||||
const struct qstr *child, struct page **res_page,
|
const struct qstr *child, struct page **res_page)
|
||||||
void **res_page_addr)
|
|
||||||
{
|
{
|
||||||
const char *name = child->name;
|
const char *name = child->name;
|
||||||
int namelen = child->len;
|
int namelen = child->len;
|
||||||
@@ -347,40 +349,36 @@ struct ext2_dir_entry_2 *ext2_find_entry (struct inode *dir,
|
|||||||
struct page *page = NULL;
|
struct page *page = NULL;
|
||||||
struct ext2_inode_info *ei = EXT2_I(dir);
|
struct ext2_inode_info *ei = EXT2_I(dir);
|
||||||
ext2_dirent * de;
|
ext2_dirent * de;
|
||||||
void *page_addr;
|
|
||||||
|
|
||||||
if (npages == 0)
|
if (npages == 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* OFFSET_CACHE */
|
/* OFFSET_CACHE */
|
||||||
*res_page = NULL;
|
*res_page = NULL;
|
||||||
*res_page_addr = NULL;
|
|
||||||
|
|
||||||
start = ei->i_dir_start_lookup;
|
start = ei->i_dir_start_lookup;
|
||||||
if (start >= npages)
|
if (start >= npages)
|
||||||
start = 0;
|
start = 0;
|
||||||
n = start;
|
n = start;
|
||||||
do {
|
do {
|
||||||
char *kaddr;
|
char *kaddr = ext2_get_page(dir, n, 0, &page);
|
||||||
page = ext2_get_page(dir, n, 0, &page_addr);
|
if (IS_ERR(kaddr))
|
||||||
if (IS_ERR(page))
|
return ERR_CAST(kaddr);
|
||||||
return ERR_CAST(page);
|
|
||||||
|
|
||||||
kaddr = page_addr;
|
|
||||||
de = (ext2_dirent *) kaddr;
|
de = (ext2_dirent *) kaddr;
|
||||||
kaddr += ext2_last_byte(dir, n) - reclen;
|
kaddr += ext2_last_byte(dir, n) - reclen;
|
||||||
while ((char *) de <= kaddr) {
|
while ((char *) de <= kaddr) {
|
||||||
if (de->rec_len == 0) {
|
if (de->rec_len == 0) {
|
||||||
ext2_error(dir->i_sb, __func__,
|
ext2_error(dir->i_sb, __func__,
|
||||||
"zero-length directory entry");
|
"zero-length directory entry");
|
||||||
ext2_put_page(page, page_addr);
|
ext2_put_page(page, de);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (ext2_match(namelen, name, de))
|
if (ext2_match(namelen, name, de))
|
||||||
goto found;
|
goto found;
|
||||||
de = ext2_next_entry(de);
|
de = ext2_next_entry(de);
|
||||||
}
|
}
|
||||||
ext2_put_page(page, page_addr);
|
ext2_put_page(page, kaddr);
|
||||||
|
|
||||||
if (++n >= npages)
|
if (++n >= npages)
|
||||||
n = 0;
|
n = 0;
|
||||||
@@ -398,7 +396,6 @@ out:
|
|||||||
|
|
||||||
found:
|
found:
|
||||||
*res_page = page;
|
*res_page = page;
|
||||||
*res_page_addr = page_addr;
|
|
||||||
ei->i_dir_start_lookup = n;
|
ei->i_dir_start_lookup = n;
|
||||||
return de;
|
return de;
|
||||||
}
|
}
|
||||||
@@ -415,33 +412,26 @@ found:
|
|||||||
* ext2_find_entry() and ext2_dotdot() act as a call to ext2_get_page() and
|
* ext2_find_entry() and ext2_dotdot() act as a call to ext2_get_page() and
|
||||||
* should be treated as a call to ext2_get_page() for nesting purposes.
|
* should be treated as a call to ext2_get_page() for nesting purposes.
|
||||||
*/
|
*/
|
||||||
struct ext2_dir_entry_2 *ext2_dotdot(struct inode *dir, struct page **p,
|
struct ext2_dir_entry_2 *ext2_dotdot(struct inode *dir, struct page **p)
|
||||||
void **pa)
|
|
||||||
{
|
{
|
||||||
void *page_addr;
|
ext2_dirent *de = ext2_get_page(dir, 0, 0, p);
|
||||||
struct page *page = ext2_get_page(dir, 0, 0, &page_addr);
|
|
||||||
ext2_dirent *de = NULL;
|
|
||||||
|
|
||||||
if (!IS_ERR(page)) {
|
if (!IS_ERR(de))
|
||||||
de = ext2_next_entry((ext2_dirent *) page_addr);
|
return ext2_next_entry(de);
|
||||||
*p = page;
|
return NULL;
|
||||||
*pa = page_addr;
|
|
||||||
}
|
|
||||||
return de;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ext2_inode_by_name(struct inode *dir, const struct qstr *child, ino_t *ino)
|
int ext2_inode_by_name(struct inode *dir, const struct qstr *child, ino_t *ino)
|
||||||
{
|
{
|
||||||
struct ext2_dir_entry_2 *de;
|
struct ext2_dir_entry_2 *de;
|
||||||
struct page *page;
|
struct page *page;
|
||||||
void *page_addr;
|
|
||||||
|
|
||||||
de = ext2_find_entry(dir, child, &page, &page_addr);
|
de = ext2_find_entry(dir, child, &page);
|
||||||
if (IS_ERR(de))
|
if (IS_ERR(de))
|
||||||
return PTR_ERR(de);
|
return PTR_ERR(de);
|
||||||
|
|
||||||
*ino = le32_to_cpu(de->inode);
|
*ino = le32_to_cpu(de->inode);
|
||||||
ext2_put_page(page, page_addr);
|
ext2_put_page(page, de);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -462,11 +452,9 @@ static int ext2_handle_dirsync(struct inode *dir)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int 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, struct inode *inode, bool update_times)
|
||||||
bool update_times)
|
|
||||||
{
|
{
|
||||||
loff_t pos = page_offset(page) +
|
loff_t pos = page_offset(page) + offset_in_page(de);
|
||||||
(char *) de - (char *) page_addr;
|
|
||||||
unsigned len = ext2_rec_len_from_disk(de->rec_len);
|
unsigned len = ext2_rec_len_from_disk(de->rec_len);
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
@@ -498,7 +486,6 @@ int ext2_add_link (struct dentry *dentry, struct inode *inode)
|
|||||||
unsigned reclen = EXT2_DIR_REC_LEN(namelen);
|
unsigned reclen = EXT2_DIR_REC_LEN(namelen);
|
||||||
unsigned short rec_len, name_len;
|
unsigned short rec_len, name_len;
|
||||||
struct page *page = NULL;
|
struct page *page = NULL;
|
||||||
void *page_addr = NULL;
|
|
||||||
ext2_dirent * de;
|
ext2_dirent * de;
|
||||||
unsigned long npages = dir_pages(dir);
|
unsigned long npages = dir_pages(dir);
|
||||||
unsigned long n;
|
unsigned long n;
|
||||||
@@ -511,15 +498,12 @@ int ext2_add_link (struct dentry *dentry, struct inode *inode)
|
|||||||
* to protect that region.
|
* to protect that region.
|
||||||
*/
|
*/
|
||||||
for (n = 0; n <= npages; n++) {
|
for (n = 0; n <= npages; n++) {
|
||||||
char *kaddr;
|
char *kaddr = ext2_get_page(dir, n, 0, &page);
|
||||||
char *dir_end;
|
char *dir_end;
|
||||||
|
|
||||||
page = ext2_get_page(dir, n, 0, &page_addr);
|
if (IS_ERR(kaddr))
|
||||||
err = PTR_ERR(page);
|
return PTR_ERR(kaddr);
|
||||||
if (IS_ERR(page))
|
|
||||||
goto out;
|
|
||||||
lock_page(page);
|
lock_page(page);
|
||||||
kaddr = page_addr;
|
|
||||||
dir_end = kaddr + ext2_last_byte(dir, n);
|
dir_end = kaddr + ext2_last_byte(dir, n);
|
||||||
de = (ext2_dirent *)kaddr;
|
de = (ext2_dirent *)kaddr;
|
||||||
kaddr += PAGE_SIZE - reclen;
|
kaddr += PAGE_SIZE - reclen;
|
||||||
@@ -550,14 +534,13 @@ int ext2_add_link (struct dentry *dentry, struct inode *inode)
|
|||||||
de = (ext2_dirent *) ((char *) de + rec_len);
|
de = (ext2_dirent *) ((char *) de + rec_len);
|
||||||
}
|
}
|
||||||
unlock_page(page);
|
unlock_page(page);
|
||||||
ext2_put_page(page, page_addr);
|
ext2_put_page(page, kaddr);
|
||||||
}
|
}
|
||||||
BUG();
|
BUG();
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
got_it:
|
got_it:
|
||||||
pos = page_offset(page) +
|
pos = page_offset(page) + offset_in_page(de);
|
||||||
(char *)de - (char *)page_addr;
|
|
||||||
err = ext2_prepare_chunk(page, pos, rec_len);
|
err = ext2_prepare_chunk(page, pos, rec_len);
|
||||||
if (err)
|
if (err)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
@@ -578,8 +561,7 @@ got_it:
|
|||||||
err = ext2_handle_dirsync(dir);
|
err = ext2_handle_dirsync(dir);
|
||||||
/* OFFSET_CACHE */
|
/* OFFSET_CACHE */
|
||||||
out_put:
|
out_put:
|
||||||
ext2_put_page(page, page_addr);
|
ext2_put_page(page, de);
|
||||||
out:
|
|
||||||
return err;
|
return err;
|
||||||
out_unlock:
|
out_unlock:
|
||||||
unlock_page(page);
|
unlock_page(page);
|
||||||
@@ -590,34 +572,36 @@ out_unlock:
|
|||||||
* ext2_delete_entry deletes a directory entry by merging it with the
|
* ext2_delete_entry deletes a directory entry by merging it with the
|
||||||
* previous entry. Page is up-to-date.
|
* previous entry. Page is up-to-date.
|
||||||
*/
|
*/
|
||||||
int ext2_delete_entry (struct ext2_dir_entry_2 *dir, struct page *page,
|
int ext2_delete_entry(struct ext2_dir_entry_2 *dir, struct page *page)
|
||||||
char *kaddr)
|
|
||||||
{
|
{
|
||||||
struct inode *inode = page->mapping->host;
|
struct inode *inode = page->mapping->host;
|
||||||
unsigned from = ((char*)dir - kaddr) & ~(ext2_chunk_size(inode)-1);
|
char *kaddr = (char *)((unsigned long)dir & PAGE_MASK);
|
||||||
unsigned to = ((char *)dir - kaddr) +
|
unsigned from = offset_in_page(dir) & ~(ext2_chunk_size(inode)-1);
|
||||||
|
unsigned to = offset_in_page(dir) +
|
||||||
ext2_rec_len_from_disk(dir->rec_len);
|
ext2_rec_len_from_disk(dir->rec_len);
|
||||||
loff_t pos;
|
loff_t pos;
|
||||||
ext2_dirent * pde = NULL;
|
ext2_dirent *pde = NULL;
|
||||||
ext2_dirent * de = (ext2_dirent *) (kaddr + from);
|
ext2_dirent *de = (ext2_dirent *)(kaddr + from);
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
while ((char*)de < (char*)dir) {
|
while ((char*)de < (char*)dir) {
|
||||||
if (de->rec_len == 0) {
|
if (de->rec_len == 0) {
|
||||||
ext2_error(inode->i_sb, __func__,
|
ext2_error(inode->i_sb, __func__,
|
||||||
"zero-length directory entry");
|
"zero-length directory entry");
|
||||||
err = -EIO;
|
return -EIO;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
pde = de;
|
pde = de;
|
||||||
de = ext2_next_entry(de);
|
de = ext2_next_entry(de);
|
||||||
}
|
}
|
||||||
if (pde)
|
if (pde)
|
||||||
from = (char *)pde - kaddr;
|
from = offset_in_page(pde);
|
||||||
pos = page_offset(page) + from;
|
pos = page_offset(page) + from;
|
||||||
lock_page(page);
|
lock_page(page);
|
||||||
err = ext2_prepare_chunk(page, pos, to - from);
|
err = ext2_prepare_chunk(page, pos, to - from);
|
||||||
BUG_ON(err);
|
if (err) {
|
||||||
|
unlock_page(page);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
if (pde)
|
if (pde)
|
||||||
pde->rec_len = ext2_rec_len_to_disk(to - from);
|
pde->rec_len = ext2_rec_len_to_disk(to - from);
|
||||||
dir->inode = 0;
|
dir->inode = 0;
|
||||||
@@ -625,9 +609,7 @@ int ext2_delete_entry (struct ext2_dir_entry_2 *dir, struct page *page,
|
|||||||
inode->i_ctime = inode->i_mtime = current_time(inode);
|
inode->i_ctime = inode->i_mtime = current_time(inode);
|
||||||
EXT2_I(inode)->i_flags &= ~EXT2_BTREE_FL;
|
EXT2_I(inode)->i_flags &= ~EXT2_BTREE_FL;
|
||||||
mark_inode_dirty(inode);
|
mark_inode_dirty(inode);
|
||||||
err = ext2_handle_dirsync(inode);
|
return ext2_handle_dirsync(inode);
|
||||||
out:
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -677,19 +659,17 @@ fail:
|
|||||||
*/
|
*/
|
||||||
int ext2_empty_dir (struct inode * inode)
|
int ext2_empty_dir (struct inode * inode)
|
||||||
{
|
{
|
||||||
void *page_addr = NULL;
|
struct page *page;
|
||||||
struct page *page = NULL;
|
char *kaddr;
|
||||||
unsigned long i, npages = dir_pages(inode);
|
unsigned long i, npages = dir_pages(inode);
|
||||||
|
|
||||||
for (i = 0; i < npages; i++) {
|
for (i = 0; i < npages; i++) {
|
||||||
char *kaddr;
|
ext2_dirent *de;
|
||||||
ext2_dirent * de;
|
|
||||||
page = ext2_get_page(inode, i, 0, &page_addr);
|
|
||||||
|
|
||||||
if (IS_ERR(page))
|
kaddr = ext2_get_page(inode, i, 0, &page);
|
||||||
|
if (IS_ERR(kaddr))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
kaddr = page_addr;
|
|
||||||
de = (ext2_dirent *)kaddr;
|
de = (ext2_dirent *)kaddr;
|
||||||
kaddr += ext2_last_byte(inode, i) - EXT2_DIR_REC_LEN(1);
|
kaddr += ext2_last_byte(inode, i) - EXT2_DIR_REC_LEN(1);
|
||||||
|
|
||||||
@@ -715,12 +695,12 @@ int ext2_empty_dir (struct inode * inode)
|
|||||||
}
|
}
|
||||||
de = ext2_next_entry(de);
|
de = ext2_next_entry(de);
|
||||||
}
|
}
|
||||||
ext2_put_page(page, page_addr);
|
ext2_put_page(page, kaddr);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
not_empty:
|
not_empty:
|
||||||
ext2_put_page(page, page_addr);
|
ext2_put_page(page, kaddr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -70,10 +70,7 @@ struct mb_cache;
|
|||||||
* second extended-fs super-block data in memory
|
* second extended-fs super-block data in memory
|
||||||
*/
|
*/
|
||||||
struct ext2_sb_info {
|
struct ext2_sb_info {
|
||||||
unsigned long s_frag_size; /* Size of a fragment in bytes */
|
|
||||||
unsigned long s_frags_per_block;/* Number of fragments per block */
|
|
||||||
unsigned long s_inodes_per_block;/* Number of inodes per block */
|
unsigned long s_inodes_per_block;/* Number of inodes per block */
|
||||||
unsigned long s_frags_per_group;/* Number of fragments in a group */
|
|
||||||
unsigned long s_blocks_per_group;/* Number of blocks in a group */
|
unsigned long s_blocks_per_group;/* Number of blocks in a group */
|
||||||
unsigned long s_inodes_per_group;/* Number of inodes in a group */
|
unsigned long s_inodes_per_group;/* Number of inodes in a group */
|
||||||
unsigned long s_itb_per_group; /* Number of inode table blocks per group */
|
unsigned long s_itb_per_group; /* Number of inode table blocks per group */
|
||||||
@@ -188,15 +185,6 @@ static inline struct ext2_sb_info *EXT2_SB(struct super_block *sb)
|
|||||||
#define EXT2_INODE_SIZE(s) (EXT2_SB(s)->s_inode_size)
|
#define EXT2_INODE_SIZE(s) (EXT2_SB(s)->s_inode_size)
|
||||||
#define EXT2_FIRST_INO(s) (EXT2_SB(s)->s_first_ino)
|
#define EXT2_FIRST_INO(s) (EXT2_SB(s)->s_first_ino)
|
||||||
|
|
||||||
/*
|
|
||||||
* Macro-instructions used to manage fragments
|
|
||||||
*/
|
|
||||||
#define EXT2_MIN_FRAG_SIZE 1024
|
|
||||||
#define EXT2_MAX_FRAG_SIZE 4096
|
|
||||||
#define EXT2_MIN_FRAG_LOG_SIZE 10
|
|
||||||
#define EXT2_FRAG_SIZE(s) (EXT2_SB(s)->s_frag_size)
|
|
||||||
#define EXT2_FRAGS_PER_BLOCK(s) (EXT2_SB(s)->s_frags_per_block)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Structure of a blocks group descriptor
|
* Structure of a blocks group descriptor
|
||||||
*/
|
*/
|
||||||
@@ -730,14 +718,12 @@ extern int ext2_inode_by_name(struct inode *dir,
|
|||||||
const struct qstr *child, ino_t *ino);
|
const struct qstr *child, ino_t *ino);
|
||||||
extern int ext2_make_empty(struct inode *, struct inode *);
|
extern int ext2_make_empty(struct inode *, struct inode *);
|
||||||
extern struct ext2_dir_entry_2 *ext2_find_entry(struct inode *, const struct qstr *,
|
extern struct ext2_dir_entry_2 *ext2_find_entry(struct inode *, const struct qstr *,
|
||||||
struct page **, void **res_page_addr);
|
struct page **);
|
||||||
extern int ext2_delete_entry(struct ext2_dir_entry_2 *dir, struct page *page,
|
extern int ext2_delete_entry(struct ext2_dir_entry_2 *dir, struct page *page);
|
||||||
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);
|
||||||
int 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, struct inode *inode, bool update_times);
|
||||||
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);
|
||||||
@@ -754,6 +740,7 @@ extern unsigned long ext2_count_free (struct buffer_head *, unsigned);
|
|||||||
extern struct inode *ext2_iget (struct super_block *, unsigned long);
|
extern struct inode *ext2_iget (struct super_block *, unsigned long);
|
||||||
extern int ext2_write_inode (struct inode *, struct writeback_control *);
|
extern int ext2_write_inode (struct inode *, struct writeback_control *);
|
||||||
extern void ext2_evict_inode(struct inode *);
|
extern void ext2_evict_inode(struct inode *);
|
||||||
|
void ext2_write_failed(struct address_space *mapping, loff_t to);
|
||||||
extern int ext2_get_block(struct inode *, sector_t, struct buffer_head *, int);
|
extern int ext2_get_block(struct inode *, sector_t, struct buffer_head *, int);
|
||||||
extern int ext2_setattr (struct mnt_idmap *, struct dentry *, struct iattr *);
|
extern int ext2_setattr (struct mnt_idmap *, struct dentry *, struct iattr *);
|
||||||
extern int ext2_getattr (struct mnt_idmap *, const struct path *,
|
extern int ext2_getattr (struct mnt_idmap *, const struct path *,
|
||||||
|
126
fs/ext2/file.c
126
fs/ext2/file.c
@@ -25,9 +25,11 @@
|
|||||||
#include <linux/quotaops.h>
|
#include <linux/quotaops.h>
|
||||||
#include <linux/iomap.h>
|
#include <linux/iomap.h>
|
||||||
#include <linux/uio.h>
|
#include <linux/uio.h>
|
||||||
|
#include <linux/buffer_head.h>
|
||||||
#include "ext2.h"
|
#include "ext2.h"
|
||||||
#include "xattr.h"
|
#include "xattr.h"
|
||||||
#include "acl.h"
|
#include "acl.h"
|
||||||
|
#include "trace.h"
|
||||||
|
|
||||||
#ifdef CONFIG_FS_DAX
|
#ifdef CONFIG_FS_DAX
|
||||||
static ssize_t ext2_dax_read_iter(struct kiocb *iocb, struct iov_iter *to)
|
static ssize_t ext2_dax_read_iter(struct kiocb *iocb, struct iov_iter *to)
|
||||||
@@ -153,7 +155,7 @@ int ext2_fsync(struct file *file, loff_t start, loff_t end, int datasync)
|
|||||||
int ret;
|
int ret;
|
||||||
struct super_block *sb = file->f_mapping->host->i_sb;
|
struct super_block *sb = file->f_mapping->host->i_sb;
|
||||||
|
|
||||||
ret = generic_file_fsync(file, start, end, datasync);
|
ret = generic_buffers_fsync(file, start, end, datasync);
|
||||||
if (ret == -EIO)
|
if (ret == -EIO)
|
||||||
/* We don't really know where the IO error happened... */
|
/* We don't really know where the IO error happened... */
|
||||||
ext2_error(sb, __func__,
|
ext2_error(sb, __func__,
|
||||||
@@ -161,12 +163,131 @@ int ext2_fsync(struct file *file, loff_t start, loff_t end, int datasync)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t ext2_dio_read_iter(struct kiocb *iocb, struct iov_iter *to)
|
||||||
|
{
|
||||||
|
struct file *file = iocb->ki_filp;
|
||||||
|
struct inode *inode = file->f_mapping->host;
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
|
trace_ext2_dio_read_begin(iocb, to, 0);
|
||||||
|
inode_lock_shared(inode);
|
||||||
|
ret = iomap_dio_rw(iocb, to, &ext2_iomap_ops, NULL, 0, NULL, 0);
|
||||||
|
inode_unlock_shared(inode);
|
||||||
|
trace_ext2_dio_read_end(iocb, to, ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ext2_dio_write_end_io(struct kiocb *iocb, ssize_t size,
|
||||||
|
int error, unsigned int flags)
|
||||||
|
{
|
||||||
|
loff_t pos = iocb->ki_pos;
|
||||||
|
struct inode *inode = file_inode(iocb->ki_filp);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we are extending the file, we have to update i_size here before
|
||||||
|
* page cache gets invalidated in iomap_dio_rw(). This prevents racing
|
||||||
|
* buffered reads from zeroing out too much from page cache pages.
|
||||||
|
* Note that all extending writes always happens synchronously with
|
||||||
|
* inode lock held by ext2_dio_write_iter(). So it is safe to update
|
||||||
|
* inode size here for extending file writes.
|
||||||
|
*/
|
||||||
|
pos += size;
|
||||||
|
if (pos > i_size_read(inode)) {
|
||||||
|
i_size_write(inode, pos);
|
||||||
|
mark_inode_dirty(inode);
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
trace_ext2_dio_write_endio(iocb, size, error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct iomap_dio_ops ext2_dio_write_ops = {
|
||||||
|
.end_io = ext2_dio_write_end_io,
|
||||||
|
};
|
||||||
|
|
||||||
|
static ssize_t ext2_dio_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||||
|
{
|
||||||
|
struct file *file = iocb->ki_filp;
|
||||||
|
struct inode *inode = file->f_mapping->host;
|
||||||
|
ssize_t ret;
|
||||||
|
unsigned int flags = 0;
|
||||||
|
unsigned long blocksize = inode->i_sb->s_blocksize;
|
||||||
|
loff_t offset = iocb->ki_pos;
|
||||||
|
loff_t count = iov_iter_count(from);
|
||||||
|
ssize_t status = 0;
|
||||||
|
|
||||||
|
trace_ext2_dio_write_begin(iocb, from, 0);
|
||||||
|
inode_lock(inode);
|
||||||
|
ret = generic_write_checks(iocb, from);
|
||||||
|
if (ret <= 0)
|
||||||
|
goto out_unlock;
|
||||||
|
|
||||||
|
ret = kiocb_modified(iocb);
|
||||||
|
if (ret)
|
||||||
|
goto out_unlock;
|
||||||
|
|
||||||
|
/* use IOMAP_DIO_FORCE_WAIT for unaligned or extending writes */
|
||||||
|
if (iocb->ki_pos + iov_iter_count(from) > i_size_read(inode) ||
|
||||||
|
(!IS_ALIGNED(iocb->ki_pos | iov_iter_alignment(from), blocksize)))
|
||||||
|
flags |= IOMAP_DIO_FORCE_WAIT;
|
||||||
|
|
||||||
|
ret = iomap_dio_rw(iocb, from, &ext2_iomap_ops, &ext2_dio_write_ops,
|
||||||
|
flags, NULL, 0);
|
||||||
|
|
||||||
|
/* ENOTBLK is magic return value for fallback to buffered-io */
|
||||||
|
if (ret == -ENOTBLK)
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
if (ret < 0 && ret != -EIOCBQUEUED)
|
||||||
|
ext2_write_failed(inode->i_mapping, offset + count);
|
||||||
|
|
||||||
|
/* handle case for partial write and for fallback to buffered write */
|
||||||
|
if (ret >= 0 && iov_iter_count(from)) {
|
||||||
|
loff_t pos, endbyte;
|
||||||
|
int ret2;
|
||||||
|
|
||||||
|
iocb->ki_flags &= ~IOCB_DIRECT;
|
||||||
|
pos = iocb->ki_pos;
|
||||||
|
status = generic_perform_write(iocb, from);
|
||||||
|
if (unlikely(status < 0)) {
|
||||||
|
ret = status;
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
iocb->ki_pos += status;
|
||||||
|
ret += status;
|
||||||
|
endbyte = pos + status - 1;
|
||||||
|
ret2 = filemap_write_and_wait_range(inode->i_mapping, pos,
|
||||||
|
endbyte);
|
||||||
|
if (!ret2)
|
||||||
|
invalidate_mapping_pages(inode->i_mapping,
|
||||||
|
pos >> PAGE_SHIFT,
|
||||||
|
endbyte >> PAGE_SHIFT);
|
||||||
|
if (ret > 0)
|
||||||
|
generic_write_sync(iocb, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
out_unlock:
|
||||||
|
inode_unlock(inode);
|
||||||
|
if (status)
|
||||||
|
trace_ext2_dio_write_buff_end(iocb, from, status);
|
||||||
|
trace_ext2_dio_write_end(iocb, from, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t ext2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
|
static ssize_t ext2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_FS_DAX
|
#ifdef CONFIG_FS_DAX
|
||||||
if (IS_DAX(iocb->ki_filp->f_mapping->host))
|
if (IS_DAX(iocb->ki_filp->f_mapping->host))
|
||||||
return ext2_dax_read_iter(iocb, to);
|
return ext2_dax_read_iter(iocb, to);
|
||||||
#endif
|
#endif
|
||||||
|
if (iocb->ki_flags & IOCB_DIRECT)
|
||||||
|
return ext2_dio_read_iter(iocb, to);
|
||||||
|
|
||||||
return generic_file_read_iter(iocb, to);
|
return generic_file_read_iter(iocb, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,6 +297,9 @@ static ssize_t ext2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
|||||||
if (IS_DAX(iocb->ki_filp->f_mapping->host))
|
if (IS_DAX(iocb->ki_filp->f_mapping->host))
|
||||||
return ext2_dax_write_iter(iocb, from);
|
return ext2_dax_write_iter(iocb, from);
|
||||||
#endif
|
#endif
|
||||||
|
if (iocb->ki_flags & IOCB_DIRECT)
|
||||||
|
return ext2_dio_write_iter(iocb, from);
|
||||||
|
|
||||||
return generic_file_write_iter(iocb, from);
|
return generic_file_write_iter(iocb, from);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -56,7 +56,7 @@ static inline int ext2_inode_is_fast_symlink(struct inode *inode)
|
|||||||
|
|
||||||
static void ext2_truncate_blocks(struct inode *inode, loff_t offset);
|
static void ext2_truncate_blocks(struct inode *inode, loff_t offset);
|
||||||
|
|
||||||
static void ext2_write_failed(struct address_space *mapping, loff_t to)
|
void ext2_write_failed(struct address_space *mapping, loff_t to)
|
||||||
{
|
{
|
||||||
struct inode *inode = mapping->host;
|
struct inode *inode = mapping->host;
|
||||||
|
|
||||||
@@ -809,9 +809,27 @@ static int ext2_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
|
|||||||
bool new = false, boundary = false;
|
bool new = false, boundary = false;
|
||||||
u32 bno;
|
u32 bno;
|
||||||
int ret;
|
int ret;
|
||||||
|
bool create = flags & IOMAP_WRITE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For writes that could fill holes inside i_size on a
|
||||||
|
* DIO_SKIP_HOLES filesystem we forbid block creations: only
|
||||||
|
* overwrites are permitted.
|
||||||
|
*/
|
||||||
|
if ((flags & IOMAP_DIRECT) &&
|
||||||
|
(first_block << blkbits) < i_size_read(inode))
|
||||||
|
create = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Writes that span EOF might trigger an IO size update on completion,
|
||||||
|
* so consider them to be dirty for the purposes of O_DSYNC even if
|
||||||
|
* there is no other metadata changes pending or have been made here.
|
||||||
|
*/
|
||||||
|
if ((flags & IOMAP_WRITE) && offset + length > i_size_read(inode))
|
||||||
|
iomap->flags |= IOMAP_F_DIRTY;
|
||||||
|
|
||||||
ret = ext2_get_blocks(inode, first_block, max_blocks,
|
ret = ext2_get_blocks(inode, first_block, max_blocks,
|
||||||
&bno, &new, &boundary, flags & IOMAP_WRITE);
|
&bno, &new, &boundary, create);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -823,6 +841,12 @@ static int ext2_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
|
|||||||
iomap->bdev = inode->i_sb->s_bdev;
|
iomap->bdev = inode->i_sb->s_bdev;
|
||||||
|
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
|
/*
|
||||||
|
* Switch to buffered-io for writing to holes in a non-extent
|
||||||
|
* based filesystem to avoid stale data exposure problem.
|
||||||
|
*/
|
||||||
|
if (!create && (flags & IOMAP_WRITE) && (flags & IOMAP_DIRECT))
|
||||||
|
return -ENOTBLK;
|
||||||
iomap->type = IOMAP_HOLE;
|
iomap->type = IOMAP_HOLE;
|
||||||
iomap->addr = IOMAP_NULL_ADDR;
|
iomap->addr = IOMAP_NULL_ADDR;
|
||||||
iomap->length = 1 << blkbits;
|
iomap->length = 1 << blkbits;
|
||||||
@@ -844,6 +868,13 @@ static int
|
|||||||
ext2_iomap_end(struct inode *inode, loff_t offset, loff_t length,
|
ext2_iomap_end(struct inode *inode, loff_t offset, loff_t length,
|
||||||
ssize_t written, unsigned flags, struct iomap *iomap)
|
ssize_t written, unsigned flags, struct iomap *iomap)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* Switch to buffered-io in case of any error.
|
||||||
|
* Blocks allocated can be used by the buffered-io path.
|
||||||
|
*/
|
||||||
|
if ((flags & IOMAP_DIRECT) && (flags & IOMAP_WRITE) && written == 0)
|
||||||
|
return -ENOTBLK;
|
||||||
|
|
||||||
if (iomap->type == IOMAP_MAPPED &&
|
if (iomap->type == IOMAP_MAPPED &&
|
||||||
written < length &&
|
written < length &&
|
||||||
(flags & IOMAP_WRITE))
|
(flags & IOMAP_WRITE))
|
||||||
@@ -908,22 +939,6 @@ static sector_t ext2_bmap(struct address_space *mapping, sector_t block)
|
|||||||
return generic_block_bmap(mapping,block,ext2_get_block);
|
return generic_block_bmap(mapping,block,ext2_get_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t
|
|
||||||
ext2_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
|
|
||||||
{
|
|
||||||
struct file *file = iocb->ki_filp;
|
|
||||||
struct address_space *mapping = file->f_mapping;
|
|
||||||
struct inode *inode = mapping->host;
|
|
||||||
size_t count = iov_iter_count(iter);
|
|
||||||
loff_t offset = iocb->ki_pos;
|
|
||||||
ssize_t ret;
|
|
||||||
|
|
||||||
ret = blockdev_direct_IO(iocb, inode, iter, ext2_get_block);
|
|
||||||
if (ret < 0 && iov_iter_rw(iter) == WRITE)
|
|
||||||
ext2_write_failed(mapping, offset + count);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ext2_writepages(struct address_space *mapping, struct writeback_control *wbc)
|
ext2_writepages(struct address_space *mapping, struct writeback_control *wbc)
|
||||||
{
|
{
|
||||||
@@ -946,7 +961,7 @@ const struct address_space_operations ext2_aops = {
|
|||||||
.write_begin = ext2_write_begin,
|
.write_begin = ext2_write_begin,
|
||||||
.write_end = ext2_write_end,
|
.write_end = ext2_write_end,
|
||||||
.bmap = ext2_bmap,
|
.bmap = ext2_bmap,
|
||||||
.direct_IO = ext2_direct_IO,
|
.direct_IO = noop_direct_IO,
|
||||||
.writepages = ext2_writepages,
|
.writepages = ext2_writepages,
|
||||||
.migrate_folio = buffer_migrate_folio,
|
.migrate_folio = buffer_migrate_folio,
|
||||||
.is_partially_uptodate = block_is_partially_uptodate,
|
.is_partially_uptodate = block_is_partially_uptodate,
|
||||||
@@ -1259,9 +1274,8 @@ static int ext2_setsize(struct inode *inode, loff_t newsize)
|
|||||||
inode_dio_wait(inode);
|
inode_dio_wait(inode);
|
||||||
|
|
||||||
if (IS_DAX(inode))
|
if (IS_DAX(inode))
|
||||||
error = dax_zero_range(inode, newsize,
|
error = dax_truncate_page(inode, newsize, NULL,
|
||||||
PAGE_ALIGN(newsize) - newsize, NULL,
|
&ext2_iomap_ops);
|
||||||
&ext2_iomap_ops);
|
|
||||||
else
|
else
|
||||||
error = block_truncate_page(inode->i_mapping,
|
error = block_truncate_page(inode->i_mapping,
|
||||||
newsize, ext2_get_block);
|
newsize, ext2_get_block);
|
||||||
|
@@ -269,26 +269,25 @@ out_dir:
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ext2_unlink(struct inode * dir, struct dentry *dentry)
|
static int ext2_unlink(struct inode *dir, struct dentry *dentry)
|
||||||
{
|
{
|
||||||
struct inode * inode = d_inode(dentry);
|
struct inode *inode = d_inode(dentry);
|
||||||
struct ext2_dir_entry_2 * de;
|
struct ext2_dir_entry_2 *de;
|
||||||
struct page * page;
|
struct page *page;
|
||||||
void *page_addr;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = dquot_initialize(dir);
|
err = dquot_initialize(dir);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
de = ext2_find_entry(dir, &dentry->d_name, &page, &page_addr);
|
de = ext2_find_entry(dir, &dentry->d_name, &page);
|
||||||
if (IS_ERR(de)) {
|
if (IS_ERR(de)) {
|
||||||
err = PTR_ERR(de);
|
err = PTR_ERR(de);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ext2_delete_entry (de, page, page_addr);
|
err = ext2_delete_entry(de, page);
|
||||||
ext2_put_page(page, page_addr);
|
ext2_put_page(page, de);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@@ -323,10 +322,8 @@ static int ext2_rename (struct mnt_idmap * idmap,
|
|||||||
struct inode * old_inode = d_inode(old_dentry);
|
struct inode * old_inode = d_inode(old_dentry);
|
||||||
struct inode * new_inode = d_inode(new_dentry);
|
struct inode * new_inode = d_inode(new_dentry);
|
||||||
struct page * dir_page = NULL;
|
struct page * dir_page = NULL;
|
||||||
void *dir_page_addr;
|
|
||||||
struct ext2_dir_entry_2 * dir_de = NULL;
|
struct ext2_dir_entry_2 * dir_de = NULL;
|
||||||
struct page * old_page;
|
struct page * old_page;
|
||||||
void *old_page_addr;
|
|
||||||
struct ext2_dir_entry_2 * old_de;
|
struct ext2_dir_entry_2 * old_de;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
@@ -335,28 +332,24 @@ static int ext2_rename (struct mnt_idmap * idmap,
|
|||||||
|
|
||||||
err = dquot_initialize(old_dir);
|
err = dquot_initialize(old_dir);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
return err;
|
||||||
|
|
||||||
err = dquot_initialize(new_dir);
|
err = dquot_initialize(new_dir);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
return err;
|
||||||
|
|
||||||
old_de = ext2_find_entry(old_dir, &old_dentry->d_name, &old_page,
|
old_de = ext2_find_entry(old_dir, &old_dentry->d_name, &old_page);
|
||||||
&old_page_addr);
|
if (IS_ERR(old_de))
|
||||||
if (IS_ERR(old_de)) {
|
return PTR_ERR(old_de);
|
||||||
err = PTR_ERR(old_de);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (S_ISDIR(old_inode->i_mode)) {
|
if (S_ISDIR(old_inode->i_mode)) {
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
dir_de = ext2_dotdot(old_inode, &dir_page, &dir_page_addr);
|
dir_de = ext2_dotdot(old_inode, &dir_page);
|
||||||
if (!dir_de)
|
if (!dir_de)
|
||||||
goto out_old;
|
goto out_old;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new_inode) {
|
if (new_inode) {
|
||||||
void *page_addr;
|
|
||||||
struct page *new_page;
|
struct page *new_page;
|
||||||
struct ext2_dir_entry_2 *new_de;
|
struct ext2_dir_entry_2 *new_de;
|
||||||
|
|
||||||
@@ -365,14 +358,13 @@ static int ext2_rename (struct mnt_idmap * idmap,
|
|||||||
goto out_dir;
|
goto out_dir;
|
||||||
|
|
||||||
new_de = ext2_find_entry(new_dir, &new_dentry->d_name,
|
new_de = ext2_find_entry(new_dir, &new_dentry->d_name,
|
||||||
&new_page, &page_addr);
|
&new_page);
|
||||||
if (IS_ERR(new_de)) {
|
if (IS_ERR(new_de)) {
|
||||||
err = PTR_ERR(new_de);
|
err = PTR_ERR(new_de);
|
||||||
goto out_dir;
|
goto out_dir;
|
||||||
}
|
}
|
||||||
err = ext2_set_link(new_dir, new_de, new_page, page_addr,
|
err = ext2_set_link(new_dir, new_de, new_page, old_inode, true);
|
||||||
old_inode, true);
|
ext2_put_page(new_page, new_de);
|
||||||
ext2_put_page(new_page, page_addr);
|
|
||||||
if (err)
|
if (err)
|
||||||
goto out_dir;
|
goto out_dir;
|
||||||
new_inode->i_ctime = current_time(new_inode);
|
new_inode->i_ctime = current_time(new_inode);
|
||||||
@@ -394,27 +386,20 @@ static int ext2_rename (struct mnt_idmap * idmap,
|
|||||||
old_inode->i_ctime = current_time(old_inode);
|
old_inode->i_ctime = current_time(old_inode);
|
||||||
mark_inode_dirty(old_inode);
|
mark_inode_dirty(old_inode);
|
||||||
|
|
||||||
ext2_delete_entry(old_de, old_page, old_page_addr);
|
err = ext2_delete_entry(old_de, old_page);
|
||||||
|
if (!err && dir_de) {
|
||||||
if (dir_de) {
|
if (old_dir != new_dir)
|
||||||
if (old_dir != new_dir) {
|
|
||||||
err = ext2_set_link(old_inode, dir_de, dir_page,
|
err = ext2_set_link(old_inode, dir_de, dir_page,
|
||||||
dir_page_addr, new_dir, false);
|
new_dir, false);
|
||||||
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
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_de);
|
||||||
goto out_old;
|
out_old:
|
||||||
|
ext2_put_page(old_page, old_de);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct inode_operations ext2_dir_inode_operations = {
|
const struct inode_operations ext2_dir_inode_operations = {
|
||||||
|
@@ -668,10 +668,9 @@ static int ext2_setup_super (struct super_block * sb,
|
|||||||
es->s_max_mnt_count = cpu_to_le16(EXT2_DFL_MAX_MNT_COUNT);
|
es->s_max_mnt_count = cpu_to_le16(EXT2_DFL_MAX_MNT_COUNT);
|
||||||
le16_add_cpu(&es->s_mnt_count, 1);
|
le16_add_cpu(&es->s_mnt_count, 1);
|
||||||
if (test_opt (sb, DEBUG))
|
if (test_opt (sb, DEBUG))
|
||||||
ext2_msg(sb, KERN_INFO, "%s, %s, bs=%lu, fs=%lu, gc=%lu, "
|
ext2_msg(sb, KERN_INFO, "%s, %s, bs=%lu, gc=%lu, "
|
||||||
"bpg=%lu, ipg=%lu, mo=%04lx]",
|
"bpg=%lu, ipg=%lu, mo=%04lx]",
|
||||||
EXT2FS_VERSION, EXT2FS_DATE, sb->s_blocksize,
|
EXT2FS_VERSION, EXT2FS_DATE, sb->s_blocksize,
|
||||||
sbi->s_frag_size,
|
|
||||||
sbi->s_groups_count,
|
sbi->s_groups_count,
|
||||||
EXT2_BLOCKS_PER_GROUP(sb),
|
EXT2_BLOCKS_PER_GROUP(sb),
|
||||||
EXT2_INODES_PER_GROUP(sb),
|
EXT2_INODES_PER_GROUP(sb),
|
||||||
@@ -1012,14 +1011,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sbi->s_frag_size = EXT2_MIN_FRAG_SIZE <<
|
|
||||||
le32_to_cpu(es->s_log_frag_size);
|
|
||||||
if (sbi->s_frag_size == 0)
|
|
||||||
goto cantfind_ext2;
|
|
||||||
sbi->s_frags_per_block = sb->s_blocksize / sbi->s_frag_size;
|
|
||||||
|
|
||||||
sbi->s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group);
|
sbi->s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group);
|
||||||
sbi->s_frags_per_group = le32_to_cpu(es->s_frags_per_group);
|
|
||||||
sbi->s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group);
|
sbi->s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group);
|
||||||
|
|
||||||
sbi->s_inodes_per_block = sb->s_blocksize / EXT2_INODE_SIZE(sb);
|
sbi->s_inodes_per_block = sb->s_blocksize / EXT2_INODE_SIZE(sb);
|
||||||
@@ -1045,11 +1037,10 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
|
|||||||
goto failed_mount;
|
goto failed_mount;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sb->s_blocksize != sbi->s_frag_size) {
|
if (es->s_log_frag_size != es->s_log_block_size) {
|
||||||
ext2_msg(sb, KERN_ERR,
|
ext2_msg(sb, KERN_ERR,
|
||||||
"error: fragsize %lu != blocksize %lu"
|
"error: fragsize log %u != blocksize log %u",
|
||||||
"(not supported yet)",
|
le32_to_cpu(es->s_log_frag_size), sb->s_blocksize_bits);
|
||||||
sbi->s_frag_size, sb->s_blocksize);
|
|
||||||
goto failed_mount;
|
goto failed_mount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1066,12 +1057,6 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
|
|||||||
sbi->s_blocks_per_group, sbi->s_inodes_per_group + 3);
|
sbi->s_blocks_per_group, sbi->s_inodes_per_group + 3);
|
||||||
goto failed_mount;
|
goto failed_mount;
|
||||||
}
|
}
|
||||||
if (sbi->s_frags_per_group > sb->s_blocksize * 8) {
|
|
||||||
ext2_msg(sb, KERN_ERR,
|
|
||||||
"error: #fragments per group too big: %lu",
|
|
||||||
sbi->s_frags_per_group);
|
|
||||||
goto failed_mount;
|
|
||||||
}
|
|
||||||
if (sbi->s_inodes_per_group < sbi->s_inodes_per_block ||
|
if (sbi->s_inodes_per_group < sbi->s_inodes_per_block ||
|
||||||
sbi->s_inodes_per_group > sb->s_blocksize * 8) {
|
sbi->s_inodes_per_group > sb->s_blocksize * 8) {
|
||||||
ext2_msg(sb, KERN_ERR,
|
ext2_msg(sb, KERN_ERR,
|
||||||
|
6
fs/ext2/trace.c
Normal file
6
fs/ext2/trace.c
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
#include "ext2.h"
|
||||||
|
#include <linux/uio.h>
|
||||||
|
|
||||||
|
#define CREATE_TRACE_POINTS
|
||||||
|
#include "trace.h"
|
94
fs/ext2/trace.h
Normal file
94
fs/ext2/trace.h
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
#undef TRACE_SYSTEM
|
||||||
|
#define TRACE_SYSTEM ext2
|
||||||
|
|
||||||
|
#if !defined(_EXT2_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
|
||||||
|
#define _EXT2_TRACE_H
|
||||||
|
|
||||||
|
#include <linux/tracepoint.h>
|
||||||
|
|
||||||
|
DECLARE_EVENT_CLASS(ext2_dio_class,
|
||||||
|
TP_PROTO(struct kiocb *iocb, struct iov_iter *iter, ssize_t ret),
|
||||||
|
TP_ARGS(iocb, iter, ret),
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__field(dev_t, dev)
|
||||||
|
__field(ino_t, ino)
|
||||||
|
__field(loff_t, isize)
|
||||||
|
__field(loff_t, pos)
|
||||||
|
__field(size_t, count)
|
||||||
|
__field(int, ki_flags)
|
||||||
|
__field(bool, aio)
|
||||||
|
__field(ssize_t, ret)
|
||||||
|
),
|
||||||
|
TP_fast_assign(
|
||||||
|
__entry->dev = file_inode(iocb->ki_filp)->i_sb->s_dev;
|
||||||
|
__entry->ino = file_inode(iocb->ki_filp)->i_ino;
|
||||||
|
__entry->isize = file_inode(iocb->ki_filp)->i_size;
|
||||||
|
__entry->pos = iocb->ki_pos;
|
||||||
|
__entry->count = iov_iter_count(iter);
|
||||||
|
__entry->ki_flags = iocb->ki_flags;
|
||||||
|
__entry->aio = !is_sync_kiocb(iocb);
|
||||||
|
__entry->ret = ret;
|
||||||
|
),
|
||||||
|
TP_printk("dev %d:%d ino 0x%lx isize 0x%llx pos 0x%llx len %zu flags %s aio %d ret %zd",
|
||||||
|
MAJOR(__entry->dev), MINOR(__entry->dev),
|
||||||
|
__entry->ino,
|
||||||
|
__entry->isize,
|
||||||
|
__entry->pos,
|
||||||
|
__entry->count,
|
||||||
|
__print_flags(__entry->ki_flags, "|", TRACE_IOCB_STRINGS),
|
||||||
|
__entry->aio,
|
||||||
|
__entry->ret)
|
||||||
|
);
|
||||||
|
|
||||||
|
#define DEFINE_DIO_RW_EVENT(name) \
|
||||||
|
DEFINE_EVENT(ext2_dio_class, name, \
|
||||||
|
TP_PROTO(struct kiocb *iocb, struct iov_iter *iter, ssize_t ret), \
|
||||||
|
TP_ARGS(iocb, iter, ret))
|
||||||
|
DEFINE_DIO_RW_EVENT(ext2_dio_write_begin);
|
||||||
|
DEFINE_DIO_RW_EVENT(ext2_dio_write_end);
|
||||||
|
DEFINE_DIO_RW_EVENT(ext2_dio_write_buff_end);
|
||||||
|
DEFINE_DIO_RW_EVENT(ext2_dio_read_begin);
|
||||||
|
DEFINE_DIO_RW_EVENT(ext2_dio_read_end);
|
||||||
|
|
||||||
|
TRACE_EVENT(ext2_dio_write_endio,
|
||||||
|
TP_PROTO(struct kiocb *iocb, ssize_t size, int ret),
|
||||||
|
TP_ARGS(iocb, size, ret),
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__field(dev_t, dev)
|
||||||
|
__field(ino_t, ino)
|
||||||
|
__field(loff_t, isize)
|
||||||
|
__field(loff_t, pos)
|
||||||
|
__field(ssize_t, size)
|
||||||
|
__field(int, ki_flags)
|
||||||
|
__field(bool, aio)
|
||||||
|
__field(int, ret)
|
||||||
|
),
|
||||||
|
TP_fast_assign(
|
||||||
|
__entry->dev = file_inode(iocb->ki_filp)->i_sb->s_dev;
|
||||||
|
__entry->ino = file_inode(iocb->ki_filp)->i_ino;
|
||||||
|
__entry->isize = file_inode(iocb->ki_filp)->i_size;
|
||||||
|
__entry->pos = iocb->ki_pos;
|
||||||
|
__entry->size = size;
|
||||||
|
__entry->ki_flags = iocb->ki_flags;
|
||||||
|
__entry->aio = !is_sync_kiocb(iocb);
|
||||||
|
__entry->ret = ret;
|
||||||
|
),
|
||||||
|
TP_printk("dev %d:%d ino 0x%lx isize 0x%llx pos 0x%llx len %zd flags %s aio %d ret %d",
|
||||||
|
MAJOR(__entry->dev), MINOR(__entry->dev),
|
||||||
|
__entry->ino,
|
||||||
|
__entry->isize,
|
||||||
|
__entry->pos,
|
||||||
|
__entry->size,
|
||||||
|
__print_flags(__entry->ki_flags, "|", TRACE_IOCB_STRINGS),
|
||||||
|
__entry->aio,
|
||||||
|
__entry->ret)
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif /* _EXT2_TRACE_H */
|
||||||
|
|
||||||
|
#undef TRACE_INCLUDE_PATH
|
||||||
|
#define TRACE_INCLUDE_PATH .
|
||||||
|
#define TRACE_INCLUDE_FILE trace
|
||||||
|
#include <trace/define_trace.h>
|
@@ -28,6 +28,7 @@
|
|||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/writeback.h>
|
#include <linux/writeback.h>
|
||||||
#include <linux/blkdev.h>
|
#include <linux/blkdev.h>
|
||||||
|
#include <linux/buffer_head.h>
|
||||||
|
|
||||||
#include "ext4.h"
|
#include "ext4.h"
|
||||||
#include "ext4_jbd2.h"
|
#include "ext4_jbd2.h"
|
||||||
@@ -78,21 +79,13 @@ static int ext4_sync_parent(struct inode *inode)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ext4_fsync_nojournal(struct inode *inode, bool datasync,
|
static int ext4_fsync_nojournal(struct file *file, loff_t start, loff_t end,
|
||||||
bool *needs_barrier)
|
int datasync, bool *needs_barrier)
|
||||||
{
|
{
|
||||||
int ret, err;
|
struct inode *inode = file->f_inode;
|
||||||
|
int ret;
|
||||||
ret = sync_mapping_buffers(inode->i_mapping);
|
|
||||||
if (!(inode->i_state & I_DIRTY_ALL))
|
|
||||||
return ret;
|
|
||||||
if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
err = sync_inode_metadata(inode, 1);
|
|
||||||
if (!ret)
|
|
||||||
ret = err;
|
|
||||||
|
|
||||||
|
ret = generic_buffers_fsync_noflush(file, start, end, datasync);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
ret = ext4_sync_parent(inode);
|
ret = ext4_sync_parent(inode);
|
||||||
if (test_opt(inode->i_sb, BARRIER))
|
if (test_opt(inode->i_sb, BARRIER))
|
||||||
@@ -155,6 +148,14 @@ int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!sbi->s_journal) {
|
||||||
|
ret = ext4_fsync_nojournal(file, start, end, datasync,
|
||||||
|
&needs_barrier);
|
||||||
|
if (needs_barrier)
|
||||||
|
goto issue_flush;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
ret = file_write_and_wait_range(file, start, end);
|
ret = file_write_and_wait_range(file, start, end);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
@@ -164,11 +165,9 @@ int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
|
|||||||
* Metadata is in the journal, we wait for proper transaction to
|
* Metadata is in the journal, we wait for proper transaction to
|
||||||
* commit here.
|
* commit here.
|
||||||
*/
|
*/
|
||||||
if (!sbi->s_journal)
|
ret = ext4_fsync_journal(inode, datasync, &needs_barrier);
|
||||||
ret = ext4_fsync_nojournal(inode, datasync, &needs_barrier);
|
|
||||||
else
|
|
||||||
ret = ext4_fsync_journal(inode, datasync, &needs_barrier);
|
|
||||||
|
|
||||||
|
issue_flush:
|
||||||
if (needs_barrier) {
|
if (needs_barrier) {
|
||||||
err = blkdev_issue_flush(inode->i_sb->s_bdev);
|
err = blkdev_issue_flush(inode->i_sb->s_bdev);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
|
@@ -555,7 +555,7 @@ restart:
|
|||||||
continue;
|
continue;
|
||||||
/* Wait for dquot users */
|
/* Wait for dquot users */
|
||||||
if (atomic_read(&dquot->dq_count)) {
|
if (atomic_read(&dquot->dq_count)) {
|
||||||
dqgrab(dquot);
|
atomic_inc(&dquot->dq_count);
|
||||||
spin_unlock(&dq_list_lock);
|
spin_unlock(&dq_list_lock);
|
||||||
/*
|
/*
|
||||||
* Once dqput() wakes us up, we know it's time to free
|
* Once dqput() wakes us up, we know it's time to free
|
||||||
@@ -2420,7 +2420,8 @@ int dquot_load_quota_sb(struct super_block *sb, int type, int format_id,
|
|||||||
|
|
||||||
error = add_dquot_ref(sb, type);
|
error = add_dquot_ref(sb, type);
|
||||||
if (error)
|
if (error)
|
||||||
dquot_disable(sb, type, flags);
|
dquot_disable(sb, type,
|
||||||
|
DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
out_fmt:
|
out_fmt:
|
||||||
|
@@ -895,8 +895,9 @@ retry:
|
|||||||
up_write(&sb->s_umount);
|
up_write(&sb->s_umount);
|
||||||
else
|
else
|
||||||
up_read(&sb->s_umount);
|
up_read(&sb->s_umount);
|
||||||
wait_event(sb->s_writers.wait_unfrozen,
|
/* Wait for sb to unfreeze */
|
||||||
sb->s_writers.frozen == SB_UNFROZEN);
|
sb_start_write(sb);
|
||||||
|
sb_end_write(sb);
|
||||||
put_super(sb);
|
put_super(sb);
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
@@ -236,7 +236,6 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags,
|
|||||||
&type->s_writers_key[i]))
|
&type->s_writers_key[i]))
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
init_waitqueue_head(&s->s_writers.wait_unfrozen);
|
|
||||||
s->s_bdi = &noop_backing_dev_info;
|
s->s_bdi = &noop_backing_dev_info;
|
||||||
s->s_flags = flags;
|
s->s_flags = flags;
|
||||||
if (s->s_user_ns != &init_user_ns)
|
if (s->s_user_ns != &init_user_ns)
|
||||||
@@ -1716,7 +1715,6 @@ int freeze_super(struct super_block *sb)
|
|||||||
if (ret) {
|
if (ret) {
|
||||||
sb->s_writers.frozen = SB_UNFROZEN;
|
sb->s_writers.frozen = SB_UNFROZEN;
|
||||||
sb_freeze_unlock(sb, SB_FREEZE_PAGEFAULT);
|
sb_freeze_unlock(sb, SB_FREEZE_PAGEFAULT);
|
||||||
wake_up(&sb->s_writers.wait_unfrozen);
|
|
||||||
deactivate_locked_super(sb);
|
deactivate_locked_super(sb);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -1732,7 +1730,6 @@ int freeze_super(struct super_block *sb)
|
|||||||
"VFS:Filesystem freeze failed\n");
|
"VFS:Filesystem freeze failed\n");
|
||||||
sb->s_writers.frozen = SB_UNFROZEN;
|
sb->s_writers.frozen = SB_UNFROZEN;
|
||||||
sb_freeze_unlock(sb, SB_FREEZE_FS);
|
sb_freeze_unlock(sb, SB_FREEZE_FS);
|
||||||
wake_up(&sb->s_writers.wait_unfrozen);
|
|
||||||
deactivate_locked_super(sb);
|
deactivate_locked_super(sb);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -1778,7 +1775,6 @@ static int thaw_super_locked(struct super_block *sb)
|
|||||||
sb->s_writers.frozen = SB_UNFROZEN;
|
sb->s_writers.frozen = SB_UNFROZEN;
|
||||||
sb_freeze_unlock(sb, SB_FREEZE_FS);
|
sb_freeze_unlock(sb, SB_FREEZE_FS);
|
||||||
out:
|
out:
|
||||||
wake_up(&sb->s_writers.wait_unfrozen);
|
|
||||||
deactivate_locked_super(sb);
|
deactivate_locked_super(sb);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
/*
|
/*
|
||||||
* balloc.c
|
* balloc.c
|
||||||
*
|
*
|
||||||
@@ -5,11 +6,6 @@
|
|||||||
* Block allocation handling routines for the OSTA-UDF(tm) filesystem.
|
* Block allocation handling routines for the OSTA-UDF(tm) filesystem.
|
||||||
*
|
*
|
||||||
* COPYRIGHT
|
* COPYRIGHT
|
||||||
* This file is distributed under the terms of the GNU General Public
|
|
||||||
* License (GPL). Copies of the GPL can be obtained from:
|
|
||||||
* ftp://prep.ai.mit.edu/pub/gnu/GPL
|
|
||||||
* Each contributing author retains all rights to their own work.
|
|
||||||
*
|
|
||||||
* (C) 1999-2001 Ben Fennema
|
* (C) 1999-2001 Ben Fennema
|
||||||
* (C) 1999 Stelias Computing Inc
|
* (C) 1999 Stelias Computing Inc
|
||||||
*
|
*
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
/*
|
/*
|
||||||
* dir.c
|
* dir.c
|
||||||
*
|
*
|
||||||
@@ -5,11 +6,6 @@
|
|||||||
* Directory handling routines for the OSTA-UDF(tm) filesystem.
|
* Directory handling routines for the OSTA-UDF(tm) filesystem.
|
||||||
*
|
*
|
||||||
* COPYRIGHT
|
* COPYRIGHT
|
||||||
* This file is distributed under the terms of the GNU General Public
|
|
||||||
* License (GPL). Copies of the GPL can be obtained from:
|
|
||||||
* ftp://prep.ai.mit.edu/pub/gnu/GPL
|
|
||||||
* Each contributing author retains all rights to their own work.
|
|
||||||
*
|
|
||||||
* (C) 1998-2004 Ben Fennema
|
* (C) 1998-2004 Ben Fennema
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
|
@@ -1,14 +1,10 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
/*
|
/*
|
||||||
* directory.c
|
* directory.c
|
||||||
*
|
*
|
||||||
* PURPOSE
|
* PURPOSE
|
||||||
* Directory related functions
|
* Directory related functions
|
||||||
*
|
*
|
||||||
* COPYRIGHT
|
|
||||||
* This file is distributed under the terms of the GNU General Public
|
|
||||||
* License (GPL). Copies of the GPL can be obtained from:
|
|
||||||
* ftp://prep.ai.mit.edu/pub/gnu/GPL
|
|
||||||
* Each contributing author retains all rights to their own work.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "udfdecl.h"
|
#include "udfdecl.h"
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
/*
|
/*
|
||||||
* file.c
|
* file.c
|
||||||
*
|
*
|
||||||
@@ -5,11 +6,6 @@
|
|||||||
* File handling routines for the OSTA-UDF(tm) filesystem.
|
* File handling routines for the OSTA-UDF(tm) filesystem.
|
||||||
*
|
*
|
||||||
* COPYRIGHT
|
* COPYRIGHT
|
||||||
* This file is distributed under the terms of the GNU General Public
|
|
||||||
* License (GPL). Copies of the GPL can be obtained from:
|
|
||||||
* ftp://prep.ai.mit.edu/pub/gnu/GPL
|
|
||||||
* Each contributing author retains all rights to their own work.
|
|
||||||
*
|
|
||||||
* (C) 1998-1999 Dave Boynton
|
* (C) 1998-1999 Dave Boynton
|
||||||
* (C) 1998-2004 Ben Fennema
|
* (C) 1998-2004 Ben Fennema
|
||||||
* (C) 1999-2000 Stelias Computing Inc
|
* (C) 1999-2000 Stelias Computing Inc
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
/*
|
/*
|
||||||
* ialloc.c
|
* ialloc.c
|
||||||
*
|
*
|
||||||
@@ -5,11 +6,6 @@
|
|||||||
* Inode allocation handling routines for the OSTA-UDF(tm) filesystem.
|
* Inode allocation handling routines for the OSTA-UDF(tm) filesystem.
|
||||||
*
|
*
|
||||||
* COPYRIGHT
|
* COPYRIGHT
|
||||||
* This file is distributed under the terms of the GNU General Public
|
|
||||||
* License (GPL). Copies of the GPL can be obtained from:
|
|
||||||
* ftp://prep.ai.mit.edu/pub/gnu/GPL
|
|
||||||
* Each contributing author retains all rights to their own work.
|
|
||||||
*
|
|
||||||
* (C) 1998-2001 Ben Fennema
|
* (C) 1998-2001 Ben Fennema
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
/*
|
/*
|
||||||
* inode.c
|
* inode.c
|
||||||
*
|
*
|
||||||
@@ -5,11 +6,6 @@
|
|||||||
* Inode handling routines for the OSTA-UDF(tm) filesystem.
|
* Inode handling routines for the OSTA-UDF(tm) filesystem.
|
||||||
*
|
*
|
||||||
* COPYRIGHT
|
* COPYRIGHT
|
||||||
* This file is distributed under the terms of the GNU General Public
|
|
||||||
* License (GPL). Copies of the GPL can be obtained from:
|
|
||||||
* ftp://prep.ai.mit.edu/pub/gnu/GPL
|
|
||||||
* Each contributing author retains all rights to their own work.
|
|
||||||
*
|
|
||||||
* (C) 1998 Dave Boynton
|
* (C) 1998 Dave Boynton
|
||||||
* (C) 1998-2004 Ben Fennema
|
* (C) 1998-2004 Ben Fennema
|
||||||
* (C) 1999-2000 Stelias Computing Inc
|
* (C) 1999-2000 Stelias Computing Inc
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
/*
|
/*
|
||||||
* lowlevel.c
|
* lowlevel.c
|
||||||
*
|
*
|
||||||
@@ -5,11 +6,6 @@
|
|||||||
* Low Level Device Routines for the UDF filesystem
|
* Low Level Device Routines for the UDF filesystem
|
||||||
*
|
*
|
||||||
* COPYRIGHT
|
* COPYRIGHT
|
||||||
* This file is distributed under the terms of the GNU General Public
|
|
||||||
* License (GPL). Copies of the GPL can be obtained from:
|
|
||||||
* ftp://prep.ai.mit.edu/pub/gnu/GPL
|
|
||||||
* Each contributing author retains all rights to their own work.
|
|
||||||
*
|
|
||||||
* (C) 1999-2001 Ben Fennema
|
* (C) 1999-2001 Ben Fennema
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
/*
|
/*
|
||||||
* misc.c
|
* misc.c
|
||||||
*
|
*
|
||||||
@@ -5,11 +6,6 @@
|
|||||||
* Miscellaneous routines for the OSTA-UDF(tm) filesystem.
|
* Miscellaneous routines for the OSTA-UDF(tm) filesystem.
|
||||||
*
|
*
|
||||||
* COPYRIGHT
|
* COPYRIGHT
|
||||||
* This file is distributed under the terms of the GNU General Public
|
|
||||||
* License (GPL). Copies of the GPL can be obtained from:
|
|
||||||
* ftp://prep.ai.mit.edu/pub/gnu/GPL
|
|
||||||
* Each contributing author retains all rights to their own work.
|
|
||||||
*
|
|
||||||
* (C) 1998 Dave Boynton
|
* (C) 1998 Dave Boynton
|
||||||
* (C) 1998-2004 Ben Fennema
|
* (C) 1998-2004 Ben Fennema
|
||||||
* (C) 1999-2000 Stelias Computing Inc
|
* (C) 1999-2000 Stelias Computing Inc
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
/*
|
/*
|
||||||
* namei.c
|
* namei.c
|
||||||
*
|
*
|
||||||
@@ -5,11 +6,6 @@
|
|||||||
* Inode name handling routines for the OSTA-UDF(tm) filesystem.
|
* Inode name handling routines for the OSTA-UDF(tm) filesystem.
|
||||||
*
|
*
|
||||||
* COPYRIGHT
|
* COPYRIGHT
|
||||||
* This file is distributed under the terms of the GNU General Public
|
|
||||||
* License (GPL). Copies of the GPL can be obtained from:
|
|
||||||
* ftp://prep.ai.mit.edu/pub/gnu/GPL
|
|
||||||
* Each contributing author retains all rights to their own work.
|
|
||||||
*
|
|
||||||
* (C) 1998-2004 Ben Fennema
|
* (C) 1998-2004 Ben Fennema
|
||||||
* (C) 1999-2000 Stelias Computing Inc
|
* (C) 1999-2000 Stelias Computing Inc
|
||||||
*
|
*
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
/*
|
/*
|
||||||
* partition.c
|
* partition.c
|
||||||
*
|
*
|
||||||
@@ -5,11 +6,6 @@
|
|||||||
* Partition handling routines for the OSTA-UDF(tm) filesystem.
|
* Partition handling routines for the OSTA-UDF(tm) filesystem.
|
||||||
*
|
*
|
||||||
* COPYRIGHT
|
* COPYRIGHT
|
||||||
* This file is distributed under the terms of the GNU General Public
|
|
||||||
* License (GPL). Copies of the GPL can be obtained from:
|
|
||||||
* ftp://prep.ai.mit.edu/pub/gnu/GPL
|
|
||||||
* Each contributing author retains all rights to their own work.
|
|
||||||
*
|
|
||||||
* (C) 1998-2001 Ben Fennema
|
* (C) 1998-2001 Ben Fennema
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
/*
|
/*
|
||||||
* super.c
|
* super.c
|
||||||
*
|
*
|
||||||
@@ -15,11 +16,6 @@
|
|||||||
* https://www.iso.org/
|
* https://www.iso.org/
|
||||||
*
|
*
|
||||||
* COPYRIGHT
|
* COPYRIGHT
|
||||||
* This file is distributed under the terms of the GNU General Public
|
|
||||||
* License (GPL). Copies of the GPL can be obtained from:
|
|
||||||
* ftp://prep.ai.mit.edu/pub/gnu/GPL
|
|
||||||
* Each contributing author retains all rights to their own work.
|
|
||||||
*
|
|
||||||
* (C) 1998 Dave Boynton
|
* (C) 1998 Dave Boynton
|
||||||
* (C) 1998-2004 Ben Fennema
|
* (C) 1998-2004 Ben Fennema
|
||||||
* (C) 2000 Stelias Computing Inc
|
* (C) 2000 Stelias Computing Inc
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
/*
|
/*
|
||||||
* symlink.c
|
* symlink.c
|
||||||
*
|
*
|
||||||
@@ -5,11 +6,6 @@
|
|||||||
* Symlink handling routines for the OSTA-UDF(tm) filesystem.
|
* Symlink handling routines for the OSTA-UDF(tm) filesystem.
|
||||||
*
|
*
|
||||||
* COPYRIGHT
|
* COPYRIGHT
|
||||||
* This file is distributed under the terms of the GNU General Public
|
|
||||||
* License (GPL). Copies of the GPL can be obtained from:
|
|
||||||
* ftp://prep.ai.mit.edu/pub/gnu/GPL
|
|
||||||
* Each contributing author retains all rights to their own work.
|
|
||||||
*
|
|
||||||
* (C) 1998-2001 Ben Fennema
|
* (C) 1998-2001 Ben Fennema
|
||||||
* (C) 1999 Stelias Computing Inc
|
* (C) 1999 Stelias Computing Inc
|
||||||
*
|
*
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
/*
|
/*
|
||||||
* truncate.c
|
* truncate.c
|
||||||
*
|
*
|
||||||
@@ -5,11 +6,6 @@
|
|||||||
* Truncate handling routines for the OSTA-UDF(tm) filesystem.
|
* Truncate handling routines for the OSTA-UDF(tm) filesystem.
|
||||||
*
|
*
|
||||||
* COPYRIGHT
|
* COPYRIGHT
|
||||||
* This file is distributed under the terms of the GNU General Public
|
|
||||||
* License (GPL). Copies of the GPL can be obtained from:
|
|
||||||
* ftp://prep.ai.mit.edu/pub/gnu/GPL
|
|
||||||
* Each contributing author retains all rights to their own work.
|
|
||||||
*
|
|
||||||
* (C) 1999-2004 Ben Fennema
|
* (C) 1999-2004 Ben Fennema
|
||||||
* (C) 1999 Stelias Computing Inc
|
* (C) 1999 Stelias Computing Inc
|
||||||
*
|
*
|
||||||
|
@@ -1,21 +1,7 @@
|
|||||||
|
// SPDX-License-Identifier: LGPL-2.0+
|
||||||
/* Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
|
/* Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
|
||||||
This file is part of the GNU C Library.
|
This file is part of the GNU C Library.
|
||||||
Contributed by Paul Eggert (eggert@twinsun.com).
|
Contributed by Paul Eggert (eggert@twinsun.com). */
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Library General Public License as
|
|
||||||
published by the Free Software Foundation; either version 2 of the
|
|
||||||
License, or (at your option) any later version.
|
|
||||||
|
|
||||||
The GNU C Library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Library General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Library General Public
|
|
||||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
|
||||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
||||||
Boston, MA 02111-1307, USA. */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* dgb 10/02/98: ripped this from glibc source to help convert timestamps
|
* dgb 10/02/98: ripped this from glibc source to help convert timestamps
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
/*
|
/*
|
||||||
* unicode.c
|
* unicode.c
|
||||||
*
|
*
|
||||||
@@ -11,11 +12,6 @@
|
|||||||
* UTF-8 is explained in the IETF RFC XXXX.
|
* UTF-8 is explained in the IETF RFC XXXX.
|
||||||
* ftp://ftp.internic.net/rfc/rfcxxxx.txt
|
* ftp://ftp.internic.net/rfc/rfcxxxx.txt
|
||||||
*
|
*
|
||||||
* COPYRIGHT
|
|
||||||
* This file is distributed under the terms of the GNU General Public
|
|
||||||
* License (GPL). Copies of the GPL can be obtained from:
|
|
||||||
* ftp://prep.ai.mit.edu/pub/gnu/GPL
|
|
||||||
* Each contributing author retains all rights to their own work.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "udfdecl.h"
|
#include "udfdecl.h"
|
||||||
@@ -247,7 +243,7 @@ static int udf_name_from_CS0(struct super_block *sb,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (translate) {
|
if (translate) {
|
||||||
if (str_o_len <= 2 && str_o[0] == '.' &&
|
if (str_o_len > 0 && str_o_len <= 2 && str_o[0] == '.' &&
|
||||||
(str_o_len == 1 || str_o[1] == '.'))
|
(str_o_len == 1 || str_o[1] == '.'))
|
||||||
needsCRC = 1;
|
needsCRC = 1;
|
||||||
if (needsCRC) {
|
if (needsCRC) {
|
||||||
|
@@ -217,6 +217,10 @@ int inode_has_buffers(struct inode *);
|
|||||||
void invalidate_inode_buffers(struct inode *);
|
void invalidate_inode_buffers(struct inode *);
|
||||||
int remove_inode_buffers(struct inode *inode);
|
int remove_inode_buffers(struct inode *inode);
|
||||||
int sync_mapping_buffers(struct address_space *mapping);
|
int sync_mapping_buffers(struct address_space *mapping);
|
||||||
|
int generic_buffers_fsync_noflush(struct file *file, loff_t start, loff_t end,
|
||||||
|
bool datasync);
|
||||||
|
int generic_buffers_fsync(struct file *file, loff_t start, loff_t end,
|
||||||
|
bool datasync);
|
||||||
void clean_bdev_aliases(struct block_device *bdev, sector_t block,
|
void clean_bdev_aliases(struct block_device *bdev, sector_t block,
|
||||||
sector_t len);
|
sector_t len);
|
||||||
static inline void clean_bdev_bh_alias(struct buffer_head *bh)
|
static inline void clean_bdev_bh_alias(struct buffer_head *bh)
|
||||||
|
@@ -1148,7 +1148,6 @@ enum {
|
|||||||
|
|
||||||
struct sb_writers {
|
struct sb_writers {
|
||||||
int frozen; /* Is sb frozen? */
|
int frozen; /* Is sb frozen? */
|
||||||
wait_queue_head_t wait_unfrozen; /* wait for thaw */
|
|
||||||
struct percpu_rw_semaphore rw_sem[SB_FREEZE_LEVELS];
|
struct percpu_rw_semaphore rw_sem[SB_FREEZE_LEVELS];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user