aboutsummaryrefslogtreecommitdiff
path: root/fs/jfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/jfs')
-rw-r--r--fs/jfs/Kconfig50
-rw-r--r--fs/jfs/Makefile4
-rw-r--r--fs/jfs/acl.c201
-rw-r--r--fs/jfs/file.c76
-rw-r--r--fs/jfs/inode.c95
-rw-r--r--fs/jfs/ioctl.c76
-rw-r--r--fs/jfs/jfs_acl.h4
-rw-r--r--fs/jfs/jfs_debug.c67
-rw-r--r--fs/jfs/jfs_debug.h10
-rw-r--r--fs/jfs/jfs_discard.c121
-rw-r--r--fs/jfs/jfs_discard.h26
-rw-r--r--fs/jfs/jfs_dmap.c240
-rw-r--r--fs/jfs/jfs_dmap.h10
-rw-r--r--fs/jfs/jfs_dtree.c154
-rw-r--r--fs/jfs/jfs_dtree.h5
-rw-r--r--fs/jfs/jfs_extent.c86
-rw-r--r--fs/jfs/jfs_filsys.h3
-rw-r--r--fs/jfs/jfs_imap.c158
-rw-r--r--fs/jfs/jfs_incore.h18
-rw-r--r--fs/jfs/jfs_inode.c58
-rw-r--r--fs/jfs/jfs_inode.h12
-rw-r--r--fs/jfs/jfs_logmgr.c89
-rw-r--r--fs/jfs/jfs_logmgr.h2
-rw-r--r--fs/jfs/jfs_metapage.c77
-rw-r--r--fs/jfs/jfs_metapage.h2
-rw-r--r--fs/jfs/jfs_mount.c4
-rw-r--r--fs/jfs/jfs_superblock.h1
-rw-r--r--fs/jfs/jfs_txnmgr.c95
-rw-r--r--fs/jfs/jfs_types.h29
-rw-r--r--fs/jfs/jfs_umount.c4
-rw-r--r--fs/jfs/jfs_unicode.h1
-rw-r--r--fs/jfs/jfs_xattr.h7
-rw-r--r--fs/jfs/jfs_xtree.c408
-rw-r--r--fs/jfs/jfs_xtree.h2
-rw-r--r--fs/jfs/namei.c228
-rw-r--r--fs/jfs/resize.c14
-rw-r--r--fs/jfs/super.c341
-rw-r--r--fs/jfs/symlink.c14
-rw-r--r--fs/jfs/xattr.c291
39 files changed, 1610 insertions, 1473 deletions
diff --git a/fs/jfs/Kconfig b/fs/jfs/Kconfig
new file mode 100644
index 00000000000..57cef19951d
--- /dev/null
+++ b/fs/jfs/Kconfig
@@ -0,0 +1,50 @@
+config JFS_FS
+ tristate "JFS filesystem support"
+ select NLS
+ select CRC32
+ help
+ This is a port of IBM's Journaled Filesystem . More information is
+ available in the file <file:Documentation/filesystems/jfs.txt>.
+
+ If you do not intend to use the JFS filesystem, say N.
+
+config JFS_POSIX_ACL
+ bool "JFS POSIX Access Control Lists"
+ depends on JFS_FS
+ select FS_POSIX_ACL
+ help
+ Posix Access Control Lists (ACLs) support permissions for users and
+ groups beyond the owner/group/world scheme.
+
+ To learn more about Access Control Lists, visit the Posix ACLs for
+ Linux website <http://acl.bestbits.at/>.
+
+ If you don't know what Access Control Lists are, say N
+
+config JFS_SECURITY
+ bool "JFS Security Labels"
+ depends on JFS_FS
+ help
+ Security labels support alternative access control models
+ implemented by security modules like SELinux. This option
+ enables an extended attribute handler for file security
+ labels in the jfs filesystem.
+
+ If you are not using a security module that requires using
+ extended attributes for file security labels, say N.
+
+config JFS_DEBUG
+ bool "JFS debugging"
+ depends on JFS_FS
+ help
+ If you are experiencing any problems with the JFS filesystem, say
+ Y here. This will result in additional debugging messages to be
+ written to the system log. Under normal circumstances, this
+ results in very little overhead.
+
+config JFS_STATISTICS
+ bool "JFS statistics"
+ depends on JFS_FS
+ help
+ Enabling this option will cause statistics from the JFS file system
+ to be made available to the user in the /proc/fs/jfs/ directory.
diff --git a/fs/jfs/Makefile b/fs/jfs/Makefile
index 3adb6395e42..d20d4737b3e 100644
--- a/fs/jfs/Makefile
+++ b/fs/jfs/Makefile
@@ -6,11 +6,11 @@ obj-$(CONFIG_JFS_FS) += jfs.o
jfs-y := super.o file.o inode.o namei.o jfs_mount.o jfs_umount.o \
jfs_xtree.o jfs_imap.o jfs_debug.o jfs_dmap.o \
- jfs_unicode.o jfs_dtree.o jfs_inode.o \
+ jfs_unicode.o jfs_dtree.o jfs_inode.o jfs_discard.o \
jfs_extent.o symlink.o jfs_metapage.o \
jfs_logmgr.o jfs_txnmgr.o jfs_uniupr.o \
resize.o xattr.o ioctl.o
jfs-$(CONFIG_JFS_POSIX_ACL) += acl.o
-EXTRA_CFLAGS += -D_JFS_4K
+ccflags-y := -D_JFS_4K
diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c
index 4d84bdc8829..0c8ca830b11 100644
--- a/fs/jfs/acl.c
+++ b/fs/jfs/acl.c
@@ -19,39 +19,36 @@
*/
#include <linux/sched.h>
+#include <linux/slab.h>
#include <linux/fs.h>
-#include <linux/quotaops.h>
#include <linux/posix_acl_xattr.h>
#include "jfs_incore.h"
#include "jfs_txnmgr.h"
#include "jfs_xattr.h"
#include "jfs_acl.h"
-static struct posix_acl *jfs_get_acl(struct inode *inode, int type)
+struct posix_acl *jfs_get_acl(struct inode *inode, int type)
{
struct posix_acl *acl;
char *ea_name;
- struct jfs_inode_info *ji = JFS_IP(inode);
- struct posix_acl **p_acl;
int size;
char *value = NULL;
+ acl = get_cached_acl(inode, type);
+ if (acl != ACL_NOT_CACHED)
+ return acl;
+
switch(type) {
case ACL_TYPE_ACCESS:
ea_name = POSIX_ACL_XATTR_ACCESS;
- p_acl = &ji->i_acl;
break;
case ACL_TYPE_DEFAULT:
ea_name = POSIX_ACL_XATTR_DEFAULT;
- p_acl = &ji->i_default_acl;
break;
default:
return ERR_PTR(-EINVAL);
}
- if (*p_acl != JFS_ACL_NOT_CACHED)
- return posix_acl_dup(*p_acl);
-
size = __jfs_getxattr(inode, ea_name, NULL, 0);
if (size > 0) {
@@ -62,53 +59,53 @@ static struct posix_acl *jfs_get_acl(struct inode *inode, int type)
}
if (size < 0) {
- if (size == -ENODATA) {
- *p_acl = NULL;
+ if (size == -ENODATA)
acl = NULL;
- } else
+ else
acl = ERR_PTR(size);
} else {
- acl = posix_acl_from_xattr(value, size);
- if (!IS_ERR(acl))
- *p_acl = posix_acl_dup(acl);
+ acl = posix_acl_from_xattr(&init_user_ns, value, size);
}
kfree(value);
+ if (!IS_ERR(acl))
+ set_cached_acl(inode, type, acl);
return acl;
}
-static int jfs_set_acl(tid_t tid, struct inode *inode, int type,
+static int __jfs_set_acl(tid_t tid, struct inode *inode, int type,
struct posix_acl *acl)
{
char *ea_name;
- struct jfs_inode_info *ji = JFS_IP(inode);
- struct posix_acl **p_acl;
int rc;
int size = 0;
char *value = NULL;
- if (S_ISLNK(inode->i_mode))
- return -EOPNOTSUPP;
-
- switch(type) {
- case ACL_TYPE_ACCESS:
- ea_name = POSIX_ACL_XATTR_ACCESS;
- p_acl = &ji->i_acl;
- break;
- case ACL_TYPE_DEFAULT:
- ea_name = POSIX_ACL_XATTR_DEFAULT;
- p_acl = &ji->i_default_acl;
- if (!S_ISDIR(inode->i_mode))
- return acl ? -EACCES : 0;
- break;
- default:
- return -EINVAL;
+ switch (type) {
+ case ACL_TYPE_ACCESS:
+ ea_name = POSIX_ACL_XATTR_ACCESS;
+ if (acl) {
+ rc = posix_acl_equiv_mode(acl, &inode->i_mode);
+ if (rc < 0)
+ return rc;
+ inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty(inode);
+ if (rc == 0)
+ acl = NULL;
+ }
+ break;
+ case ACL_TYPE_DEFAULT:
+ ea_name = POSIX_ACL_XATTR_DEFAULT;
+ break;
+ default:
+ return -EINVAL;
}
+
if (acl) {
size = posix_acl_xattr_size(acl->a_count);
value = kmalloc(size, GFP_KERNEL);
if (!value)
return -ENOMEM;
- rc = posix_acl_to_xattr(acl, value, size);
+ rc = posix_acl_to_xattr(&init_user_ns, acl, value, size);
if (rc < 0)
goto out;
}
@@ -116,131 +113,49 @@ static int jfs_set_acl(tid_t tid, struct inode *inode, int type,
out:
kfree(value);
- if (!rc) {
- if (*p_acl && (*p_acl != JFS_ACL_NOT_CACHED))
- posix_acl_release(*p_acl);
- *p_acl = posix_acl_dup(acl);
- }
- return rc;
-}
-
-static int jfs_check_acl(struct inode *inode, int mask)
-{
- struct jfs_inode_info *ji = JFS_IP(inode);
-
- if (ji->i_acl == JFS_ACL_NOT_CACHED) {
- struct posix_acl *acl = jfs_get_acl(inode, ACL_TYPE_ACCESS);
- if (IS_ERR(acl))
- return PTR_ERR(acl);
- posix_acl_release(acl);
- }
-
- if (ji->i_acl)
- return posix_acl_permission(inode, ji->i_acl, mask);
- return -EAGAIN;
-}
-
-int jfs_permission(struct inode *inode, int mask, struct nameidata *nd)
-{
- return generic_permission(inode, mask, jfs_check_acl);
-}
-
-int jfs_init_acl(tid_t tid, struct inode *inode, struct inode *dir)
-{
- struct posix_acl *acl = NULL;
- struct posix_acl *clone;
- mode_t mode;
- int rc = 0;
-
- if (S_ISLNK(inode->i_mode))
- return 0;
-
- acl = jfs_get_acl(dir, ACL_TYPE_DEFAULT);
- if (IS_ERR(acl))
- return PTR_ERR(acl);
-
- if (acl) {
- if (S_ISDIR(inode->i_mode)) {
- rc = jfs_set_acl(tid, inode, ACL_TYPE_DEFAULT, acl);
- if (rc)
- goto cleanup;
- }
- clone = posix_acl_clone(acl, GFP_KERNEL);
- if (!clone) {
- rc = -ENOMEM;
- goto cleanup;
- }
- mode = inode->i_mode;
- rc = posix_acl_create_masq(clone, &mode);
- if (rc >= 0) {
- inode->i_mode = mode;
- if (rc > 0)
- rc = jfs_set_acl(tid, inode, ACL_TYPE_ACCESS,
- clone);
- }
- posix_acl_release(clone);
-cleanup:
- posix_acl_release(acl);
- } else
- inode->i_mode &= ~current->fs->umask;
-
- JFS_IP(inode)->mode2 = (JFS_IP(inode)->mode2 & 0xffff0000) |
- inode->i_mode;
+ if (!rc)
+ set_cached_acl(inode, type, acl);
return rc;
}
-static int jfs_acl_chmod(struct inode *inode)
+int jfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
{
- struct posix_acl *acl, *clone;
int rc;
-
- if (S_ISLNK(inode->i_mode))
- return -EOPNOTSUPP;
-
- acl = jfs_get_acl(inode, ACL_TYPE_ACCESS);
- if (IS_ERR(acl) || !acl)
- return PTR_ERR(acl);
-
- clone = posix_acl_clone(acl, GFP_KERNEL);
- posix_acl_release(acl);
- if (!clone)
- return -ENOMEM;
-
- rc = posix_acl_chmod_masq(clone, inode->i_mode);
- if (!rc) {
- tid_t tid = txBegin(inode->i_sb, 0);
- mutex_lock(&JFS_IP(inode)->commit_mutex);
- rc = jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, clone);
- if (!rc)
- rc = txCommit(tid, 1, &inode, 0);
- txEnd(tid);
- mutex_unlock(&JFS_IP(inode)->commit_mutex);
- }
-
- posix_acl_release(clone);
+ tid_t tid;
+
+ tid = txBegin(inode->i_sb, 0);
+ mutex_lock(&JFS_IP(inode)->commit_mutex);
+ rc = __jfs_set_acl(tid, inode, type, acl);
+ if (!rc)
+ rc = txCommit(tid, 1, &inode, 0);
+ txEnd(tid);
+ mutex_unlock(&JFS_IP(inode)->commit_mutex);
return rc;
}
-int jfs_setattr(struct dentry *dentry, struct iattr *iattr)
+int jfs_init_acl(tid_t tid, struct inode *inode, struct inode *dir)
{
- struct inode *inode = dentry->d_inode;
- int rc;
+ struct posix_acl *default_acl, *acl;
+ int rc = 0;
- rc = inode_change_ok(inode, iattr);
+ rc = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
if (rc)
return rc;
- if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) ||
- (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) {
- if (DQUOT_TRANSFER(inode, iattr))
- return -EDQUOT;
+ if (default_acl) {
+ rc = __jfs_set_acl(tid, inode, ACL_TYPE_DEFAULT, default_acl);
+ posix_acl_release(default_acl);
}
- rc = inode_setattr(inode, iattr);
+ if (acl) {
+ if (!rc)
+ rc = __jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, acl);
+ posix_acl_release(acl);
+ }
- if (!rc && (iattr->ia_valid & ATTR_MODE))
- rc = jfs_acl_chmod(inode);
+ JFS_IP(inode)->mode2 = (JFS_IP(inode)->mode2 & 0xffff0000) |
+ inode->i_mode;
return rc;
}
diff --git a/fs/jfs/file.c b/fs/jfs/file.c
index 7f6063acaa3..33aa0cc1f8b 100644
--- a/fs/jfs/file.c
+++ b/fs/jfs/file.c
@@ -17,7 +17,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <linux/mm.h>
#include <linux/fs.h>
+#include <linux/posix_acl.h>
+#include <linux/quotaops.h>
#include "jfs_incore.h"
#include "jfs_inode.h"
#include "jfs_dmap.h"
@@ -26,19 +29,26 @@
#include "jfs_acl.h"
#include "jfs_debug.h"
-int jfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+int jfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
{
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = file->f_mapping->host;
int rc = 0;
+ rc = filemap_write_and_wait_range(inode->i_mapping, start, end);
+ if (rc)
+ return rc;
+
+ mutex_lock(&inode->i_mutex);
if (!(inode->i_state & I_DIRTY) ||
(datasync && !(inode->i_state & I_DIRTY_DATASYNC))) {
/* Make sure committed changes hit the disk */
jfs_flush_journal(JFS_SBI(inode->i_sb)->log, 1);
+ mutex_unlock(&inode->i_mutex);
return rc;
}
rc |= jfs_commit_inode(inode, 1);
+ mutex_unlock(&inode->i_mutex);
return rc ? -EIO : 0;
}
@@ -47,7 +57,7 @@ static int jfs_open(struct inode *inode, struct file *file)
{
int rc;
- if ((rc = generic_file_open(inode, file)))
+ if ((rc = dquot_file_open(inode, file)))
return rc;
/*
@@ -64,9 +74,9 @@ static int jfs_open(struct inode *inode, struct file *file)
struct jfs_inode_info *ji = JFS_IP(inode);
spin_lock_irq(&ji->ag_lock);
if (ji->active_ag == -1) {
- ji->active_ag = ji->agno;
- atomic_inc(
- &JFS_SBI(inode->i_sb)->bmap->db_active[ji->agno]);
+ struct jfs_sb_info *jfs_sb = JFS_SBI(inode->i_sb);
+ ji->active_ag = BLKTOAG(addressPXD(&ji->ixpxd), jfs_sb);
+ atomic_inc( &jfs_sb->bmap->db_active[ji->active_ag]);
}
spin_unlock_irq(&ji->ag_lock);
}
@@ -88,28 +98,66 @@ static int jfs_release(struct inode *inode, struct file *file)
return 0;
}
+int jfs_setattr(struct dentry *dentry, struct iattr *iattr)
+{
+ struct inode *inode = dentry->d_inode;
+ int rc;
+
+ rc = inode_change_ok(inode, iattr);
+ if (rc)
+ return rc;
+
+ if (is_quota_modification(inode, iattr))
+ dquot_initialize(inode);
+ if ((iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid)) ||
+ (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))) {
+ rc = dquot_transfer(inode, iattr);
+ if (rc)
+ return rc;
+ }
+
+ if ((iattr->ia_valid & ATTR_SIZE) &&
+ iattr->ia_size != i_size_read(inode)) {
+ inode_dio_wait(inode);
+
+ rc = inode_newsize_ok(inode, iattr->ia_size);
+ if (rc)
+ return rc;
+
+ truncate_setsize(inode, iattr->ia_size);
+ jfs_truncate(inode);
+ }
+
+ setattr_copy(inode, iattr);
+ mark_inode_dirty(inode);
+
+ if (iattr->ia_valid & ATTR_MODE)
+ rc = posix_acl_chmod(inode, inode->i_mode);
+ return rc;
+}
+
const struct inode_operations jfs_file_inode_operations = {
- .truncate = jfs_truncate,
.setxattr = jfs_setxattr,
.getxattr = jfs_getxattr,
.listxattr = jfs_listxattr,
.removexattr = jfs_removexattr,
-#ifdef CONFIG_JFS_POSIX_ACL
.setattr = jfs_setattr,
- .permission = jfs_permission,
+#ifdef CONFIG_JFS_POSIX_ACL
+ .get_acl = jfs_get_acl,
+ .set_acl = jfs_set_acl,
#endif
};
const struct file_operations jfs_file_operations = {
.open = jfs_open,
.llseek = generic_file_llseek,
- .write = do_sync_write,
- .read = do_sync_read,
- .aio_read = generic_file_aio_read,
- .aio_write = generic_file_aio_write,
+ .write = new_sync_write,
+ .read = new_sync_read,
+ .read_iter = generic_file_read_iter,
+ .write_iter = generic_file_write_iter,
.mmap = generic_file_mmap,
.splice_read = generic_file_splice_read,
- .splice_write = generic_file_splice_write,
+ .splice_write = iter_file_splice_write,
.fsync = jfs_fsync,
.release = jfs_release,
.unlocked_ioctl = jfs_ioctl,
diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c
index 210339784b5..bd3df1ca3c9 100644
--- a/fs/jfs/inode.c
+++ b/fs/jfs/inode.c
@@ -22,6 +22,8 @@
#include <linux/buffer_head.h>
#include <linux/pagemap.h>
#include <linux/quotaops.h>
+#include <linux/writeback.h>
+#include <linux/aio.h>
#include "jfs_incore.h"
#include "jfs_inode.h"
#include "jfs_filsys.h"
@@ -59,8 +61,14 @@ struct inode *jfs_iget(struct super_block *sb, unsigned long ino)
if (inode->i_size >= IDATASIZE) {
inode->i_op = &page_symlink_inode_operations;
inode->i_mapping->a_ops = &jfs_aops;
- } else
- inode->i_op = &jfs_symlink_inode_operations;
+ } else {
+ inode->i_op = &jfs_fast_symlink_inode_operations;
+ /*
+ * The inline data should be null-terminated, but
+ * don't let on-disk corruption crash the kernel
+ */
+ JFS_IP(inode)->i_inline[inode->i_size] = '\0';
+ }
} else {
inode->i_op = &jfs_file_inode_operations;
init_special_inode(inode, inode->i_mode, inode->i_rdev);
@@ -114,9 +122,11 @@ int jfs_commit_inode(struct inode *inode, int wait)
return rc;
}
-int jfs_write_inode(struct inode *inode, int wait)
+int jfs_write_inode(struct inode *inode, struct writeback_control *wbc)
{
- if (test_cflag(COMMIT_Nolink, inode))
+ int wait = wbc->sync_mode == WB_SYNC_ALL;
+
+ if (inode->i_nlink == 0)
return 0;
/*
* If COMMIT_DIRTY is not set, the inode isn't really dirty.
@@ -136,31 +146,35 @@ int jfs_write_inode(struct inode *inode, int wait)
return 0;
}
-void jfs_delete_inode(struct inode *inode)
+void jfs_evict_inode(struct inode *inode)
{
- jfs_info("In jfs_delete_inode, inode = 0x%p", inode);
+ jfs_info("In jfs_evict_inode, inode = 0x%p", inode);
- if (!is_bad_inode(inode) &&
- (JFS_IP(inode)->fileset == FILESYSTEM_I)) {
- truncate_inode_pages(&inode->i_data, 0);
+ if (!inode->i_nlink && !is_bad_inode(inode)) {
+ dquot_initialize(inode);
- if (test_cflag(COMMIT_Freewmap, inode))
- jfs_free_zero_link(inode);
+ if (JFS_IP(inode)->fileset == FILESYSTEM_I) {
+ truncate_inode_pages_final(&inode->i_data);
- diFree(inode);
+ if (test_cflag(COMMIT_Freewmap, inode))
+ jfs_free_zero_link(inode);
- /*
- * Free the inode from the quota allocation.
- */
- DQUOT_INIT(inode);
- DQUOT_FREE_INODE(inode);
- DQUOT_DROP(inode);
- }
+ diFree(inode);
+ /*
+ * Free the inode from the quota allocation.
+ */
+ dquot_initialize(inode);
+ dquot_free_inode(inode);
+ }
+ } else {
+ truncate_inode_pages_final(&inode->i_data);
+ }
clear_inode(inode);
+ dquot_drop(inode);
}
-void jfs_dirty_inode(struct inode *inode)
+void jfs_dirty_inode(struct inode *inode, int flags)
{
static int noisy = 5;
@@ -287,12 +301,28 @@ static int jfs_readpages(struct file *file, struct address_space *mapping,
return mpage_readpages(mapping, pages, nr_pages, jfs_get_block);
}
+static void jfs_write_failed(struct address_space *mapping, loff_t to)
+{
+ struct inode *inode = mapping->host;
+
+ if (to > inode->i_size) {
+ truncate_pagecache(inode, inode->i_size);
+ jfs_truncate(inode);
+ }
+}
+
static int jfs_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
{
- return nobh_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
+ int ret;
+
+ ret = nobh_write_begin(mapping, pos, len, flags, pagep, fsdata,
jfs_get_block);
+ if (unlikely(ret))
+ jfs_write_failed(mapping, pos + len);
+
+ return ret;
}
static sector_t jfs_bmap(struct address_space *mapping, sector_t block)
@@ -301,13 +331,29 @@ static sector_t jfs_bmap(struct address_space *mapping, sector_t block)
}
static ssize_t jfs_direct_IO(int rw, struct kiocb *iocb,
- const struct iovec *iov, loff_t offset, unsigned long nr_segs)
+ struct iov_iter *iter, loff_t offset)
{
struct file *file = iocb->ki_filp;
+ struct address_space *mapping = file->f_mapping;
struct inode *inode = file->f_mapping->host;
+ size_t count = iov_iter_count(iter);
+ ssize_t ret;
+
+ ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, jfs_get_block);
+
+ /*
+ * In case of error extending write may have instantiated a few
+ * blocks outside i_size. Trim these off again.
+ */
+ if (unlikely((rw & WRITE) && ret < 0)) {
+ loff_t isize = i_size_read(inode);
+ loff_t end = offset + count;
+
+ if (end > isize)
+ jfs_write_failed(mapping, end);
+ }
- return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
- offset, nr_segs, jfs_get_block, NULL);
+ return ret;
}
const struct address_space_operations jfs_aops = {
@@ -315,7 +361,6 @@ const struct address_space_operations jfs_aops = {
.readpages = jfs_readpages,
.writepage = jfs_writepage,
.writepages = jfs_writepages,
- .sync_page = block_sync_page,
.write_begin = jfs_write_begin,
.write_end = nobh_write_end,
.bmap = jfs_bmap,
diff --git a/fs/jfs/ioctl.c b/fs/jfs/ioctl.c
index a1f8e375ad2..93a1232894f 100644
--- a/fs/jfs/ioctl.c
+++ b/fs/jfs/ioctl.c
@@ -8,15 +8,20 @@
#include <linux/fs.h>
#include <linux/ctype.h>
#include <linux/capability.h>
+#include <linux/mount.h>
#include <linux/time.h>
#include <linux/sched.h>
+#include <linux/blkdev.h>
#include <asm/current.h>
#include <asm/uaccess.h>
+#include "jfs_filsys.h"
+#include "jfs_debug.h"
#include "jfs_incore.h"
#include "jfs_dinode.h"
#include "jfs_inode.h"
-
+#include "jfs_dmap.h"
+#include "jfs_discard.h"
static struct {
long jfs_flag;
@@ -53,7 +58,7 @@ static long jfs_map_ext2(unsigned long flags, int from)
long jfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = file_inode(filp);
struct jfs_inode_info *jfs_inode = JFS_IP(inode);
unsigned int flags;
@@ -65,23 +70,30 @@ long jfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
return put_user(flags, (int __user *) arg);
case JFS_IOC_SETFLAGS: {
unsigned int oldflags;
+ int err;
- if (IS_RDONLY(inode))
- return -EROFS;
-
- if (!is_owner_or_cap(inode))
- return -EACCES;
+ err = mnt_want_write_file(filp);
+ if (err)
+ return err;
- if (get_user(flags, (int __user *) arg))
- return -EFAULT;
+ if (!inode_owner_or_capable(inode)) {
+ err = -EACCES;
+ goto setflags_out;
+ }
+ if (get_user(flags, (int __user *) arg)) {
+ err = -EFAULT;
+ goto setflags_out;
+ }
flags = jfs_map_ext2(flags, 1);
if (!S_ISDIR(inode->i_mode))
flags &= ~JFS_DIRSYNC_FL;
/* Is it quota file? Do not allow user to mess with it */
- if (IS_NOQUOTA(inode))
- return -EPERM;
+ if (IS_NOQUOTA(inode)) {
+ err = -EPERM;
+ goto setflags_out;
+ }
/* Lock against other parallel changes of flags */
mutex_lock(&inode->i_mutex);
@@ -98,7 +110,8 @@ long jfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
(JFS_APPEND_FL | JFS_IMMUTABLE_FL))) {
if (!capable(CAP_LINUX_IMMUTABLE)) {
mutex_unlock(&inode->i_mutex);
- return -EPERM;
+ err = -EPERM;
+ goto setflags_out;
}
}
@@ -110,8 +123,44 @@ long jfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
mutex_unlock(&inode->i_mutex);
inode->i_ctime = CURRENT_TIME_SEC;
mark_inode_dirty(inode);
+setflags_out:
+ mnt_drop_write_file(filp);
+ return err;
+ }
+
+ case FITRIM:
+ {
+ struct super_block *sb = inode->i_sb;
+ struct request_queue *q = bdev_get_queue(sb->s_bdev);
+ struct fstrim_range range;
+ s64 ret = 0;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (!blk_queue_discard(q)) {
+ jfs_warn("FITRIM not supported on device");
+ return -EOPNOTSUPP;
+ }
+
+ if (copy_from_user(&range, (struct fstrim_range __user *)arg,
+ sizeof(range)))
+ return -EFAULT;
+
+ range.minlen = max_t(unsigned int, range.minlen,
+ q->limits.discard_granularity);
+
+ ret = jfs_ioc_trim(inode, &range);
+ if (ret < 0)
+ return ret;
+
+ if (copy_to_user((struct fstrim_range __user *)arg, &range,
+ sizeof(range)))
+ return -EFAULT;
+
return 0;
}
+
default:
return -ENOTTY;
}
@@ -131,6 +180,9 @@ long jfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
case JFS_IOC_SETFLAGS32:
cmd = JFS_IOC_SETFLAGS;
break;
+ case FITRIM:
+ cmd = FITRIM;
+ break;
}
return jfs_ioctl(filp, cmd, arg);
}
diff --git a/fs/jfs/jfs_acl.h b/fs/jfs/jfs_acl.h
index 455fa429204..489f993b7b1 100644
--- a/fs/jfs/jfs_acl.h
+++ b/fs/jfs/jfs_acl.h
@@ -20,9 +20,9 @@
#ifdef CONFIG_JFS_POSIX_ACL
-int jfs_permission(struct inode *, int, struct nameidata *);
+struct posix_acl *jfs_get_acl(struct inode *inode, int type);
+int jfs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
int jfs_init_acl(tid_t, struct inode *, struct inode *);
-int jfs_setattr(struct dentry *, struct iattr *);
#else
diff --git a/fs/jfs/jfs_debug.c b/fs/jfs/jfs_debug.c
index 887f5759e53..dd824d9b0b1 100644
--- a/fs/jfs/jfs_debug.c
+++ b/fs/jfs/jfs_debug.c
@@ -21,6 +21,7 @@
#include <linux/ctype.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <asm/uaccess.h>
#include "jfs_incore.h"
#include "jfs_filsys.h"
@@ -30,29 +31,19 @@
static struct proc_dir_entry *base;
#ifdef CONFIG_JFS_DEBUG
-static int loglevel_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static int jfs_loglevel_proc_show(struct seq_file *m, void *v)
{
- int len;
-
- len = sprintf(page, "%d\n", jfsloglevel);
-
- len -= off;
- *start = page + off;
-
- if (len > count)
- len = count;
- else
- *eof = 1;
-
- if (len < 0)
- len = 0;
+ seq_printf(m, "%d\n", jfsloglevel);
+ return 0;
+}
- return len;
+static int jfs_loglevel_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, jfs_loglevel_proc_show, NULL);
}
-static int loglevel_write(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
+static ssize_t jfs_loglevel_proc_write(struct file *file,
+ const char __user *buffer, size_t count, loff_t *ppos)
{
char c;
@@ -65,22 +56,30 @@ static int loglevel_write(struct file *file, const char __user *buffer,
jfsloglevel = c - '0';
return count;
}
+
+static const struct file_operations jfs_loglevel_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = jfs_loglevel_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = jfs_loglevel_proc_write,
+};
#endif
static struct {
const char *name;
- read_proc_t *read_fn;
- write_proc_t *write_fn;
+ const struct file_operations *proc_fops;
} Entries[] = {
#ifdef CONFIG_JFS_STATISTICS
- { "lmstats", jfs_lmstats_read, },
- { "txstats", jfs_txstats_read, },
- { "xtstat", jfs_xtstat_read, },
- { "mpstat", jfs_mpstat_read, },
+ { "lmstats", &jfs_lmstats_proc_fops, },
+ { "txstats", &jfs_txstats_proc_fops, },
+ { "xtstat", &jfs_xtstat_proc_fops, },
+ { "mpstat", &jfs_mpstat_proc_fops, },
#endif
#ifdef CONFIG_JFS_DEBUG
- { "TxAnchor", jfs_txanchor_read, },
- { "loglevel", loglevel_read, loglevel_write }
+ { "TxAnchor", &jfs_txanchor_proc_fops, },
+ { "loglevel", &jfs_loglevel_proc_fops }
#endif
};
#define NPROCENT ARRAY_SIZE(Entries)
@@ -89,17 +88,11 @@ void jfs_proc_init(void)
{
int i;
- if (!(base = proc_mkdir("jfs", proc_root_fs)))
+ if (!(base = proc_mkdir("fs/jfs", NULL)))
return;
- base->owner = THIS_MODULE;
- for (i = 0; i < NPROCENT; i++) {
- struct proc_dir_entry *p;
- if ((p = create_proc_entry(Entries[i].name, 0, base))) {
- p->read_proc = Entries[i].read_fn;
- p->write_proc = Entries[i].write_fn;
- }
- }
+ for (i = 0; i < NPROCENT; i++)
+ proc_create(Entries[i].name, 0, base, Entries[i].proc_fops);
}
void jfs_proc_clean(void)
@@ -109,7 +102,7 @@ void jfs_proc_clean(void)
if (base) {
for (i = 0; i < NPROCENT; i++)
remove_proc_entry(Entries[i].name, base);
- remove_proc_entry("jfs", proc_root_fs);
+ remove_proc_entry("fs/jfs", NULL);
}
}
diff --git a/fs/jfs/jfs_debug.h b/fs/jfs/jfs_debug.h
index 044c1e654cc..eafd1300a00 100644
--- a/fs/jfs/jfs_debug.h
+++ b/fs/jfs/jfs_debug.h
@@ -62,7 +62,7 @@ extern void jfs_proc_clean(void);
extern int jfsloglevel;
-extern int jfs_txanchor_read(char *, char **, off_t, int, int *, void *);
+extern const struct file_operations jfs_txanchor_proc_fops;
/* information message: e.g., configuration, major event */
#define jfs_info(fmt, arg...) do { \
@@ -105,10 +105,10 @@ extern int jfs_txanchor_read(char *, char **, off_t, int, int *, void *);
* ----------
*/
#ifdef CONFIG_JFS_STATISTICS
-extern int jfs_lmstats_read(char *, char **, off_t, int, int *, void *);
-extern int jfs_txstats_read(char *, char **, off_t, int, int *, void *);
-extern int jfs_mpstat_read(char *, char **, off_t, int, int *, void *);
-extern int jfs_xtstat_read(char *, char **, off_t, int, int *, void *);
+extern const struct file_operations jfs_lmstats_proc_fops;
+extern const struct file_operations jfs_txstats_proc_fops;
+extern const struct file_operations jfs_mpstat_proc_fops;
+extern const struct file_operations jfs_xtstat_proc_fops;
#define INCREMENT(x) ((x)++)
#define DECREMENT(x) ((x)--)
diff --git a/fs/jfs/jfs_discard.c b/fs/jfs/jfs_discard.c
new file mode 100644
index 00000000000..dfcd5030455
--- /dev/null
+++ b/fs/jfs/jfs_discard.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) Tino Reichardt, 2012
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+
+#include "jfs_incore.h"
+#include "jfs_superblock.h"
+#include "jfs_discard.h"
+#include "jfs_dmap.h"
+#include "jfs_debug.h"
+
+
+/*
+ * NAME: jfs_issue_discard()
+ *
+ * FUNCTION: TRIM the specified block range on device, if supported
+ *
+ * PARAMETERS:
+ * ip - pointer to in-core inode
+ * blkno - starting block number to be trimmed (0..N)
+ * nblocks - number of blocks to be trimmed
+ *
+ * RETURN VALUES:
+ * none
+ *
+ * serialization: IREAD_LOCK(ipbmap) held on entry/exit;
+ */
+void jfs_issue_discard(struct inode *ip, u64 blkno, u64 nblocks)
+{
+ struct super_block *sb = ip->i_sb;
+ int r = 0;
+
+ r = sb_issue_discard(sb, blkno, nblocks, GFP_NOFS, 0);
+ if (unlikely(r != 0)) {
+ jfs_err("JFS: sb_issue_discard" \
+ "(%p, %llu, %llu, GFP_NOFS, 0) = %d => failed!\n",
+ sb, (unsigned long long)blkno,
+ (unsigned long long)nblocks, r);
+ }
+
+ jfs_info("JFS: sb_issue_discard" \
+ "(%p, %llu, %llu, GFP_NOFS, 0) = %d\n",
+ sb, (unsigned long long)blkno,
+ (unsigned long long)nblocks, r);
+
+ return;
+}
+
+/*
+ * NAME: jfs_ioc_trim()
+ *
+ * FUNCTION: attempt to discard (TRIM) all free blocks from the
+ * filesystem.
+ *
+ * PARAMETERS:
+ * ip - pointer to in-core inode;
+ * range - the range, given by user space
+ *
+ * RETURN VALUES:
+ * 0 - success
+ * -EIO - i/o error
+ */
+int jfs_ioc_trim(struct inode *ip, struct fstrim_range *range)
+{
+ struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
+ struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap;
+ struct super_block *sb = ipbmap->i_sb;
+ int agno, agno_end;
+ u64 start, end, minlen;
+ u64 trimmed = 0;
+
+ /**
+ * convert byte values to block size of filesystem:
+ * start: First Byte to trim
+ * len: number of Bytes to trim from start
+ * minlen: minimum extent length in Bytes
+ */
+ start = range->start >> sb->s_blocksize_bits;
+ end = start + (range->len >> sb->s_blocksize_bits) - 1;
+ minlen = range->minlen >> sb->s_blocksize_bits;
+ if (minlen == 0)
+ minlen = 1;
+
+ if (minlen > bmp->db_agsize ||
+ start >= bmp->db_mapsize ||
+ range->len < sb->s_blocksize)
+ return -EINVAL;
+
+ if (end >= bmp->db_mapsize)
+ end = bmp->db_mapsize - 1;
+
+ /**
+ * we trim all ag's within the range
+ */
+ agno = BLKTOAG(start, JFS_SBI(ip->i_sb));
+ agno_end = BLKTOAG(end, JFS_SBI(ip->i_sb));
+ while (agno <= agno_end) {
+ trimmed += dbDiscardAG(ip, agno, minlen);
+ agno++;
+ }
+ range->len = trimmed << sb->s_blocksize_bits;
+
+ return 0;
+}
diff --git a/fs/jfs/jfs_discard.h b/fs/jfs/jfs_discard.h
new file mode 100644
index 00000000000..40d1ee6081a
--- /dev/null
+++ b/fs/jfs/jfs_discard.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) Tino Reichardt, 2012
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _H_JFS_DISCARD
+#define _H_JFS_DISCARD
+
+struct fstrim_range;
+
+extern void jfs_issue_discard(struct inode *ip, u64 blkno, u64 nblocks);
+extern int jfs_ioc_trim(struct inode *ip, struct fstrim_range *range);
+
+#endif /* _H_JFS_DISCARD */
diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c
index e1985066b1c..2d514c7affc 100644
--- a/fs/jfs/jfs_dmap.c
+++ b/fs/jfs/jfs_dmap.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) International Business Machines Corp., 2000-2004
+ * Portions Copyright (C) Tino Reichardt, 2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,6 +18,7 @@
*/
#include <linux/fs.h>
+#include <linux/slab.h>
#include "jfs_incore.h"
#include "jfs_superblock.h"
#include "jfs_dmap.h"
@@ -24,6 +26,7 @@
#include "jfs_lock.h"
#include "jfs_metapage.h"
#include "jfs_debug.h"
+#include "jfs_discard.h"
/*
* SERIALIZATION of the Block Allocation Map.
@@ -103,7 +106,6 @@ static int dbFreeBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
static int dbFreeDmap(struct bmap * bmp, struct dmap * dp, s64 blkno,
int nblocks);
static int dbMaxBud(u8 * cp);
-s64 dbMapFileSizeToMapSize(struct inode *ipbmap);
static int blkstol2(s64 nb);
static int cntlz(u32 value);
@@ -144,7 +146,6 @@ static const s8 budtab[256] = {
2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1
};
-
/*
* NAME: dbMount()
*
@@ -195,7 +196,7 @@ int dbMount(struct inode *ipbmap)
bmp->db_maxag = le32_to_cpu(dbmp_le->dn_maxag);
bmp->db_agpref = le32_to_cpu(dbmp_le->dn_agpref);
bmp->db_aglevel = le32_to_cpu(dbmp_le->dn_aglevel);
- bmp->db_agheigth = le32_to_cpu(dbmp_le->dn_agheigth);
+ bmp->db_agheight = le32_to_cpu(dbmp_le->dn_agheight);
bmp->db_agwidth = le32_to_cpu(dbmp_le->dn_agwidth);
bmp->db_agstart = le32_to_cpu(dbmp_le->dn_agstart);
bmp->db_agl2size = le32_to_cpu(dbmp_le->dn_agl2size);
@@ -287,7 +288,7 @@ int dbSync(struct inode *ipbmap)
dbmp_le->dn_maxag = cpu_to_le32(bmp->db_maxag);
dbmp_le->dn_agpref = cpu_to_le32(bmp->db_agpref);
dbmp_le->dn_aglevel = cpu_to_le32(bmp->db_aglevel);
- dbmp_le->dn_agheigth = cpu_to_le32(bmp->db_agheigth);
+ dbmp_le->dn_agheight = cpu_to_le32(bmp->db_agheight);
dbmp_le->dn_agwidth = cpu_to_le32(bmp->db_agwidth);
dbmp_le->dn_agstart = cpu_to_le32(bmp->db_agstart);
dbmp_le->dn_agl2size = cpu_to_le32(bmp->db_agl2size);
@@ -309,7 +310,6 @@ int dbSync(struct inode *ipbmap)
return (0);
}
-
/*
* NAME: dbFree()
*
@@ -336,6 +336,7 @@ int dbFree(struct inode *ip, s64 blkno, s64 nblocks)
s64 lblkno, rem;
struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap;
+ struct super_block *sb = ipbmap->i_sb;
IREAD_LOCK(ipbmap, RDWRLOCK_DMAP);
@@ -345,11 +346,17 @@ int dbFree(struct inode *ip, s64 blkno, s64 nblocks)
printk(KERN_ERR "blkno = %Lx, nblocks = %Lx\n",
(unsigned long long) blkno,
(unsigned long long) nblocks);
- jfs_error(ip->i_sb,
- "dbFree: block to be freed is outside the map");
+ jfs_error(ip->i_sb, "block to be freed is outside the map\n");
return -EIO;
}
+ /**
+ * TRIM the blocks, when mounted with discard option
+ */
+ if (JFS_SBI(sb)->flag & JFS_DISCARD)
+ if (JFS_SBI(sb)->minblks_trim <= nblocks)
+ jfs_issue_discard(ipbmap, blkno, nblocks);
+
/*
* free the blocks a dmap at a time.
*/
@@ -376,7 +383,7 @@ int dbFree(struct inode *ip, s64 blkno, s64 nblocks)
/* free the blocks. */
if ((rc = dbFreeDmap(bmp, dp, blkno, nb))) {
- jfs_error(ip->i_sb, "dbFree: error in block map\n");
+ jfs_error(ip->i_sb, "error in block map\n");
release_metapage(mp);
IREAD_UNLOCK(ipbmap);
return (rc);
@@ -433,8 +440,7 @@ dbUpdatePMap(struct inode *ipbmap,
printk(KERN_ERR "blkno = %Lx, nblocks = %Lx\n",
(unsigned long long) blkno,
(unsigned long long) nblocks);
- jfs_error(ipbmap->i_sb,
- "dbUpdatePMap: blocks are outside the map");
+ jfs_error(ipbmap->i_sb, "blocks are outside the map\n");
return -EIO;
}
@@ -718,7 +724,7 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results)
/* the hint should be within the map */
if (hint >= mapSize) {
- jfs_error(ip->i_sb, "dbAlloc: the hint is outside the map");
+ jfs_error(ip->i_sb, "the hint is outside the map\n");
return -EIO;
}
@@ -755,7 +761,7 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results)
* allocation group.
*/
if ((blkno & (bmp->db_agsize - 1)) == 0)
- /* check if the AG is currenly being written to.
+ /* check if the AG is currently being written to.
* if so, call dbNextAG() to find a non-busy
* AG with sufficient free space.
*/
@@ -1049,8 +1055,7 @@ static int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks)
bmp = sbi->bmap;
if (lastblkno < 0 || lastblkno >= bmp->db_mapsize) {
IREAD_UNLOCK(ipbmap);
- jfs_error(ip->i_sb,
- "dbExtend: the block is outside the filesystem");
+ jfs_error(ip->i_sb, "the block is outside the filesystem\n");
return -EIO;
}
@@ -1094,7 +1099,6 @@ static int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks)
/* we were not successful */
release_metapage(mp);
-
return (rc);
}
@@ -1127,8 +1131,7 @@ static int dbAllocNext(struct bmap * bmp, struct dmap * dp, s64 blkno,
u32 mask;
if (dp->tree.leafidx != cpu_to_le32(LEAFIND)) {
- jfs_error(bmp->db_ipbmap->i_sb,
- "dbAllocNext: Corrupt dmap page");
+ jfs_error(bmp->db_ipbmap->i_sb, "Corrupt dmap page\n");
return -EIO;
}
@@ -1205,7 +1208,7 @@ static int dbAllocNext(struct bmap * bmp, struct dmap * dp, s64 blkno,
* by this leaf.
*/
l2size =
- min((int)leaf[word], NLSTOL2BSZ(nwords));
+ min_t(int, leaf[word], NLSTOL2BSZ(nwords));
/* determine how many words were handled.
*/
@@ -1258,8 +1261,7 @@ dbAllocNear(struct bmap * bmp,
s8 *leaf;
if (dp->tree.leafidx != cpu_to_le32(LEAFIND)) {
- jfs_error(bmp->db_ipbmap->i_sb,
- "dbAllocNear: Corrupt dmap page");
+ jfs_error(bmp->db_ipbmap->i_sb, "Corrupt dmap page\n");
return -EIO;
}
@@ -1374,8 +1376,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results)
*/
if (l2nb > bmp->db_agl2size) {
jfs_error(bmp->db_ipbmap->i_sb,
- "dbAllocAG: allocation request is larger than the "
- "allocation group size");
+ "allocation request is larger than the allocation group size\n");
return -EIO;
}
@@ -1410,7 +1411,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results)
(unsigned long long) blkno,
(unsigned long long) nblocks);
jfs_error(bmp->db_ipbmap->i_sb,
- "dbAllocAG: dbAllocCtl failed in free AG");
+ "dbAllocCtl failed in free AG\n");
}
return (rc);
}
@@ -1426,8 +1427,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results)
budmin = dcp->budmin;
if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) {
- jfs_error(bmp->db_ipbmap->i_sb,
- "dbAllocAG: Corrupt dmapctl page");
+ jfs_error(bmp->db_ipbmap->i_sb, "Corrupt dmapctl page\n");
release_metapage(mp);
return -EIO;
}
@@ -1440,7 +1440,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results)
* tree index of this allocation group within the control page.
*/
agperlev =
- (1 << (L2LPERCTL - (bmp->db_agheigth << 1))) / bmp->db_agwidth;
+ (1 << (L2LPERCTL - (bmp->db_agheight << 1))) / bmp->db_agwidth;
ti = bmp->db_agstart + bmp->db_agwidth * (agno & (agperlev - 1));
/* dmap control page trees fan-out by 4 and a single allocation
@@ -1459,7 +1459,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results)
* the subtree to find the leftmost leaf that describes this
* free space.
*/
- for (k = bmp->db_agheigth; k > 0; k--) {
+ for (k = bmp->db_agheight; k > 0; k--) {
for (n = 0, m = (ti << 2) + 1; n < 4; n++) {
if (l2nb <= dcp->stree[m + n]) {
ti = m + n;
@@ -1468,7 +1468,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results)
}
if (n == 4) {
jfs_error(bmp->db_ipbmap->i_sb,
- "dbAllocAG: failed descending stree");
+ "failed descending stree\n");
release_metapage(mp);
return -EIO;
}
@@ -1508,8 +1508,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results)
&blkno))) {
if (rc == -ENOSPC) {
jfs_error(bmp->db_ipbmap->i_sb,
- "dbAllocAG: control page "
- "inconsistent");
+ "control page inconsistent\n");
return -EIO;
}
return (rc);
@@ -1521,7 +1520,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results)
rc = dbAllocCtl(bmp, nblocks, l2nb, blkno, results);
if (rc == -ENOSPC) {
jfs_error(bmp->db_ipbmap->i_sb,
- "dbAllocAG: unable to allocate blocks");
+ "unable to allocate blocks\n");
rc = -EIO;
}
return (rc);
@@ -1580,8 +1579,7 @@ static int dbAllocAny(struct bmap * bmp, s64 nblocks, int l2nb, s64 * results)
*/
rc = dbAllocCtl(bmp, nblocks, l2nb, blkno, results);
if (rc == -ENOSPC) {
- jfs_error(bmp->db_ipbmap->i_sb,
- "dbAllocAny: unable to allocate blocks");
+ jfs_error(bmp->db_ipbmap->i_sb, "unable to allocate blocks\n");
return -EIO;
}
return (rc);
@@ -1589,6 +1587,116 @@ static int dbAllocAny(struct bmap * bmp, s64 nblocks, int l2nb, s64 * results)
/*
+ * NAME: dbDiscardAG()
+ *
+ * FUNCTION: attempt to discard (TRIM) all free blocks of specific AG
+ *
+ * algorithm:
+ * 1) allocate blocks, as large as possible and save them
+ * while holding IWRITE_LOCK on ipbmap
+ * 2) trim all these saved block/length values
+ * 3) mark the blocks free again
+ *
+ * benefit:
+ * - we work only on one ag at some time, minimizing how long we
+ * need to lock ipbmap
+ * - reading / writing the fs is possible most time, even on
+ * trimming
+ *
+ * downside:
+ * - we write two times to the dmapctl and dmap pages
+ * - but for me, this seems the best way, better ideas?
+ * /TR 2012
+ *
+ * PARAMETERS:
+ * ip - pointer to in-core inode
+ * agno - ag to trim
+ * minlen - minimum value of contiguous blocks
+ *
+ * RETURN VALUES:
+ * s64 - actual number of blocks trimmed
+ */
+s64 dbDiscardAG(struct inode *ip, int agno, s64 minlen)
+{
+ struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
+ struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap;
+ s64 nblocks, blkno;
+ u64 trimmed = 0;
+ int rc, l2nb;
+ struct super_block *sb = ipbmap->i_sb;
+
+ struct range2trim {
+ u64 blkno;
+ u64 nblocks;
+ } *totrim, *tt;
+
+ /* max blkno / nblocks pairs to trim */
+ int count = 0, range_cnt;
+ u64 max_ranges;
+
+ /* prevent others from writing new stuff here, while trimming */
+ IWRITE_LOCK(ipbmap, RDWRLOCK_DMAP);
+
+ nblocks = bmp->db_agfree[agno];
+ max_ranges = nblocks;
+ do_div(max_ranges, minlen);
+ range_cnt = min_t(u64, max_ranges + 1, 32 * 1024);
+ totrim = kmalloc(sizeof(struct range2trim) * range_cnt, GFP_NOFS);
+ if (totrim == NULL) {
+ jfs_error(bmp->db_ipbmap->i_sb, "no memory for trim array\n");
+ IWRITE_UNLOCK(ipbmap);
+ return 0;
+ }
+
+ tt = totrim;
+ while (nblocks >= minlen) {
+ l2nb = BLKSTOL2(nblocks);
+
+ /* 0 = okay, -EIO = fatal, -ENOSPC -> try smaller block */
+ rc = dbAllocAG(bmp, agno, nblocks, l2nb, &blkno);
+ if (rc == 0) {
+ tt->blkno = blkno;
+ tt->nblocks = nblocks;
+ tt++; count++;
+
+ /* the whole ag is free, trim now */
+ if (bmp->db_agfree[agno] == 0)
+ break;
+
+ /* give a hint for the next while */
+ nblocks = bmp->db_agfree[agno];
+ continue;
+ } else if (rc == -ENOSPC) {
+ /* search for next smaller log2 block */
+ l2nb = BLKSTOL2(nblocks) - 1;
+ nblocks = 1 << l2nb;
+ } else {
+ /* Trim any already allocated blocks */
+ jfs_error(bmp->db_ipbmap->i_sb, "-EIO\n");
+ break;
+ }
+
+ /* check, if our trim array is full */
+ if (unlikely(count >= range_cnt - 1))
+ break;
+ }
+ IWRITE_UNLOCK(ipbmap);
+
+ tt->nblocks = 0; /* mark the current end */
+ for (tt = totrim; tt->nblocks != 0; tt++) {
+ /* when mounted with online discard, dbFree() will
+ * call jfs_issue_discard() itself */
+ if (!(JFS_SBI(sb)->flag & JFS_DISCARD))
+ jfs_issue_discard(ip, tt->blkno, tt->nblocks);
+ dbFree(ip, tt->blkno, tt->nblocks);
+ trimmed += tt->nblocks;
+ }
+ kfree(totrim);
+
+ return trimmed;
+}
+
+/*
* NAME: dbFindCtl()
*
* FUNCTION: starting at a specified dmap control page level and block
@@ -1642,13 +1750,13 @@ static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno)
if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) {
jfs_error(bmp->db_ipbmap->i_sb,
- "dbFindCtl: Corrupt dmapctl page");
+ "Corrupt dmapctl page\n");
release_metapage(mp);
return -EIO;
}
/* search the tree within the dmap control page for
- * sufficent free space. if sufficient free space is found,
+ * sufficient free space. if sufficient free space is found,
* dbFindLeaf() returns the index of the leaf at which
* free space was found.
*/
@@ -1663,7 +1771,7 @@ static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno)
if (rc) {
if (lev != level) {
jfs_error(bmp->db_ipbmap->i_sb,
- "dbFindCtl: dmap inconsistent");
+ "dmap inconsistent\n");
return -EIO;
}
return -ENOSPC;
@@ -1787,14 +1895,14 @@ dbAllocCtl(struct bmap * bmp, s64 nblocks, int l2nb, s64 blkno, s64 * results)
if (dp->tree.stree[ROOT] != L2BPERDMAP) {
release_metapage(mp);
jfs_error(bmp->db_ipbmap->i_sb,
- "dbAllocCtl: the dmap is not all free");
+ "the dmap is not all free\n");
rc = -EIO;
goto backout;
}
/* determine how many blocks to allocate from this dmap.
*/
- nb = min(n, (s64)BPERDMAP);
+ nb = min_t(s64, n, BPERDMAP);
/* allocate the blocks from the dmap.
*/
@@ -1834,7 +1942,7 @@ dbAllocCtl(struct bmap * bmp, s64 nblocks, int l2nb, s64 blkno, s64 * results)
* to indicate that we have leaked blocks.
*/
jfs_error(bmp->db_ipbmap->i_sb,
- "dbAllocCtl: I/O Error: Block Leakage.");
+ "I/O Error: Block Leakage\n");
continue;
}
dp = (struct dmap *) mp->data;
@@ -1846,8 +1954,7 @@ dbAllocCtl(struct bmap * bmp, s64 nblocks, int l2nb, s64 blkno, s64 * results)
* to indicate that we have leaked blocks.
*/
release_metapage(mp);
- jfs_error(bmp->db_ipbmap->i_sb,
- "dbAllocCtl: Block Leakage.");
+ jfs_error(bmp->db_ipbmap->i_sb, "Block Leakage\n");
continue;
}
@@ -2144,8 +2251,7 @@ static void dbAllocBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
for (; nwords > 0; nwords -= nw) {
if (leaf[word] < BUDMIN) {
jfs_error(bmp->db_ipbmap->i_sb,
- "dbAllocBits: leaf page "
- "corrupt");
+ "leaf page corrupt\n");
break;
}
@@ -2154,7 +2260,8 @@ static void dbAllocBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
* of bits being allocated and the l2 number
* of bits currently described by this leaf.
*/
- size = min((int)leaf[word], NLSTOL2BSZ(nwords));
+ size = min_t(int, leaf[word],
+ NLSTOL2BSZ(nwords));
/* update the leaf to reflect the allocation.
* in addition to setting the leaf value to
@@ -2172,7 +2279,7 @@ static void dbAllocBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
}
/* update the free count for this dmap */
- dp->nfree = cpu_to_le32(le32_to_cpu(dp->nfree) - nblocks);
+ le32_add_cpu(&dp->nfree, -nblocks);
BMAP_LOCK(bmp);
@@ -2316,7 +2423,7 @@ static int dbFreeBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
/* update the free count for this dmap.
*/
- dp->nfree = cpu_to_le32(le32_to_cpu(dp->nfree) + nblocks);
+ le32_add_cpu(&dp->nfree, nblocks);
BMAP_LOCK(bmp);
@@ -2417,8 +2524,7 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level)
dcp = (struct dmapctl *) mp->data;
if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) {
- jfs_error(bmp->db_ipbmap->i_sb,
- "dbAdjCtl: Corrupt dmapctl page");
+ jfs_error(bmp->db_ipbmap->i_sb, "Corrupt dmapctl page\n");
release_metapage(mp);
return -EIO;
}
@@ -2437,7 +2543,7 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level)
/* check if this is a control page update for an allocation.
* if so, update the leaf to reflect the new leaf value using
- * dbSplit(); otherwise (deallocation), use dbJoin() to udpate
+ * dbSplit(); otherwise (deallocation), use dbJoin() to update
* the leaf with the new value. in addition to updating the
* leaf, dbSplit() will also split the binary buddy system of
* the leaves, if required, and bubble new values within the
@@ -2519,8 +2625,7 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level)
assert(level == bmp->db_maxlevel);
if (bmp->db_maxfreebud != oldroot) {
jfs_error(bmp->db_ipbmap->i_sb,
- "dbAdjCtl: the maximum free buddy is "
- "not the old root");
+ "the maximum free buddy is not the old root\n");
}
bmp->db_maxfreebud = dcp->stree[ROOT];
}
@@ -2743,7 +2848,7 @@ static int dbJoin(dmtree_t * tp, int leafno, int newval)
/* check which (leafno or buddy) is the left buddy.
* the left buddy gets to claim the blocks resulting
* from the join while the right gets to claim none.
- * the left buddy is also eligable to participate in
+ * the left buddy is also eligible to participate in
* a join at the next higher level while the right
* is not.
*
@@ -3160,7 +3265,7 @@ static int dbAllocDmapBU(struct bmap * bmp, struct dmap * dp, s64 blkno,
{
int rc;
int dbitno, word, rembits, nb, nwords, wbitno, agno;
- s8 oldroot, *leaf;
+ s8 oldroot;
struct dmaptree *tp = (struct dmaptree *) & dp->tree;
/* save the current value of the root (i.e. maximum free string)
@@ -3168,9 +3273,6 @@ static int dbAllocDmapBU(struct bmap * bmp, struct dmap * dp, s64 blkno,
*/
oldroot = tp->stree[ROOT];
- /* pick up a pointer to the leaves of the dmap tree */
- leaf = tp->stree + LEAFIND;
-
/* determine the bit number and word within the dmap of the
* starting block.
*/
@@ -3226,7 +3328,7 @@ static int dbAllocDmapBU(struct bmap * bmp, struct dmap * dp, s64 blkno,
}
/* update the free count for this dmap */
- dp->nfree = cpu_to_le32(le32_to_cpu(dp->nfree) - nblocks);
+ le32_add_cpu(&dp->nfree, -nblocks);
/* reconstruct summary tree */
dbInitDmapTree(dp);
@@ -3337,7 +3439,7 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks)
for (i = 0, n = 0; i < agno; n++) {
bmp->db_agfree[n] = 0; /* init collection point */
- /* coalesce cotiguous k AGs; */
+ /* coalesce contiguous k AGs; */
for (j = 0; j < k && i < agno; j++, i++) {
/* merge AGi to AGn */
bmp->db_agfree[n] += bmp->db_agfree[i];
@@ -3365,7 +3467,7 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks)
p = BMAPBLKNO + nbperpage; /* L2 page */
l2mp = read_metapage(ipbmap, p, PSIZE, 0);
if (!l2mp) {
- jfs_error(ipbmap->i_sb, "dbExtendFS: L2 page could not be read");
+ jfs_error(ipbmap->i_sb, "L2 page could not be read\n");
return -EIO;
}
l2dcp = (struct dmapctl *) l2mp->data;
@@ -3462,7 +3564,7 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks)
if (mp == NULL)
goto errout;
- n = min(nblocks, (s64)BPERDMAP);
+ n = min_t(s64, nblocks, BPERDMAP);
}
dp = (struct dmap *) mp->data;
@@ -3530,8 +3632,7 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks)
}
} /* for each L1 in a L2 */
- jfs_error(ipbmap->i_sb,
- "dbExtendFS: function has not returned as expected");
+ jfs_error(ipbmap->i_sb, "function has not returned as expected\n");
errout:
if (l0mp)
release_metapage(l0mp);
@@ -3601,12 +3702,12 @@ void dbFinalizeBmap(struct inode *ipbmap)
}
if (bmp->db_agpref >= bmp->db_numag) {
jfs_error(ipbmap->i_sb,
- "cannot find ag with average freespace");
+ "cannot find ag with average freespace\n");
}
}
/*
- * compute db_aglevel, db_agheigth, db_width, db_agstart:
+ * compute db_aglevel, db_agheight, db_width, db_agstart:
* an ag is covered in aglevel dmapctl summary tree,
* at agheight level height (from leaf) with agwidth number of nodes
* each, which starts at agstart index node of the smmary tree node
@@ -3615,9 +3716,9 @@ void dbFinalizeBmap(struct inode *ipbmap)
bmp->db_aglevel = BMAPSZTOLEV(bmp->db_agsize);
l2nl =
bmp->db_agl2size - (L2BPERDMAP + bmp->db_aglevel * L2LPERCTL);
- bmp->db_agheigth = l2nl >> 1;
- bmp->db_agwidth = 1 << (l2nl - (bmp->db_agheigth << 1));
- for (i = 5 - bmp->db_agheigth, bmp->db_agstart = 0, n = 1; i > 0;
+ bmp->db_agheight = l2nl >> 1;
+ bmp->db_agwidth = 1 << (l2nl - (bmp->db_agheight << 1));
+ for (i = 5 - bmp->db_agheight, bmp->db_agstart = 0, n = 1; i > 0;
i--) {
bmp->db_agstart += n;
n <<= 2;
@@ -3660,9 +3761,8 @@ static int dbInitDmap(struct dmap * dp, s64 Blkno, int nblocks)
goto initTree;
}
} else {
- dp->nblocks =
- cpu_to_le32(le32_to_cpu(dp->nblocks) + nblocks);
- dp->nfree = cpu_to_le32(le32_to_cpu(dp->nfree) + nblocks);
+ le32_add_cpu(&dp->nblocks, nblocks);
+ le32_add_cpu(&dp->nfree, nblocks);
}
/* word number containing start block number */
diff --git a/fs/jfs/jfs_dmap.h b/fs/jfs/jfs_dmap.h
index 11e6d471b36..562b9a7e431 100644
--- a/fs/jfs/jfs_dmap.h
+++ b/fs/jfs/jfs_dmap.h
@@ -61,7 +61,7 @@
* determine the maximum free string for four (lower level) nodes
* of the tree.
*/
-static __inline signed char TREEMAX(signed char *cp)
+static inline signed char TREEMAX(signed char *cp)
{
signed char tmp1, tmp2;
@@ -210,7 +210,7 @@ struct dbmap_disk {
__le32 dn_maxag; /* 4: max active alloc group number */
__le32 dn_agpref; /* 4: preferred alloc group (hint) */
__le32 dn_aglevel; /* 4: dmapctl level holding the AG */
- __le32 dn_agheigth; /* 4: height in dmapctl of the AG */
+ __le32 dn_agheight; /* 4: height in dmapctl of the AG */
__le32 dn_agwidth; /* 4: width in dmapctl of the AG */
__le32 dn_agstart; /* 4: start tree index at AG height */
__le32 dn_agl2size; /* 4: l2 num of blks per alloc group */
@@ -229,7 +229,7 @@ struct dbmap {
int dn_maxag; /* max active alloc group number */
int dn_agpref; /* preferred alloc group (hint) */
int dn_aglevel; /* dmapctl level holding the AG */
- int dn_agheigth; /* height in dmapctl of the AG */
+ int dn_agheight; /* height in dmapctl of the AG */
int dn_agwidth; /* width in dmapctl of the AG */
int dn_agstart; /* start tree index at AG height */
int dn_agl2size; /* l2 num of blks per alloc group */
@@ -255,7 +255,7 @@ struct bmap {
#define db_agsize db_bmap.dn_agsize
#define db_agl2size db_bmap.dn_agl2size
#define db_agwidth db_bmap.dn_agwidth
-#define db_agheigth db_bmap.dn_agheigth
+#define db_agheight db_bmap.dn_agheight
#define db_agstart db_bmap.dn_agstart
#define db_numag db_bmap.dn_numag
#define db_maxlevel db_bmap.dn_maxlevel
@@ -311,4 +311,6 @@ extern int dbAllocBottomUp(struct inode *ip, s64 blkno, s64 nblocks);
extern int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks);
extern void dbFinalizeBmap(struct inode *ipbmap);
extern s64 dbMapFileSizeToMapSize(struct inode *ipbmap);
+extern s64 dbDiscardAG(struct inode *ip, int agno, s64 minlen);
+
#endif /* _H_JFS_DMAP */
diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c
index 4dcc0581999..984c2bbf4f6 100644
--- a/fs/jfs/jfs_dtree.c
+++ b/fs/jfs/jfs_dtree.c
@@ -102,6 +102,7 @@
#include <linux/fs.h>
#include <linux/quotaops.h>
+#include <linux/slab.h>
#include "jfs_incore.h"
#include "jfs_superblock.h"
#include "jfs_filsys.h"
@@ -123,21 +124,21 @@ struct dtsplit {
#define DT_PAGE(IP, MP) BT_PAGE(IP, MP, dtpage_t, i_dtroot)
/* get page buffer for specified block address */
-#define DT_GETPAGE(IP, BN, MP, SIZE, P, RC)\
-{\
- BT_GETPAGE(IP, BN, MP, dtpage_t, SIZE, P, RC, i_dtroot)\
- if (!(RC))\
- {\
- if (((P)->header.nextindex > (((BN)==0)?DTROOTMAXSLOT:(P)->header.maxslot)) ||\
- ((BN) && ((P)->header.maxslot > DTPAGEMAXSLOT)))\
- {\
- BT_PUTPAGE(MP);\
- jfs_error((IP)->i_sb, "DT_GETPAGE: dtree page corrupt");\
- MP = NULL;\
- RC = -EIO;\
- }\
- }\
-}
+#define DT_GETPAGE(IP, BN, MP, SIZE, P, RC) \
+do { \
+ BT_GETPAGE(IP, BN, MP, dtpage_t, SIZE, P, RC, i_dtroot); \
+ if (!(RC)) { \
+ if (((P)->header.nextindex > \
+ (((BN) == 0) ? DTROOTMAXSLOT : (P)->header.maxslot)) || \
+ ((BN) && ((P)->header.maxslot > DTPAGEMAXSLOT))) { \
+ BT_PUTPAGE(MP); \
+ jfs_error((IP)->i_sb, \
+ "DT_GETPAGE: dtree page corrupt\n"); \
+ MP = NULL; \
+ RC = -EIO; \
+ } \
+ } \
+} while (0)
/* for consistency */
#define DT_PUTPAGE(MP) BT_PUTPAGE(MP)
@@ -381,10 +382,10 @@ static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot)
* It's time to move the inline table to an external
* page and begin to build the xtree
*/
- if (DQUOT_ALLOC_BLOCK(ip, sbi->nbperpage))
+ if (dquot_alloc_block(ip, sbi->nbperpage))
goto clean_up;
if (dbAlloc(ip, 0, sbi->nbperpage, &xaddr)) {
- DQUOT_FREE_BLOCK(ip, sbi->nbperpage);
+ dquot_free_block(ip, sbi->nbperpage);
goto clean_up;
}
@@ -408,7 +409,7 @@ static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot)
memcpy(&jfs_ip->i_dirtable, temp_table,
sizeof (temp_table));
dbFree(ip, xaddr, sbi->nbperpage);
- DQUOT_FREE_BLOCK(ip, sbi->nbperpage);
+ dquot_free_block(ip, sbi->nbperpage);
goto clean_up;
}
ip->i_size = PSIZE;
@@ -775,7 +776,7 @@ int dtSearch(struct inode *ip, struct component_name * key, ino_t * data,
/* Something's corrupted, mark filesystem dirty so
* chkdsk will fix it.
*/
- jfs_error(sb, "stack overrun in dtSearch!");
+ jfs_error(sb, "stack overrun!\n");
BT_STACK_DUMP(btstack);
rc = -EIO;
goto out;
@@ -1027,10 +1028,9 @@ static int dtSplitUp(tid_t tid,
n = xlen;
/* Allocate blocks to quota. */
- if (DQUOT_ALLOC_BLOCK(ip, n)) {
- rc = -EDQUOT;
+ rc = dquot_alloc_block(ip, n);
+ if (rc)
goto extendOut;
- }
quota_allocation += n;
if ((rc = dbReAlloc(sbi->ipbmap, xaddr, (s64) xlen,
@@ -1308,7 +1308,7 @@ static int dtSplitUp(tid_t tid,
/* Rollback quota allocation */
if (rc && quota_allocation)
- DQUOT_FREE_BLOCK(ip, quota_allocation);
+ dquot_free_block(ip, quota_allocation);
dtSplitUp_Exit:
@@ -1369,9 +1369,10 @@ static int dtSplitPage(tid_t tid, struct inode *ip, struct dtsplit * split,
return -EIO;
/* Allocate blocks to quota. */
- if (DQUOT_ALLOC_BLOCK(ip, lengthPXD(pxd))) {
+ rc = dquot_alloc_block(ip, lengthPXD(pxd));
+ if (rc) {
release_metapage(rmp);
- return -EDQUOT;
+ return rc;
}
jfs_info("dtSplitPage: ip:0x%p smp:0x%p rmp:0x%p", ip, smp, rmp);
@@ -1892,6 +1893,7 @@ static int dtSplitRoot(tid_t tid,
struct dt_lock *dtlck;
struct tlock *tlck;
struct lv *lv;
+ int rc;
/* get split root page */
smp = split->mp;
@@ -1916,9 +1918,10 @@ static int dtSplitRoot(tid_t tid,
rp = rmp->data;
/* Allocate blocks to quota. */
- if (DQUOT_ALLOC_BLOCK(ip, lengthPXD(pxd))) {
+ rc = dquot_alloc_block(ip, lengthPXD(pxd));
+ if (rc) {
release_metapage(rmp);
- return -EDQUOT;
+ return rc;
}
BT_MARK_DIRTY(rmp, ip);
@@ -2287,7 +2290,7 @@ static int dtDeleteUp(tid_t tid, struct inode *ip,
xlen = lengthPXD(&fp->header.self);
/* Free quota allocation. */
- DQUOT_FREE_BLOCK(ip, xlen);
+ dquot_free_block(ip, xlen);
/* free/invalidate its buffer page */
discard_metapage(fmp);
@@ -2363,7 +2366,7 @@ static int dtDeleteUp(tid_t tid, struct inode *ip,
xlen = lengthPXD(&p->header.self);
/* Free quota allocation */
- DQUOT_FREE_BLOCK(ip, xlen);
+ dquot_free_block(ip, xlen);
/* free/invalidate its buffer page */
discard_metapage(mp);
@@ -2999,9 +3002,9 @@ static inline struct jfs_dirent *next_jfs_dirent(struct jfs_dirent *dirent)
* return: offset = (pn, index) of start entry
* of next jfs_readdir()/dtRead()
*/
-int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
+int jfs_readdir(struct file *file, struct dir_context *ctx)
{
- struct inode *ip = filp->f_path.dentry->d_inode;
+ struct inode *ip = file_inode(file);
struct nls_table *codepage = JFS_SBI(ip->i_sb)->nls_tab;
int rc = 0;
loff_t dtpos; /* legacy OS/2 style position */
@@ -3030,7 +3033,7 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
int overflow, fix_page, page_fixed = 0;
static int unique_pos = 2; /* If we can't fix broken index */
- if (filp->f_pos == DIREND)
+ if (ctx->pos == DIREND)
return 0;
if (DO_INDEX(ip)) {
@@ -3042,7 +3045,15 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
*/
do_index = 1;
- dir_index = (u32) filp->f_pos;
+ dir_index = (u32) ctx->pos;
+
+ /*
+ * NFSv4 reserves cookies 1 and 2 for . and .. so the value
+ * we return to the vfs is one greater than the one we use
+ * internally.
+ */
+ if (dir_index)
+ dir_index--;
if (dir_index > 1) {
struct dir_table_slot dirtab_slot;
@@ -3050,25 +3061,25 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (dtEmpty(ip) ||
(dir_index >= JFS_IP(ip)->next_index)) {
/* Stale position. Directory has shrunk */
- filp->f_pos = DIREND;
+ ctx->pos = DIREND;
return 0;
}
repeat:
rc = read_index(ip, dir_index, &dirtab_slot);
if (rc) {
- filp->f_pos = DIREND;
+ ctx->pos = DIREND;
return rc;
}
if (dirtab_slot.flag == DIR_INDEX_FREE) {
if (loop_count++ > JFS_IP(ip)->next_index) {
jfs_err("jfs_readdir detected "
"infinite loop!");
- filp->f_pos = DIREND;
+ ctx->pos = DIREND;
return 0;
}
dir_index = le32_to_cpu(dirtab_slot.addr2);
if (dir_index == -1) {
- filp->f_pos = DIREND;
+ ctx->pos = DIREND;
return 0;
}
goto repeat;
@@ -3077,13 +3088,13 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
index = dirtab_slot.slot;
DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
if (rc) {
- filp->f_pos = DIREND;
+ ctx->pos = DIREND;
return 0;
}
if (p->header.flag & BT_INTERNAL) {
jfs_err("jfs_readdir: bad index table");
DT_PUTPAGE(mp);
- filp->f_pos = -1;
+ ctx->pos = DIREND;
return 0;
}
} else {
@@ -3091,23 +3102,22 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
/*
* self "."
*/
- filp->f_pos = 0;
- if (filldir(dirent, ".", 1, 0, ip->i_ino,
- DT_DIR))
+ ctx->pos = 1;
+ if (!dir_emit(ctx, ".", 1, ip->i_ino, DT_DIR))
return 0;
}
/*
* parent ".."
*/
- filp->f_pos = 1;
- if (filldir(dirent, "..", 2, 1, PARENT(ip), DT_DIR))
+ ctx->pos = 2;
+ if (!dir_emit(ctx, "..", 2, PARENT(ip), DT_DIR))
return 0;
/*
* Find first entry of left-most leaf
*/
if (dtEmpty(ip)) {
- filp->f_pos = DIREND;
+ ctx->pos = DIREND;
return 0;
}
@@ -3120,28 +3130,25 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
/*
* Legacy filesystem - OS/2 & Linux JFS < 0.3.6
*
- * pn = index = 0: First entry "."
- * pn = 0; index = 1: Second entry ".."
+ * pn = 0; index = 1: First entry "."
+ * pn = 0; index = 2: Second entry ".."
* pn > 0: Real entries, pn=1 -> leftmost page
* pn = index = -1: No more entries
*/
- dtpos = filp->f_pos;
- if (dtpos == 0) {
+ dtpos = ctx->pos;
+ if (dtpos < 2) {
/* build "." entry */
-
- if (filldir(dirent, ".", 1, filp->f_pos, ip->i_ino,
- DT_DIR))
+ ctx->pos = 1;
+ if (!dir_emit(ctx, ".", 1, ip->i_ino, DT_DIR))
return 0;
- dtoffset->index = 1;
- filp->f_pos = dtpos;
+ dtoffset->index = 2;
+ ctx->pos = dtpos;
}
if (dtoffset->pn == 0) {
- if (dtoffset->index == 1) {
+ if (dtoffset->index == 2) {
/* build ".." entry */
-
- if (filldir(dirent, "..", 2, filp->f_pos,
- PARENT(ip), DT_DIR))
+ if (!dir_emit(ctx, "..", 2, PARENT(ip), DT_DIR))
return 0;
} else {
jfs_err("jfs_readdir called with "
@@ -3149,18 +3156,18 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
}
dtoffset->pn = 1;
dtoffset->index = 0;
- filp->f_pos = dtpos;
+ ctx->pos = dtpos;
}
if (dtEmpty(ip)) {
- filp->f_pos = DIREND;
+ ctx->pos = DIREND;
return 0;
}
- if ((rc = dtReadNext(ip, &filp->f_pos, &btstack))) {
+ if ((rc = dtReadNext(ip, &ctx->pos, &btstack))) {
jfs_err("jfs_readdir: unexpected rc = %d "
"from dtReadNext", rc);
- filp->f_pos = DIREND;
+ ctx->pos = DIREND;
return 0;
}
/* get start leaf page and index */
@@ -3168,7 +3175,7 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
/* offset beyond directory eof ? */
if (bn < 0) {
- filp->f_pos = DIREND;
+ ctx->pos = DIREND;
return 0;
}
}
@@ -3177,7 +3184,7 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (dirent_buf == 0) {
DT_PUTPAGE(mp);
jfs_warn("jfs_readdir: __get_free_page failed!");
- filp->f_pos = DIREND;
+ ctx->pos = DIREND;
return -ENOMEM;
}
@@ -3230,6 +3237,12 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
}
jfs_dirent->position = unique_pos++;
}
+ /*
+ * We add 1 to the index because we may
+ * use a value of 2 internally, and NFSv4
+ * doesn't like that.
+ */
+ jfs_dirent->position++;
} else {
jfs_dirent->position = dtpos;
len = min(d_namleft, DTLHDRDATALEN_LEGACY);
@@ -3249,8 +3262,7 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
/* Sanity Check */
if (d_namleft == 0) {
jfs_error(ip->i_sb,
- "JFS:Dtree error: ino = "
- "%ld, bn=%Ld, index = %d",
+ "JFS:Dtree error: ino = %ld, bn=%lld, index = %d\n",
(long)ip->i_ino,
(long long)bn,
i);
@@ -3292,9 +3304,9 @@ skip_one:
jfs_dirent = (struct jfs_dirent *) dirent_buf;
while (jfs_dirents--) {
- filp->f_pos = jfs_dirent->position;
- if (filldir(dirent, jfs_dirent->name,
- jfs_dirent->name_len, filp->f_pos,
+ ctx->pos = jfs_dirent->position;
+ if (!dir_emit(ctx, jfs_dirent->name,
+ jfs_dirent->name_len,
jfs_dirent->ino, DT_UNKNOWN))
goto out;
jfs_dirent = next_jfs_dirent(jfs_dirent);
@@ -3306,7 +3318,7 @@ skip_one:
}
if (!overflow && (bn == 0)) {
- filp->f_pos = DIREND;
+ ctx->pos = DIREND;
break;
}
@@ -3370,7 +3382,7 @@ static int dtReadFirst(struct inode *ip, struct btstack * btstack)
*/
if (BT_STACK_FULL(btstack)) {
DT_PUTPAGE(mp);
- jfs_error(ip->i_sb, "dtReadFirst: btstack overrun");
+ jfs_error(ip->i_sb, "btstack overrun\n");
BT_STACK_DUMP(btstack);
return -EIO;
}
diff --git a/fs/jfs/jfs_dtree.h b/fs/jfs/jfs_dtree.h
index cdac2d5bafe..fd4169e6e69 100644
--- a/fs/jfs/jfs_dtree.h
+++ b/fs/jfs/jfs_dtree.h
@@ -243,9 +243,6 @@ typedef union {
#define JFS_REMOVE 3
#define JFS_RENAME 4
-#define DIRENTSIZ(namlen) \
- ( (sizeof(struct dirent) - 2*(JFS_NAME_MAX+1) + 2*((namlen)+1) + 3) &~ 3 )
-
/*
* Maximum file offset for directories.
*/
@@ -268,5 +265,5 @@ extern int dtDelete(tid_t tid, struct inode *ip, struct component_name * key,
extern int dtModify(tid_t tid, struct inode *ip, struct component_name * key,
ino_t * orig_ino, ino_t new_ino, int flag);
-extern int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir);
+extern int jfs_readdir(struct file *file, struct dir_context *ctx);
#endif /* !_H_JFS_DTREE */
diff --git a/fs/jfs/jfs_extent.c b/fs/jfs/jfs_extent.c
index 7ae1e3281de..2ae7d59ab10 100644
--- a/fs/jfs/jfs_extent.c
+++ b/fs/jfs/jfs_extent.c
@@ -126,7 +126,7 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, bool abnr)
/* allocate the disk blocks for the extent. initially, extBalloc()
* will try to allocate disk blocks for the requested size (xlen).
- * if this fails (xlen contiguous free blocks not avaliable), it'll
+ * if this fails (xlen contiguous free blocks not available), it'll
* try to allocate a smaller number of blocks (producing a smaller
* extent), with this smaller number of blocks consisting of the
* requested number of blocks rounded down to the next smaller
@@ -141,10 +141,11 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, bool abnr)
}
/* Allocate blocks to quota. */
- if (DQUOT_ALLOC_BLOCK(ip, nxlen)) {
+ rc = dquot_alloc_block(ip, nxlen);
+ if (rc) {
dbFree(ip, nxaddr, (s64) nxlen);
mutex_unlock(&JFS_IP(ip)->commit_mutex);
- return -EDQUOT;
+ return rc;
}
/* determine the value of the extent flag */
@@ -164,7 +165,7 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, bool abnr)
*/
if (rc) {
dbFree(ip, nxaddr, nxlen);
- DQUOT_FREE_BLOCK(ip, nxlen);
+ dquot_free_block(ip, nxlen);
mutex_unlock(&JFS_IP(ip)->commit_mutex);
return (rc);
}
@@ -256,10 +257,11 @@ int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, bool abnr)
goto exit;
/* Allocat blocks to quota. */
- if (DQUOT_ALLOC_BLOCK(ip, nxlen)) {
+ rc = dquot_alloc_block(ip, nxlen);
+ if (rc) {
dbFree(ip, nxaddr, (s64) nxlen);
mutex_unlock(&JFS_IP(ip)->commit_mutex);
- return -EDQUOT;
+ return rc;
}
delta = nxlen - xlen;
@@ -297,7 +299,7 @@ int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, bool abnr)
/* extend the extent */
if ((rc = xtExtend(0, ip, xoff + xlen, (int) nextend, 0))) {
dbFree(ip, xaddr + xlen, delta);
- DQUOT_FREE_BLOCK(ip, nxlen);
+ dquot_free_block(ip, nxlen);
goto exit;
}
} else {
@@ -308,7 +310,7 @@ int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, bool abnr)
*/
if ((rc = xtTailgate(0, ip, xoff, (int) ntail, nxaddr, 0))) {
dbFree(ip, nxaddr, nxlen);
- DQUOT_FREE_BLOCK(ip, nxlen);
+ dquot_free_block(ip, nxlen);
goto exit;
}
}
@@ -362,11 +364,12 @@ exit:
int extHint(struct inode *ip, s64 offset, xad_t * xp)
{
struct super_block *sb = ip->i_sb;
- struct xadlist xadl;
- struct lxdlist lxdl;
- lxd_t lxd;
+ int nbperpage = JFS_SBI(sb)->nbperpage;
s64 prev;
- int rc, nbperpage = JFS_SBI(sb)->nbperpage;
+ int rc = 0;
+ s64 xaddr;
+ int xlen;
+ int xflag;
/* init the hint as "no hint provided" */
XADaddress(xp, 0);
@@ -376,46 +379,31 @@ int extHint(struct inode *ip, s64 offset, xad_t * xp)
*/
prev = ((offset & ~POFFSET) >> JFS_SBI(sb)->l2bsize) - nbperpage;
- /* if the offsets in the first page of the file,
- * no hint provided.
+ /* if the offset is in the first page of the file, no hint provided.
*/
if (prev < 0)
- return (0);
-
- /* prepare to lookup the previous page's extent info */
- lxdl.maxnlxd = 1;
- lxdl.nlxd = 1;
- lxdl.lxd = &lxd;
- LXDoffset(&lxd, prev)
- LXDlength(&lxd, nbperpage);
-
- xadl.maxnxad = 1;
- xadl.nxad = 0;
- xadl.xad = xp;
-
- /* perform the lookup */
- if ((rc = xtLookupList(ip, &lxdl, &xadl, 0)))
- return (rc);
-
- /* check if no extent exists for the previous page.
- * this is possible for sparse files.
- */
- if (xadl.nxad == 0) {
-// assert(ISSPARSE(ip));
- return (0);
- }
+ goto out;
- /* only preserve the abnr flag within the xad flags
- * of the returned hint.
- */
- xp->flag &= XAD_NOTRECORDED;
+ rc = xtLookup(ip, prev, nbperpage, &xflag, &xaddr, &xlen, 0);
- if(xadl.nxad != 1 || lengthXAD(xp) != nbperpage) {
- jfs_error(ip->i_sb, "extHint: corrupt xtree");
- return -EIO;
- }
+ if ((rc == 0) && xlen) {
+ if (xlen != nbperpage) {
+ jfs_error(ip->i_sb, "corrupt xtree\n");
+ rc = -EIO;
+ }
+ XADaddress(xp, xaddr);
+ XADlength(xp, xlen);
+ XADoffset(xp, prev);
+ /*
+ * only preserve the abnr flag within the xad flags
+ * of the returned hint.
+ */
+ xp->flag = xflag & XAD_NOTRECORDED;
+ } else
+ rc = 0;
- return (0);
+out:
+ return (rc);
}
@@ -493,7 +481,7 @@ int extFill(struct inode *ip, xad_t * xp)
*
* initially, we will try to allocate disk blocks for the
* requested size (nblocks). if this fails (nblocks
- * contiguous free blocks not avaliable), we'll try to allocate
+ * contiguous free blocks not available), we'll try to allocate
* a smaller number of blocks (producing a smaller extent), with
* this smaller number of blocks consisting of the requested
* number of blocks rounded down to the next smaller power of 2
@@ -587,7 +575,7 @@ extBalloc(struct inode *ip, s64 hint, s64 * nblocks, s64 * blkno)
* to a new set of blocks. If moving the extent, we initially
* will try to allocate disk blocks for the requested size
* (newnblks). if this fails (new contiguous free blocks not
- * avaliable), we'll try to allocate a smaller number of
+ * available), we'll try to allocate a smaller number of
* blocks (producing a smaller extent), with this smaller
* number of blocks consisting of the requested number of
* blocks rounded down to the next smaller power of 2
diff --git a/fs/jfs/jfs_filsys.h b/fs/jfs/jfs_filsys.h
index b3f5463fbe5..b67d64671bb 100644
--- a/fs/jfs/jfs_filsys.h
+++ b/fs/jfs/jfs_filsys.h
@@ -45,6 +45,9 @@
/* mount time flag to disable journaling to disk */
#define JFS_NOINTEGRITY 0x00000040
+/* mount time flag to enable TRIM to ssd disks */
+#define JFS_DISCARD 0x00000080
+
/* commit option */
#define JFS_COMMIT 0x00000f00 /* commit option mask */
#define JFS_GROUPCOMMIT 0x00000100 /* group (of 1) commit */
diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c
index 9bf29f77173..f321986e73d 100644
--- a/fs/jfs/jfs_imap.c
+++ b/fs/jfs/jfs_imap.c
@@ -45,6 +45,7 @@
#include <linux/buffer_head.h>
#include <linux/pagemap.h>
#include <linux/quotaops.h>
+#include <linux/slab.h>
#include "jfs_incore.h"
#include "jfs_inode.h"
@@ -57,12 +58,6 @@
#include "jfs_debug.h"
/*
- * __mark_inode_dirty expects inodes to be hashed. Since we don't want
- * special inodes in the fileset inode space, we hash them to a dummy head
- */
-static HLIST_HEAD(aggregate_hash);
-
-/*
* imap locks
*/
/* iag free list lock */
@@ -391,7 +386,7 @@ int diRead(struct inode *ip)
dp += rel_inode;
if (ip->i_ino != le32_to_cpu(dp->di_number)) {
- jfs_error(ip->i_sb, "diRead: i_ino != di_number");
+ jfs_error(ip->i_sb, "i_ino != di_number\n");
rc = -EIO;
} else if (le32_to_cpu(dp->di_nlink) == 0)
rc = -ESTALE;
@@ -402,7 +397,7 @@ int diRead(struct inode *ip)
release_metapage(mp);
/* set the ag for the inode */
- JFS_IP(ip)->agno = BLKTOAG(agstart, sbi);
+ JFS_IP(ip)->agstart = agstart;
JFS_IP(ip)->active_ag = -1;
return (rc);
@@ -462,7 +457,7 @@ struct inode *diReadSpecial(struct super_block *sb, ino_t inum, int secondary)
/* read the page of fixed disk inode (AIT) in raw mode */
mp = read_metapage(ip, address << sbi->l2nbperpage, PSIZE, 1);
if (mp == NULL) {
- ip->i_nlink = 1; /* Don't want iput() deleting it */
+ set_nlink(ip, 1); /* Don't want iput() deleting it */
iput(ip);
return (NULL);
}
@@ -474,7 +469,7 @@ struct inode *diReadSpecial(struct super_block *sb, ino_t inum, int secondary)
/* copy on-disk inode to in-memory inode */
if ((copy_from_dinode(dp, ip)) != 0) {
/* handle bad return by returning NULL for ip */
- ip->i_nlink = 1; /* Don't want iput() deleting it */
+ set_nlink(ip, 1); /* Don't want iput() deleting it */
iput(ip);
/* release the page */
release_metapage(mp);
@@ -496,7 +491,13 @@ struct inode *diReadSpecial(struct super_block *sb, ino_t inum, int secondary)
/* release the page */
release_metapage(mp);
- hlist_add_head(&ip->i_hash, &aggregate_hash);
+ /*
+ * __mark_inode_dirty expects inodes to be hashed. Since we don't
+ * want special inodes in the fileset inode space, we make them
+ * appear hashed, but do not put on any lists. hlist_del()
+ * will work fine and require no locking.
+ */
+ hlist_add_fake(&ip->i_hash);
return (ip);
}
@@ -624,7 +625,7 @@ int diWrite(tid_t tid, struct inode *ip)
if (!addressPXD(&(jfs_ip->ixpxd)) ||
(lengthPXD(&(jfs_ip->ixpxd)) !=
JFS_IP(ipimap)->i_imap->im_nbperiext)) {
- jfs_error(ip->i_sb, "diWrite: ixpxd invalid");
+ jfs_error(ip->i_sb, "ixpxd invalid\n");
return -EIO;
}
@@ -892,15 +893,14 @@ int diFree(struct inode *ip)
if (iagno >= imap->im_nextiag) {
print_hex_dump(KERN_ERR, "imap: ", DUMP_PREFIX_ADDRESS, 16, 4,
imap, 32, 0);
- jfs_error(ip->i_sb,
- "diFree: inum = %d, iagno = %d, nextiag = %d",
+ jfs_error(ip->i_sb, "inum = %d, iagno = %d, nextiag = %d\n",
(uint) inum, iagno, imap->im_nextiag);
return -EIO;
}
/* get the allocation group for this ino.
*/
- agno = JFS_IP(ip)->agno;
+ agno = BLKTOAG(JFS_IP(ip)->agstart, JFS_SBI(ip->i_sb));
/* Lock the AG specific inode map information
*/
@@ -929,15 +929,14 @@ int diFree(struct inode *ip)
mask = HIGHORDER >> bitno;
if (!(le32_to_cpu(iagp->wmap[extno]) & mask)) {
- jfs_error(ip->i_sb,
- "diFree: wmap shows inode already free");
+ jfs_error(ip->i_sb, "wmap shows inode already free\n");
}
if (!addressPXD(&iagp->inoext[extno])) {
release_metapage(mp);
IREAD_UNLOCK(ipimap);
AG_UNLOCK(imap, agno);
- jfs_error(ip->i_sb, "diFree: invalid inoext");
+ jfs_error(ip->i_sb, "invalid inoext\n");
return -EIO;
}
@@ -949,7 +948,7 @@ int diFree(struct inode *ip)
release_metapage(mp);
IREAD_UNLOCK(ipimap);
AG_UNLOCK(imap, agno);
- jfs_error(ip->i_sb, "diFree: numfree > numinos");
+ jfs_error(ip->i_sb, "numfree > numinos\n");
return -EIO;
}
/*
@@ -1019,8 +1018,7 @@ int diFree(struct inode *ip)
/* update the free inode counts at the iag, ag and
* map level.
*/
- iagp->nfreeinos =
- cpu_to_le32(le32_to_cpu(iagp->nfreeinos) + 1);
+ le32_add_cpu(&iagp->nfreeinos, 1);
imap->im_agctl[agno].numfree += 1;
atomic_inc(&imap->im_numfree);
@@ -1069,7 +1067,7 @@ int diFree(struct inode *ip)
*/
if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG - 1)) {
/* in preparation for removing the iag from the
- * ag extent free list, read the iags preceeding
+ * ag extent free list, read the iags preceding
* and following the iag on the ag extent free
* list.
*/
@@ -1095,7 +1093,7 @@ int diFree(struct inode *ip)
int inofreefwd = le32_to_cpu(iagp->inofreefwd);
/* in preparation for removing the iag from the
- * ag inode free list, read the iags preceeding
+ * ag inode free list, read the iags preceding
* and following the iag on the ag inode free
* list. before reading these iags, we must make
* sure that we already don't have them in hand
@@ -1199,7 +1197,7 @@ int diFree(struct inode *ip)
* for the inode being freed.
*/
if (iagp->pmap[extno] != 0) {
- jfs_error(ip->i_sb, "diFree: the pmap does not show inode free");
+ jfs_error(ip->i_sb, "the pmap does not show inode free\n");
}
iagp->wmap[extno] = 0;
PXDlength(&iagp->inoext[extno], 0);
@@ -1219,9 +1217,8 @@ int diFree(struct inode *ip)
/* update the number of free inodes and number of free extents
* for the iag.
*/
- iagp->nfreeinos = cpu_to_le32(le32_to_cpu(iagp->nfreeinos) -
- (INOSPEREXT - 1));
- iagp->nfreeexts = cpu_to_le32(le32_to_cpu(iagp->nfreeexts) + 1);
+ le32_add_cpu(&iagp->nfreeinos, -(INOSPEREXT - 1));
+ le32_add_cpu(&iagp->nfreeexts, 1);
/* update the number of free inodes and backed inodes
* at the ag and inode map level.
@@ -1316,12 +1313,11 @@ int diFree(struct inode *ip)
static inline void
diInitInode(struct inode *ip, int iagno, int ino, int extno, struct iag * iagp)
{
- struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
struct jfs_inode_info *jfs_ip = JFS_IP(ip);
ip->i_ino = (iagno << L2INOSPERIAG) + ino;
jfs_ip->ixpxd = iagp->inoext[extno];
- jfs_ip->agno = BLKTOAG(le64_to_cpu(iagp->agstart), sbi);
+ jfs_ip->agstart = le64_to_cpu(iagp->agstart);
jfs_ip->active_ag = -1;
}
@@ -1380,7 +1376,7 @@ int diAlloc(struct inode *pip, bool dir, struct inode *ip)
*/
/* get the ag number of this iag */
- agno = JFS_IP(pip)->agno;
+ agno = BLKTOAG(JFS_IP(pip)->agstart, JFS_SBI(pip->i_sb));
if (atomic_read(&JFS_SBI(pip->i_sb)->bmap->db_active[agno])) {
/*
@@ -1495,7 +1491,7 @@ int diAlloc(struct inode *pip, bool dir, struct inode *ip)
/* mask any prior bits for the starting words of the
* summary map.
*/
- mask = ONES << (EXTSPERSUM - bitno);
+ mask = (bitno == 0) ? 0 : (ONES << (EXTSPERSUM - bitno));
inosmap = le32_to_cpu(iagp->inosmap[sword]) | mask;
extsmap = le32_to_cpu(iagp->extsmap[sword]) | mask;
@@ -1520,9 +1516,8 @@ int diAlloc(struct inode *pip, bool dir, struct inode *ip)
release_metapage(mp);
AG_UNLOCK(imap, agno);
jfs_error(ip->i_sb,
- "diAlloc: can't find free bit "
- "in wmap");
- return EIO;
+ "can't find free bit in wmap\n");
+ return -EIO;
}
/* determine the inode number within the
@@ -1662,7 +1657,7 @@ diAllocAG(struct inomap * imap, int agno, bool dir, struct inode *ip)
numinos = imap->im_agctl[agno].numinos;
if (numfree > numinos) {
- jfs_error(ip->i_sb, "diAllocAG: numfree > numinos");
+ jfs_error(ip->i_sb, "numfree > numinos\n");
return -EIO;
}
@@ -1682,7 +1677,7 @@ diAllocAG(struct inomap * imap, int agno, bool dir, struct inode *ip)
* try to allocate a new extent of free inodes.
*/
if (addext) {
- /* if free space is not avaliable for this new extent, try
+ /* if free space is not available for this new extent, try
* below to allocate a free and existing (already backed)
* inode from the ag.
*/
@@ -1813,8 +1808,7 @@ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip)
if (!iagp->nfreeinos) {
IREAD_UNLOCK(imap->im_ipimap);
release_metapage(mp);
- jfs_error(ip->i_sb,
- "diAllocIno: nfreeinos = 0, but iag on freelist");
+ jfs_error(ip->i_sb, "nfreeinos = 0, but iag on freelist\n");
return -EIO;
}
@@ -1826,7 +1820,7 @@ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip)
IREAD_UNLOCK(imap->im_ipimap);
release_metapage(mp);
jfs_error(ip->i_sb,
- "diAllocIno: free inode not found in summary map");
+ "free inode not found in summary map\n");
return -EIO;
}
@@ -1841,7 +1835,7 @@ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip)
if (rem >= EXTSPERSUM) {
IREAD_UNLOCK(imap->im_ipimap);
release_metapage(mp);
- jfs_error(ip->i_sb, "diAllocIno: no free extent found");
+ jfs_error(ip->i_sb, "no free extent found\n");
return -EIO;
}
extno = (sword << L2EXTSPERSUM) + rem;
@@ -1852,7 +1846,7 @@ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip)
if (rem >= INOSPEREXT) {
IREAD_UNLOCK(imap->im_ipimap);
release_metapage(mp);
- jfs_error(ip->i_sb, "diAllocIno: free inode not found");
+ jfs_error(ip->i_sb, "free inode not found\n");
return -EIO;
}
@@ -1938,7 +1932,7 @@ static int diAllocExt(struct inomap * imap, int agno, struct inode *ip)
IREAD_LOCK(imap->im_ipimap, RDWRLOCK_IMAP);
if ((rc = diIAGRead(imap, iagno, &mp))) {
IREAD_UNLOCK(imap->im_ipimap);
- jfs_error(ip->i_sb, "diAllocExt: error reading iag");
+ jfs_error(ip->i_sb, "error reading iag\n");
return rc;
}
iagp = (struct iag *) mp->data;
@@ -1950,8 +1944,7 @@ static int diAllocExt(struct inomap * imap, int agno, struct inode *ip)
if (sword >= SMAPSZ) {
release_metapage(mp);
IREAD_UNLOCK(imap->im_ipimap);
- jfs_error(ip->i_sb,
- "diAllocExt: free ext summary map not found");
+ jfs_error(ip->i_sb, "free ext summary map not found\n");
return -EIO;
}
if (~iagp->extsmap[sword])
@@ -1964,7 +1957,7 @@ static int diAllocExt(struct inomap * imap, int agno, struct inode *ip)
if (rem >= EXTSPERSUM) {
release_metapage(mp);
IREAD_UNLOCK(imap->im_ipimap);
- jfs_error(ip->i_sb, "diAllocExt: free extent not found");
+ jfs_error(ip->i_sb, "free extent not found\n");
return -EIO;
}
extno = (sword << L2EXTSPERSUM) + rem;
@@ -2037,7 +2030,7 @@ static int diAllocBit(struct inomap * imap, struct iag * iagp, int ino)
/* check if this is the last free inode within the iag.
* if so, it will have to be removed from the ag free
- * inode list, so get the iags preceeding and following
+ * inode list, so get the iags preceding and following
* it on the list.
*/
if (iagp->nfreeinos == cpu_to_le32(1)) {
@@ -2083,8 +2076,7 @@ static int diAllocBit(struct inomap * imap, struct iag * iagp, int ino)
if (bmp)
release_metapage(bmp);
- jfs_error(imap->im_ipimap->i_sb,
- "diAllocBit: iag inconsistent");
+ jfs_error(imap->im_ipimap->i_sb, "iag inconsistent\n");
return -EIO;
}
@@ -2124,7 +2116,7 @@ static int diAllocBit(struct inomap * imap, struct iag * iagp, int ino)
/* update the free inode count at the iag, ag, inode
* map levels.
*/
- iagp->nfreeinos = cpu_to_le32(le32_to_cpu(iagp->nfreeinos) - 1);
+ le32_add_cpu(&iagp->nfreeinos, -1);
imap->im_agctl[agno].numfree -= 1;
atomic_dec(&imap->im_numfree);
@@ -2191,7 +2183,7 @@ static int diNewExt(struct inomap * imap, struct iag * iagp, int extno)
/* better have free extents.
*/
if (!iagp->nfreeexts) {
- jfs_error(imap->im_ipimap->i_sb, "diNewExt: no free extents");
+ jfs_error(imap->im_ipimap->i_sb, "no free extents\n");
return -EIO;
}
@@ -2209,7 +2201,7 @@ static int diNewExt(struct inomap * imap, struct iag * iagp, int extno)
/* check if this is the last free extent within the
* iag. if so, the iag must be removed from the ag
- * free extent list, so get the iags preceeding and
+ * free extent list, so get the iags preceding and
* following the iag on this list.
*/
if (iagp->nfreeexts == cpu_to_le32(1)) {
@@ -2263,7 +2255,7 @@ static int diNewExt(struct inomap * imap, struct iag * iagp, int extno)
}
if (ciagp == NULL) {
jfs_error(imap->im_ipimap->i_sb,
- "diNewExt: ciagp == NULL");
+ "ciagp == NULL\n");
rc = -EIO;
goto error_out;
}
@@ -2378,9 +2370,8 @@ static int diNewExt(struct inomap * imap, struct iag * iagp, int extno)
/* update the free inode and free extent counts for the
* iag.
*/
- iagp->nfreeinos = cpu_to_le32(le32_to_cpu(iagp->nfreeinos) +
- (INOSPEREXT - 1));
- iagp->nfreeexts = cpu_to_le32(le32_to_cpu(iagp->nfreeexts) - 1);
+ le32_add_cpu(&iagp->nfreeinos, (INOSPEREXT - 1));
+ le32_add_cpu(&iagp->nfreeexts, -1);
/* update the free and backed inode counts for the ag.
*/
@@ -2501,12 +2492,12 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
IWRITE_UNLOCK(ipimap);
IAGFREE_UNLOCK(imap);
jfs_error(imap->im_ipimap->i_sb,
- "diNewIAG: ipimap->i_size is wrong");
+ "ipimap->i_size is wrong\n");
return -EIO;
}
- /* get the next avaliable iag number */
+ /* get the next available iag number */
iagno = imap->im_nextiag;
/* make sure that we have not exceeded the maximum inode
@@ -2574,6 +2565,7 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
txAbort(tid, 0);
txEnd(tid);
+ mutex_unlock(&JFS_IP(ipimap)->commit_mutex);
/* release the inode map lock */
IWRITE_UNLOCK(ipimap);
@@ -2616,7 +2608,7 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
duplicateIXtree(sb, blkno, xlen, &xaddr);
- /* update the next avaliable iag number */
+ /* update the next available iag number */
imap->im_nextiag += 1;
/* Add the iag to the iag free list so we don't lose the iag
@@ -2760,8 +2752,7 @@ diUpdatePMap(struct inode *ipimap,
iagno = INOTOIAG(inum);
/* make sure that the iag is contained within the map */
if (iagno >= imap->im_nextiag) {
- jfs_error(ipimap->i_sb,
- "diUpdatePMap: the iag is outside the map");
+ jfs_error(ipimap->i_sb, "the iag is outside the map\n");
return -EIO;
}
/* read the iag */
@@ -2790,13 +2781,13 @@ diUpdatePMap(struct inode *ipimap,
*/
if (!(le32_to_cpu(iagp->wmap[extno]) & mask)) {
jfs_error(ipimap->i_sb,
- "diUpdatePMap: inode %ld not marked as "
- "allocated in wmap!", inum);
+ "inode %ld not marked as allocated in wmap!\n",
+ inum);
}
if (!(le32_to_cpu(iagp->pmap[extno]) & mask)) {
jfs_error(ipimap->i_sb,
- "diUpdatePMap: inode %ld not marked as "
- "allocated in pmap!", inum);
+ "inode %ld not marked as allocated in pmap!\n",
+ inum);
}
/* update the bitmap for the extent of the freed inode */
iagp->pmap[extno] &= cpu_to_le32(~mask);
@@ -2811,15 +2802,13 @@ diUpdatePMap(struct inode *ipimap,
if (!(le32_to_cpu(iagp->wmap[extno]) & mask)) {
release_metapage(mp);
jfs_error(ipimap->i_sb,
- "diUpdatePMap: the inode is not allocated in "
- "the working map");
+ "the inode is not allocated in the working map\n");
return -EIO;
}
if ((le32_to_cpu(iagp->pmap[extno]) & mask) != 0) {
release_metapage(mp);
jfs_error(ipimap->i_sb,
- "diUpdatePMap: the inode is not free in the "
- "persistent map");
+ "the inode is not free in the persistent map\n");
return -EIO;
}
/* update the bitmap for the extent of the allocated inode */
@@ -2911,8 +2900,7 @@ int diExtendFS(struct inode *ipimap, struct inode *ipbmap)
iagp = (struct iag *) bp->data;
if (le32_to_cpu(iagp->iagnum) != i) {
release_metapage(bp);
- jfs_error(ipimap->i_sb,
- "diExtendFs: unexpected value of iagnum");
+ jfs_error(ipimap->i_sb, "unexpected value of iagnum\n");
return -EIO;
}
@@ -2922,10 +2910,9 @@ int diExtendFS(struct inode *ipimap, struct inode *ipbmap)
continue;
}
- /* agstart that computes to the same ag is treated as same; */
agstart = le64_to_cpu(iagp->agstart);
- /* iagp->agstart = agstart & ~(mp->db_agsize - 1); */
n = agstart >> mp->db_agl2size;
+ iagp->agstart = cpu_to_le64((s64)n << mp->db_agl2size);
/* compute backed inodes */
numinos = (EXTSPERIAG - le32_to_cpu(iagp->nfreeexts))
@@ -2989,8 +2976,7 @@ int diExtendFS(struct inode *ipimap, struct inode *ipbmap)
if (xnuminos != atomic_read(&imap->im_numinos) ||
xnumfree != atomic_read(&imap->im_numfree)) {
- jfs_error(ipimap->i_sb,
- "diExtendFs: numinos or numfree incorrect");
+ jfs_error(ipimap->i_sb, "numinos or numfree incorrect\n");
return -EIO;
}
@@ -3079,17 +3065,17 @@ static int copy_from_dinode(struct dinode * dip, struct inode *ip)
ip->i_mode |= 0001;
}
}
- ip->i_nlink = le32_to_cpu(dip->di_nlink);
+ set_nlink(ip, le32_to_cpu(dip->di_nlink));
- jfs_ip->saved_uid = le32_to_cpu(dip->di_uid);
- if (sbi->uid == -1)
+ jfs_ip->saved_uid = make_kuid(&init_user_ns, le32_to_cpu(dip->di_uid));
+ if (!uid_valid(sbi->uid))
ip->i_uid = jfs_ip->saved_uid;
else {
ip->i_uid = sbi->uid;
}
- jfs_ip->saved_gid = le32_to_cpu(dip->di_gid);
- if (sbi->gid == -1)
+ jfs_ip->saved_gid = make_kgid(&init_user_ns, le32_to_cpu(dip->di_gid));
+ if (!gid_valid(sbi->gid))
ip->i_gid = jfs_ip->saved_gid;
else {
ip->i_gid = sbi->gid;
@@ -3153,14 +3139,16 @@ static void copy_to_dinode(struct dinode * dip, struct inode *ip)
dip->di_size = cpu_to_le64(ip->i_size);
dip->di_nblocks = cpu_to_le64(PBLK2LBLK(ip->i_sb, ip->i_blocks));
dip->di_nlink = cpu_to_le32(ip->i_nlink);
- if (sbi->uid == -1)
- dip->di_uid = cpu_to_le32(ip->i_uid);
+ if (!uid_valid(sbi->uid))
+ dip->di_uid = cpu_to_le32(i_uid_read(ip));
else
- dip->di_uid = cpu_to_le32(jfs_ip->saved_uid);
- if (sbi->gid == -1)
- dip->di_gid = cpu_to_le32(ip->i_gid);
+ dip->di_uid =cpu_to_le32(from_kuid(&init_user_ns,
+ jfs_ip->saved_uid));
+ if (!gid_valid(sbi->gid))
+ dip->di_gid = cpu_to_le32(i_gid_read(ip));
else
- dip->di_gid = cpu_to_le32(jfs_ip->saved_gid);
+ dip->di_gid = cpu_to_le32(from_kgid(&init_user_ns,
+ jfs_ip->saved_gid));
jfs_get_inode_flags(jfs_ip);
/*
* mode2 is only needed for storing the higher order bits.
diff --git a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h
index 439901d205f..cf47f09e8ac 100644
--- a/fs/jfs/jfs_incore.h
+++ b/fs/jfs/jfs_incore.h
@@ -38,8 +38,8 @@
struct jfs_inode_info {
int fileset; /* fileset number (always 16)*/
uint mode2; /* jfs-specific mode */
- uint saved_uid; /* saved for uid mount option */
- uint saved_gid; /* saved for gid mount option */
+ kuid_t saved_uid; /* saved for uid mount option */
+ kgid_t saved_gid; /* saved for gid mount option */
pxd_t ixpxd; /* inode extent descriptor */
dxd_t acl; /* dxd describing acl */
dxd_t ea; /* dxd describing ea */
@@ -50,8 +50,9 @@ struct jfs_inode_info {
short btindex; /* btpage entry index*/
struct inode *ipimap; /* inode map */
unsigned long cflag; /* commit flags */
+ u64 agstart; /* agstart of the containing IAG */
u16 bxflag; /* xflag of pseudo buffer? */
- unchar agno; /* ag number */
+ unchar pad;
signed char active_ag; /* ag currently allocating from */
lid_t blid; /* lid of pseudo buffer? */
lid_t atlhead; /* anonymous tlock list head */
@@ -74,10 +75,6 @@ struct jfs_inode_info {
/* xattr_sem allows us to access the xattrs without taking i_mutex */
struct rw_semaphore xattr_sem;
lid_t xtlid; /* lid of xtree lock on directory */
-#ifdef CONFIG_JFS_POSIX_ACL
- struct posix_acl *i_acl;
- struct posix_acl *i_default_acl;
-#endif
union {
struct {
xtpage_t _xtroot; /* 288: xtree root */
@@ -107,8 +104,6 @@ struct jfs_inode_info {
#define i_inline u.link._inline
#define i_inline_ea u.link._inline_ea
-#define JFS_ACL_NOT_CACHED ((void *)-1)
-
#define IREAD_LOCK(ip, subclass) \
down_read_nested(&JFS_IP(ip)->rdwrlock, subclass)
#define IREAD_UNLOCK(ip) up_read(&JFS_IP(ip)->rdwrlock)
@@ -197,9 +192,10 @@ struct jfs_sb_info {
uint state; /* mount/recovery state */
unsigned long flag; /* mount time flags */
uint p_state; /* state prior to going no integrity */
- uint uid; /* uid to override on-disk uid */
- uint gid; /* gid to override on-disk gid */
+ kuid_t uid; /* uid to override on-disk uid */
+ kgid_t gid; /* gid to override on-disk gid */
uint umask; /* umask to override on-disk umask */
+ uint minblks_trim; /* minimum blocks, for online trim */
};
/* jfs_sb_info commit_state */
diff --git a/fs/jfs/jfs_inode.c b/fs/jfs/jfs_inode.c
index ed6574bee51..6b0f816201a 100644
--- a/fs/jfs/jfs_inode.c
+++ b/fs/jfs/jfs_inode.c
@@ -29,20 +29,20 @@
void jfs_set_inode_flags(struct inode *inode)
{
unsigned int flags = JFS_IP(inode)->mode2;
-
- inode->i_flags &= ~(S_IMMUTABLE | S_APPEND |
- S_NOATIME | S_DIRSYNC | S_SYNC);
+ unsigned int new_fl = 0;
if (flags & JFS_IMMUTABLE_FL)
- inode->i_flags |= S_IMMUTABLE;
+ new_fl |= S_IMMUTABLE;
if (flags & JFS_APPEND_FL)
- inode->i_flags |= S_APPEND;
+ new_fl |= S_APPEND;
if (flags & JFS_NOATIME_FL)
- inode->i_flags |= S_NOATIME;
+ new_fl |= S_NOATIME;
if (flags & JFS_DIRSYNC_FL)
- inode->i_flags |= S_DIRSYNC;
+ new_fl |= S_DIRSYNC;
if (flags & JFS_SYNC_FL)
- inode->i_flags |= S_SYNC;
+ new_fl |= S_SYNC;
+ inode_set_flags(inode, new_fl, S_IMMUTABLE | S_APPEND | S_NOATIME |
+ S_DIRSYNC | S_SYNC);
}
void jfs_get_inode_flags(struct jfs_inode_info *jfs_ip)
@@ -79,7 +79,8 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
inode = new_inode(sb);
if (!inode) {
jfs_warn("ialloc: new_inode returned NULL!");
- return ERR_PTR(-ENOMEM);
+ rc = -ENOMEM;
+ goto fail;
}
jfs_inode = JFS_IP(inode);
@@ -89,18 +90,15 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
jfs_warn("ialloc: diAlloc returned %d!", rc);
if (rc == -EIO)
make_bad_inode(inode);
- iput(inode);
- return ERR_PTR(rc);
+ goto fail_put;
}
- inode->i_uid = current->fsuid;
- if (parent->i_mode & S_ISGID) {
- inode->i_gid = parent->i_gid;
- if (S_ISDIR(mode))
- mode |= S_ISGID;
- } else
- inode->i_gid = current->fsgid;
+ if (insert_inode_locked(inode) < 0) {
+ rc = -EINVAL;
+ goto fail_put;
+ }
+ inode_init_owner(inode, parent, mode);
/*
* New inodes need to save sane values on disk when
* uid & gid mount options are used
@@ -111,15 +109,11 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
/*
* Allocate inode to quota.
*/
- if (DQUOT_ALLOC_INODE(inode)) {
- DQUOT_DROP(inode);
- inode->i_flags |= S_NOQUOTA;
- inode->i_nlink = 0;
- iput(inode);
- return ERR_PTR(-EDQUOT);
- }
+ dquot_initialize(inode);
+ rc = dquot_alloc_inode(inode);
+ if (rc)
+ goto fail_drop;
- inode->i_mode = mode;
/* inherit flags from parent */
jfs_inode->mode2 = JFS_IP(parent)->mode2 & JFS_FL_INHERIT;
@@ -132,7 +126,7 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
if (S_ISLNK(mode))
jfs_inode->mode2 &= ~(JFS_IMMUTABLE_FL|JFS_APPEND_FL);
}
- jfs_inode->mode2 |= mode;
+ jfs_inode->mode2 |= inode->i_mode;
inode->i_blocks = 0;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
@@ -158,4 +152,14 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
jfs_info("ialloc returns inode = 0x%p\n", inode);
return inode;
+
+fail_drop:
+ dquot_drop(inode);
+ inode->i_flags |= S_NOQUOTA;
+ clear_nlink(inode);
+ unlock_new_inode(inode);
+fail_put:
+ iput(inode);
+fail:
+ return ERR_PTR(rc);
}
diff --git a/fs/jfs/jfs_inode.h b/fs/jfs/jfs_inode.h
index adb2fafcc54..9271cfe4a14 100644
--- a/fs/jfs/jfs_inode.h
+++ b/fs/jfs/jfs_inode.h
@@ -21,14 +21,14 @@
struct fid;
extern struct inode *ialloc(struct inode *, umode_t);
-extern int jfs_fsync(struct file *, struct dentry *, int);
+extern int jfs_fsync(struct file *, loff_t, loff_t, int);
extern long jfs_ioctl(struct file *, unsigned int, unsigned long);
extern long jfs_compat_ioctl(struct file *, unsigned int, unsigned long);
extern struct inode *jfs_iget(struct super_block *, unsigned long);
extern int jfs_commit_inode(struct inode *, int);
-extern int jfs_write_inode(struct inode*, int);
-extern void jfs_delete_inode(struct inode *);
-extern void jfs_dirty_inode(struct inode *);
+extern int jfs_write_inode(struct inode *, struct writeback_control *);
+extern void jfs_evict_inode(struct inode *);
+extern void jfs_dirty_inode(struct inode *, int);
extern void jfs_truncate(struct inode *);
extern void jfs_truncate_nolock(struct inode *, loff_t);
extern void jfs_free_zero_link(struct inode *);
@@ -40,6 +40,7 @@ extern struct dentry *jfs_fh_to_parent(struct super_block *sb, struct fid *fid,
int fh_len, int fh_type);
extern void jfs_set_inode_flags(struct inode *);
extern int jfs_get_block(struct inode *, sector_t, struct buffer_head *, int);
+extern int jfs_setattr(struct dentry *, struct iattr *);
extern const struct address_space_operations jfs_aops;
extern const struct inode_operations jfs_dir_inode_operations;
@@ -47,5 +48,6 @@ extern const struct file_operations jfs_dir_operations;
extern const struct inode_operations jfs_file_inode_operations;
extern const struct file_operations jfs_file_operations;
extern const struct inode_operations jfs_symlink_inode_operations;
-extern struct dentry_operations jfs_ci_dentry_operations;
+extern const struct inode_operations jfs_fast_symlink_inode_operations;
+extern const struct dentry_operations jfs_ci_dentry_operations;
#endif /* _H_JFS_INODE */
diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
index 325a9679b95..0acddf60af5 100644
--- a/fs/jfs/jfs_logmgr.c
+++ b/fs/jfs/jfs_logmgr.c
@@ -67,8 +67,11 @@
#include <linux/buffer_head.h> /* for sync_blockdev() */
#include <linux/bio.h>
#include <linux/freezer.h>
+#include <linux/export.h>
#include <linux/delay.h>
#include <linux/mutex.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
#include "jfs_incore.h"
#include "jfs_filsys.h"
#include "jfs_metapage.h"
@@ -164,7 +167,7 @@ do { \
* Global list of active external journals
*/
static LIST_HEAD(jfs_external_logs);
-static struct jfs_log *dummy_log = NULL;
+static struct jfs_log *dummy_log;
static DEFINE_MUTEX(jfs_log_mutex);
/*
@@ -1008,15 +1011,13 @@ static int lmLogSync(struct jfs_log * log, int hard_sync)
* option 2 - shutdown file systems
* associated with log ?
* option 3 - extend log ?
- */
- /*
* option 4 - second chance
*
* mark log wrapped, and continue.
* when all active transactions are completed,
- * mark log vaild for recovery.
+ * mark log valid for recovery.
* if crashed during invalid state, log state
- * implies invald log, forcing fsck().
+ * implies invalid log, forcing fsck().
*/
/* mark log state log wrap in log superblock */
/* log->state = LOGWRAP; */
@@ -1057,7 +1058,8 @@ static int lmLogSync(struct jfs_log * log, int hard_sync)
*/
void jfs_syncpt(struct jfs_log *log, int hard_sync)
{ LOG_LOCK(log);
- lmLogSync(log, hard_sync);
+ if (!test_bit(log_QUIESCE, &log->flag))
+ lmLogSync(log, hard_sync);
LOG_UNLOCK(log);
}
@@ -1120,16 +1122,13 @@ int lmLogOpen(struct super_block *sb)
* file systems to log may have n-to-1 relationship;
*/
- bdev = open_by_devnum(sbi->logdev, FMODE_READ|FMODE_WRITE);
+ bdev = blkdev_get_by_dev(sbi->logdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL,
+ log);
if (IS_ERR(bdev)) {
- rc = -PTR_ERR(bdev);
+ rc = PTR_ERR(bdev);
goto free;
}
- if ((rc = bd_claim(bdev, log))) {
- goto close;
- }
-
log->bdev = bdev;
memcpy(log->uuid, sbi->loguuid, sizeof(log->uuid));
@@ -1137,7 +1136,7 @@ int lmLogOpen(struct super_block *sb)
* initialize log:
*/
if ((rc = lmLogInit(log)))
- goto unclaim;
+ goto close;
list_add(&log->journal_list, &jfs_external_logs);
@@ -1163,11 +1162,8 @@ journal_found:
list_del(&log->journal_list);
lbmLogShutdown(log);
- unclaim:
- bd_release(bdev);
-
close: /* close external log device */
- blkdev_put(bdev);
+ blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
free: /* free log descriptor */
mutex_unlock(&jfs_log_mutex);
@@ -1512,8 +1508,7 @@ int lmLogClose(struct super_block *sb)
bdev = log->bdev;
rc = lmLogShutdown(log);
- bd_release(bdev);
- blkdev_put(bdev);
+ blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
kfree(log);
@@ -2003,19 +1998,24 @@ static int lbmRead(struct jfs_log * log, int pn, struct lbuf ** bpp)
bio = bio_alloc(GFP_NOFS, 1);
- bio->bi_sector = bp->l_blkno << (log->l2bsize - 9);
+ bio->bi_iter.bi_sector = bp->l_blkno << (log->l2bsize - 9);
bio->bi_bdev = log->bdev;
bio->bi_io_vec[0].bv_page = bp->l_page;
bio->bi_io_vec[0].bv_len = LOGPSIZE;
bio->bi_io_vec[0].bv_offset = bp->l_offset;
bio->bi_vcnt = 1;
- bio->bi_idx = 0;
- bio->bi_size = LOGPSIZE;
+ bio->bi_iter.bi_size = LOGPSIZE;
bio->bi_end_io = lbmIODone;
bio->bi_private = bp;
- submit_bio(READ_SYNC, bio);
+ /*check if journaling to disk has been disabled*/
+ if (log->no_integrity) {
+ bio->bi_iter.bi_size = 0;
+ lbmIODone(bio, 0);
+ } else {
+ submit_bio(READ_SYNC, bio);
+ }
wait_event(bp->l_ioevent, (bp->l_flag != lbmREAD));
@@ -2144,22 +2144,21 @@ static void lbmStartIO(struct lbuf * bp)
jfs_info("lbmStartIO\n");
bio = bio_alloc(GFP_NOFS, 1);
- bio->bi_sector = bp->l_blkno << (log->l2bsize - 9);
+ bio->bi_iter.bi_sector = bp->l_blkno << (log->l2bsize - 9);
bio->bi_bdev = log->bdev;
bio->bi_io_vec[0].bv_page = bp->l_page;
bio->bi_io_vec[0].bv_len = LOGPSIZE;
bio->bi_io_vec[0].bv_offset = bp->l_offset;
bio->bi_vcnt = 1;
- bio->bi_idx = 0;
- bio->bi_size = LOGPSIZE;
+ bio->bi_iter.bi_size = LOGPSIZE;
bio->bi_end_io = lbmIODone;
bio->bi_private = bp;
/* check if journaling to disk has been disabled */
if (log->no_integrity) {
- bio->bi_size = 0;
+ bio->bi_iter.bi_size = 0;
lbmIODone(bio, 0);
} else {
submit_bio(WRITE_SYNC, bio);
@@ -2355,7 +2354,7 @@ int jfsIOWait(void *arg)
if (freezing(current)) {
spin_unlock_irq(&log_redrive_lock);
- refrigerator();
+ try_to_freeze();
} else {
set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irq(&log_redrive_lock);
@@ -2503,13 +2502,9 @@ exit:
}
#ifdef CONFIG_JFS_STATISTICS
-int jfs_lmstats_read(char *buffer, char **start, off_t offset, int length,
- int *eof, void *data)
+static int jfs_lmstats_proc_show(struct seq_file *m, void *v)
{
- int len = 0;
- off_t begin;
-
- len += sprintf(buffer,
+ seq_printf(m,
"JFS Logmgr stats\n"
"================\n"
"commits = %d\n"
@@ -2522,19 +2517,19 @@ int jfs_lmstats_read(char *buffer, char **start, off_t offset, int length,
lmStat.pagedone,
lmStat.full_page,
lmStat.partial_page);
+ return 0;
+}
- begin = offset;
- *start = buffer + begin;
- len -= begin;
-
- if (len > length)
- len = length;
- else
- *eof = 1;
-
- if (len < 0)
- len = 0;
-
- return len;
+static int jfs_lmstats_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, jfs_lmstats_proc_show, NULL);
}
+
+const struct file_operations jfs_lmstats_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = jfs_lmstats_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
#endif /* CONFIG_JFS_STATISTICS */
diff --git a/fs/jfs/jfs_logmgr.h b/fs/jfs/jfs_logmgr.h
index 9236bc49ae7..e38c2159885 100644
--- a/fs/jfs/jfs_logmgr.h
+++ b/fs/jfs/jfs_logmgr.h
@@ -288,7 +288,7 @@ struct lrd {
/*
* SYNCPT: log sync point
*
- * replay log upto syncpt address specified;
+ * replay log up to syncpt address specified;
*/
struct {
__le32 sync; /* 4: syncpt address (0 = here) */
diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c
index d1e64f2f2fc..49ba7ff1bbb 100644
--- a/fs/jfs/jfs_metapage.c
+++ b/fs/jfs/jfs_metapage.c
@@ -19,10 +19,13 @@
#include <linux/fs.h>
#include <linux/mm.h>
+#include <linux/module.h>
#include <linux/bio.h>
+#include <linux/slab.h>
#include <linux/init.h>
#include <linux/buffer_head.h>
#include <linux/mempool.h>
+#include <linux/seq_file.h>
#include "jfs_incore.h"
#include "jfs_superblock.h"
#include "jfs_filsys.h"
@@ -180,7 +183,7 @@ static inline void remove_metapage(struct page *page, struct metapage *mp)
#endif
-static void init_once(struct kmem_cache *cachep, void *foo)
+static void init_once(void *foo)
{
struct metapage *mp = (struct metapage *)foo;
@@ -367,6 +370,7 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc)
unsigned long bio_bytes = 0;
unsigned long bio_offset = 0;
int offset;
+ int bad_blocks = 0;
page_start = (sector_t)page->index <<
(PAGE_CACHE_SHIFT - inode->i_blkbits);
@@ -392,6 +396,7 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc)
}
clear_bit(META_dirty, &mp->flag);
+ set_bit(META_io, &mp->flag);
block_offset = offset >> inode->i_blkbits;
lblock = page_start + block_offset;
if (bio) {
@@ -400,7 +405,6 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc)
len = min(xlen, blocks_per_mp);
xlen -= len;
bio_bytes += len << inode->i_blkbits;
- set_bit(META_io, &mp->flag);
continue;
}
/* Not contiguous */
@@ -412,7 +416,7 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc)
* count from hitting zero before we're through
*/
inc_io(page);
- if (!bio->bi_size)
+ if (!bio->bi_iter.bi_size)
goto dump_bio;
submit_bio(WRITE, bio);
nr_underway++;
@@ -422,17 +426,19 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc)
xlen = (PAGE_CACHE_SIZE - offset) >> inode->i_blkbits;
pblock = metapage_get_blocks(inode, lblock, &xlen);
if (!pblock) {
- /* Need better error handling */
printk(KERN_ERR "JFS: metapage_get_blocks failed\n");
- dec_io(page, last_write_complete);
+ /*
+ * We already called inc_io(), but can't cancel it
+ * with dec_io() until we're done with the page
+ */
+ bad_blocks++;
continue;
}
- set_bit(META_io, &mp->flag);
len = min(xlen, (int)JFS_SBI(inode->i_sb)->nbperpage);
bio = bio_alloc(GFP_NOFS, 1);
bio->bi_bdev = inode->i_sb->s_bdev;
- bio->bi_sector = pblock << (inode->i_blkbits - 9);
+ bio->bi_iter.bi_sector = pblock << (inode->i_blkbits - 9);
bio->bi_end_io = metapage_write_end_io;
bio->bi_private = page;
@@ -446,7 +452,7 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc)
if (bio) {
if (bio_add_page(bio, page, bio_bytes, bio_offset) < bio_bytes)
goto add_failed;
- if (!bio->bi_size)
+ if (!bio->bi_iter.bi_size)
goto dump_bio;
submit_bio(WRITE, bio);
@@ -457,6 +463,9 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc)
unlock_page(page);
+ if (bad_blocks)
+ goto err_out;
+
if (nr_underway == 0)
end_page_writeback(page);
@@ -472,7 +481,9 @@ skip:
bio_put(bio);
unlock_page(page);
dec_io(page, last_write_complete);
-
+err_out:
+ while (bad_blocks--)
+ dec_io(page, last_write_complete);
return -EIO;
}
@@ -506,7 +517,8 @@ static int metapage_readpage(struct file *fp, struct page *page)
bio = bio_alloc(GFP_NOFS, 1);
bio->bi_bdev = inode->i_sb->s_bdev;
- bio->bi_sector = pblock << (inode->i_blkbits - 9);
+ bio->bi_iter.bi_sector =
+ pblock << (inode->i_blkbits - 9);
bio->bi_end_io = metapage_read_end_io;
bio->bi_private = page;
len = xlen << inode->i_blkbits;
@@ -560,9 +572,10 @@ static int metapage_releasepage(struct page *page, gfp_t gfp_mask)
return ret;
}
-static void metapage_invalidatepage(struct page *page, unsigned long offset)
+static void metapage_invalidatepage(struct page *page, unsigned int offset,
+ unsigned int length)
{
- BUG_ON(offset);
+ BUG_ON(offset || length < PAGE_CACHE_SIZE);
BUG_ON(PageWriteback(page));
@@ -572,7 +585,6 @@ static void metapage_invalidatepage(struct page *page, unsigned long offset)
const struct address_space_operations jfs_metapage_aops = {
.readpage = metapage_readpage,
.writepage = metapage_writepage,
- .sync_page = block_sync_page,
.releasepage = metapage_releasepage,
.invalidatepage = metapage_invalidatepage,
.set_page_dirty = __set_page_dirty_nobuffers,
@@ -636,7 +648,7 @@ struct metapage *__get_metapage(struct inode *inode, unsigned long lblock,
if (mp) {
if (mp->logical_size != size) {
jfs_error(inode->i_sb,
- "__get_metapage: mp->logical_size != size");
+ "get_mp->logical_size != size\n");
jfs_err("logical_size = %d, size = %d",
mp->logical_size, size);
dump_stack();
@@ -647,8 +659,7 @@ struct metapage *__get_metapage(struct inode *inode, unsigned long lblock,
if (test_bit(META_discard, &mp->flag)) {
if (!new) {
jfs_error(inode->i_sb,
- "__get_metapage: using a "
- "discarded metapage");
+ "using a discarded metapage\n");
discard_metapage(mp);
goto unlock;
}
@@ -804,13 +815,9 @@ void __invalidate_metapages(struct inode *ip, s64 addr, int len)
}
#ifdef CONFIG_JFS_STATISTICS
-int jfs_mpstat_read(char *buffer, char **start, off_t offset, int length,
- int *eof, void *data)
+static int jfs_mpstat_proc_show(struct seq_file *m, void *v)
{
- int len = 0;
- off_t begin;
-
- len += sprintf(buffer,
+ seq_printf(m,
"JFS Metapage statistics\n"
"=======================\n"
"page allocations = %d\n"
@@ -819,19 +826,19 @@ int jfs_mpstat_read(char *buffer, char **start, off_t offset, int length,
mpStat.pagealloc,
mpStat.pagefree,
mpStat.lockwait);
+ return 0;
+}
- begin = offset;
- *start = buffer + begin;
- len -= begin;
-
- if (len > length)
- len = length;
- else
- *eof = 1;
-
- if (len < 0)
- len = 0;
-
- return len;
+static int jfs_mpstat_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, jfs_mpstat_proc_show, NULL);
}
+
+const struct file_operations jfs_mpstat_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = jfs_mpstat_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
#endif
diff --git a/fs/jfs/jfs_metapage.h b/fs/jfs/jfs_metapage.h
index d94f8d9e87d..a78beda85f6 100644
--- a/fs/jfs/jfs_metapage.h
+++ b/fs/jfs/jfs_metapage.h
@@ -75,7 +75,7 @@ extern void grab_metapage(struct metapage *);
extern void force_metapage(struct metapage *);
/*
- * hold_metapage and put_metapage are used in conjuction. The page lock
+ * hold_metapage and put_metapage are used in conjunction. The page lock
* is not dropped between the two, so no other threads can get or release
* the metapage
*/
diff --git a/fs/jfs/jfs_mount.c b/fs/jfs/jfs_mount.c
index 7b698f2ec45..9895595fd2f 100644
--- a/fs/jfs/jfs_mount.c
+++ b/fs/jfs/jfs_mount.c
@@ -97,7 +97,7 @@ int jfs_mount(struct super_block *sb)
ipaimap = diReadSpecial(sb, AGGREGATE_I, 0);
if (ipaimap == NULL) {
- jfs_err("jfs_mount: Faild to read AGGREGATE_I");
+ jfs_err("jfs_mount: Failed to read AGGREGATE_I");
rc = -EIO;
goto errout20;
}
@@ -148,7 +148,7 @@ int jfs_mount(struct super_block *sb)
if ((sbi->mntflag & JFS_BAD_SAIT) == 0) {
ipaimap2 = diReadSpecial(sb, AGGREGATE_I, 1);
if (!ipaimap2) {
- jfs_err("jfs_mount: Faild to read AGGREGATE_I");
+ jfs_err("jfs_mount: Failed to read AGGREGATE_I");
rc = -EIO;
goto errout35;
}
diff --git a/fs/jfs/jfs_superblock.h b/fs/jfs/jfs_superblock.h
index 884fc21ab8e..04847b8d307 100644
--- a/fs/jfs/jfs_superblock.h
+++ b/fs/jfs/jfs_superblock.h
@@ -108,6 +108,7 @@ struct jfs_superblock {
extern int readSuper(struct super_block *, struct buffer_head **);
extern int updateSuper(struct super_block *, uint);
+__printf(2, 3)
extern void jfs_error(struct super_block *, const char *, ...);
extern int jfs_mount(struct super_block *);
extern int jfs_mount_rw(struct super_block *, int);
diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
index e7c60ae6b5b..564c4f279ac 100644
--- a/fs/jfs/jfs_txnmgr.c
+++ b/fs/jfs/jfs_txnmgr.c
@@ -49,6 +49,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kthread.h>
+#include <linux/seq_file.h>
#include "jfs_incore.h"
#include "jfs_inode.h"
#include "jfs_filsys.h"
@@ -635,7 +636,7 @@ struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage * mp,
* the inode of the page and available to all anonymous
* transactions until txCommit() time at which point
* they are transferred to the transaction tlock list of
- * the commiting transaction of the inode)
+ * the committing transaction of the inode)
*/
if (xtid == 0) {
tlck->tid = tid;
@@ -1142,7 +1143,6 @@ int txCommit(tid_t tid, /* transaction identifier */
struct jfs_log *log;
struct tblock *tblk;
struct lrd *lrd;
- int lsn;
struct inode *ip;
struct jfs_inode_info *jfs_ip;
int k, n;
@@ -1278,7 +1278,7 @@ int txCommit(tid_t tid, /* transaction identifier */
* lazy commit thread finishes processing
*/
if (tblk->xflag & COMMIT_DELETE) {
- atomic_inc(&tblk->u.ip->i_count);
+ ihold(tblk->u.ip);
/*
* Avoid a rare deadlock
*
@@ -1291,7 +1291,7 @@ int txCommit(tid_t tid, /* transaction identifier */
*/
/*
* I believe this code is no longer needed. Splitting I_LOCK
- * into two bits, I_LOCK and I_SYNC should prevent this
+ * into two bits, I_NEW and I_SYNC should prevent this
* deadlock as well. But since I don't have a JFS testload
* to verify this, only a trivial s/I_LOCK/I_SYNC/ was done.
* Joern
@@ -1309,7 +1309,7 @@ int txCommit(tid_t tid, /* transaction identifier */
*/
lrd->type = cpu_to_le16(LOG_COMMIT);
lrd->length = 0;
- lsn = lmLog(log, tblk, lrd, NULL);
+ lmLog(log, tblk, lrd, NULL);
lmGroupCommit(log, tblk);
@@ -2684,7 +2684,7 @@ void txAbort(tid_t tid, int dirty)
* mark filesystem dirty
*/
if (dirty)
- jfs_error(tblk->sb, "txAbort");
+ jfs_error(tblk->sb, "\n");
return;
}
@@ -2800,7 +2800,7 @@ int jfs_lazycommit(void *arg)
if (freezing(current)) {
LAZY_UNLOCK(flags);
- refrigerator();
+ try_to_freeze();
} else {
DECLARE_WAITQUEUE(wq, current);
@@ -2934,7 +2934,6 @@ int jfs_sync(void *arg)
{
struct inode *ip;
struct jfs_inode_info *jfs_ip;
- int rc;
tid_t tid;
do {
@@ -2960,7 +2959,7 @@ int jfs_sync(void *arg)
*/
TXN_UNLOCK();
tid = txBegin(ip->i_sb, COMMIT_INODE);
- rc = txCommit(tid, 1, &ip, 0);
+ txCommit(tid, 1, &ip, 0);
txEnd(tid);
mutex_unlock(&jfs_ip->commit_mutex);
@@ -2978,12 +2977,9 @@ int jfs_sync(void *arg)
* put back on the anon_list.
*/
- /* Take off anon_list */
- list_del(&jfs_ip->anon_inode_list);
-
- /* Put on anon_list2 */
- list_add(&jfs_ip->anon_inode_list,
- &TxAnchor.anon_list2);
+ /* Move from anon_list to anon_list2 */
+ list_move(&jfs_ip->anon_inode_list,
+ &TxAnchor.anon_list2);
TXN_UNLOCK();
iput(ip);
@@ -2995,7 +2991,7 @@ int jfs_sync(void *arg)
if (freezing(current)) {
TXN_UNLOCK();
- refrigerator();
+ try_to_freeze();
} else {
set_current_state(TASK_INTERRUPTIBLE);
TXN_UNLOCK();
@@ -3009,11 +3005,8 @@ int jfs_sync(void *arg)
}
#if defined(CONFIG_PROC_FS) && defined(CONFIG_JFS_DEBUG)
-int jfs_txanchor_read(char *buffer, char **start, off_t offset, int length,
- int *eof, void *data)
+static int jfs_txanchor_proc_show(struct seq_file *m, void *v)
{
- int len = 0;
- off_t begin;
char *freewait;
char *freelockwait;
char *lowlockwait;
@@ -3025,7 +3018,7 @@ int jfs_txanchor_read(char *buffer, char **start, off_t offset, int length,
lowlockwait =
waitqueue_active(&TxAnchor.lowlockwait) ? "active" : "empty";
- len += sprintf(buffer,
+ seq_printf(m,
"JFS TxAnchor\n"
"============\n"
"freetid = %d\n"
@@ -3044,31 +3037,27 @@ int jfs_txanchor_read(char *buffer, char **start, off_t offset, int length,
TxAnchor.tlocksInUse,
jfs_tlocks_low,
list_empty(&TxAnchor.unlock_queue) ? "" : "not ");
+ return 0;
+}
- begin = offset;
- *start = buffer + begin;
- len -= begin;
-
- if (len > length)
- len = length;
- else
- *eof = 1;
-
- if (len < 0)
- len = 0;
-
- return len;
+static int jfs_txanchor_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, jfs_txanchor_proc_show, NULL);
}
+
+const struct file_operations jfs_txanchor_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = jfs_txanchor_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
#endif
#if defined(CONFIG_PROC_FS) && defined(CONFIG_JFS_STATISTICS)
-int jfs_txstats_read(char *buffer, char **start, off_t offset, int length,
- int *eof, void *data)
+static int jfs_txstats_proc_show(struct seq_file *m, void *v)
{
- int len = 0;
- off_t begin;
-
- len += sprintf(buffer,
+ seq_printf(m,
"JFS TxStats\n"
"===========\n"
"calls to txBegin = %d\n"
@@ -3089,19 +3078,19 @@ int jfs_txstats_read(char *buffer, char **start, off_t offset, int length,
TxStat.txBeginAnon_lockslow,
TxStat.txLockAlloc,
TxStat.txLockAlloc_freelock);
+ return 0;
+}
- begin = offset;
- *start = buffer + begin;
- len -= begin;
-
- if (len > length)
- len = length;
- else
- *eof = 1;
-
- if (len < 0)
- len = 0;
-
- return len;
+static int jfs_txstats_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, jfs_txstats_proc_show, NULL);
}
+
+const struct file_operations jfs_txstats_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = jfs_txstats_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
#endif
diff --git a/fs/jfs/jfs_types.h b/fs/jfs/jfs_types.h
index 649f9817acc..43ea3713c08 100644
--- a/fs/jfs/jfs_types.h
+++ b/fs/jfs/jfs_types.h
@@ -58,35 +58,6 @@ struct timestruc_t {
#define ONES 0xffffffffu /* all bit on */
/*
- * logical xd (lxd)
- */
-typedef struct {
- unsigned len:24;
- unsigned off1:8;
- u32 off2;
-} lxd_t;
-
-/* lxd_t field construction */
-#define LXDlength(lxd, length32) ( (lxd)->len = length32 )
-#define LXDoffset(lxd, offset64)\
-{\
- (lxd)->off1 = ((s64)offset64) >> 32;\
- (lxd)->off2 = (offset64) & 0xffffffff;\
-}
-
-/* lxd_t field extraction */
-#define lengthLXD(lxd) ( (lxd)->len )
-#define offsetLXD(lxd)\
- ( ((s64)((lxd)->off1)) << 32 | (lxd)->off2 )
-
-/* lxd list */
-struct lxdlist {
- s16 maxnlxd;
- s16 nlxd;
- lxd_t *lxd;
-};
-
-/*
* physical xd (pxd)
*/
typedef struct {
diff --git a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c
index adcf92d3b60..7971f37534a 100644
--- a/fs/jfs/jfs_umount.c
+++ b/fs/jfs/jfs_umount.c
@@ -68,7 +68,7 @@ int jfs_umount(struct super_block *sb)
/*
* Wait for outstanding transactions to be written to log:
*/
- jfs_flush_journal(log, 1);
+ jfs_flush_journal(log, 2);
/*
* close fileset inode allocation map (aka fileset inode)
@@ -146,7 +146,7 @@ int jfs_umount_rw(struct super_block *sb)
*
* remove file system from log active file system list.
*/
- jfs_flush_journal(log, 1);
+ jfs_flush_journal(log, 2);
/*
* Make sure all metadata makes it to disk
diff --git a/fs/jfs/jfs_unicode.h b/fs/jfs/jfs_unicode.h
index 3fbb3a22559..8f0f02cb6ca 100644
--- a/fs/jfs/jfs_unicode.h
+++ b/fs/jfs/jfs_unicode.h
@@ -19,6 +19,7 @@
#ifndef _H_JFS_UNICODE
#define _H_JFS_UNICODE
+#include <linux/slab.h>
#include <asm/byteorder.h>
#include "jfs_types.h"
diff --git a/fs/jfs/jfs_xattr.h b/fs/jfs/jfs_xattr.h
index 88b6cc535bf..e8d717dabca 100644
--- a/fs/jfs/jfs_xattr.h
+++ b/fs/jfs/jfs_xattr.h
@@ -61,11 +61,14 @@ extern ssize_t jfs_getxattr(struct dentry *, const char *, void *, size_t);
extern ssize_t jfs_listxattr(struct dentry *, char *, size_t);
extern int jfs_removexattr(struct dentry *, const char *);
+extern const struct xattr_handler *jfs_xattr_handlers[];
+
#ifdef CONFIG_JFS_SECURITY
-extern int jfs_init_security(tid_t, struct inode *, struct inode *);
+extern int jfs_init_security(tid_t, struct inode *, struct inode *,
+ const struct qstr *);
#else
static inline int jfs_init_security(tid_t tid, struct inode *inode,
- struct inode *dir)
+ struct inode *dir, const struct qstr *qstr)
{
return 0;
}
diff --git a/fs/jfs/jfs_xtree.c b/fs/jfs/jfs_xtree.c
index a000aaa7513..5ad7748860c 100644
--- a/fs/jfs/jfs_xtree.c
+++ b/fs/jfs/jfs_xtree.c
@@ -20,7 +20,9 @@
*/
#include <linux/fs.h>
+#include <linux/module.h>
#include <linux/quotaops.h>
+#include <linux/seq_file.h>
#include "jfs_incore.h"
#include "jfs_filsys.h"
#include "jfs_metapage.h"
@@ -62,22 +64,23 @@
/* get page buffer for specified block address */
/* ToDo: Replace this ugly macro with a function */
-#define XT_GETPAGE(IP, BN, MP, SIZE, P, RC)\
-{\
- BT_GETPAGE(IP, BN, MP, xtpage_t, SIZE, P, RC, i_xtroot)\
- if (!(RC))\
- {\
- if ((le16_to_cpu((P)->header.nextindex) < XTENTRYSTART) ||\
- (le16_to_cpu((P)->header.nextindex) > le16_to_cpu((P)->header.maxentry)) ||\
- (le16_to_cpu((P)->header.maxentry) > (((BN)==0)?XTROOTMAXSLOT:PSIZE>>L2XTSLOTSIZE)))\
- {\
- jfs_error((IP)->i_sb, "XT_GETPAGE: xtree page corrupt");\
- BT_PUTPAGE(MP);\
- MP = NULL;\
- RC = -EIO;\
- }\
- }\
-}
+#define XT_GETPAGE(IP, BN, MP, SIZE, P, RC) \
+do { \
+ BT_GETPAGE(IP, BN, MP, xtpage_t, SIZE, P, RC, i_xtroot); \
+ if (!(RC)) { \
+ if ((le16_to_cpu((P)->header.nextindex) < XTENTRYSTART) || \
+ (le16_to_cpu((P)->header.nextindex) > \
+ le16_to_cpu((P)->header.maxentry)) || \
+ (le16_to_cpu((P)->header.maxentry) > \
+ (((BN) == 0) ? XTROOTMAXSLOT : PSIZE >> L2XTSLOTSIZE))) { \
+ jfs_error((IP)->i_sb, \
+ "XT_GETPAGE: xtree page corrupt\n"); \
+ BT_PUTPAGE(MP); \
+ MP = NULL; \
+ RC = -EIO; \
+ } \
+ } \
+} while (0)
/* for consistency */
#define XT_PUTPAGE(MP) BT_PUTPAGE(MP)
@@ -162,11 +165,8 @@ int xtLookup(struct inode *ip, s64 lstart,
/* is lookup offset beyond eof ? */
size = ((u64) ip->i_size + (JFS_SBI(ip->i_sb)->bsize - 1)) >>
JFS_SBI(ip->i_sb)->l2bsize;
- if (lstart >= size) {
- jfs_err("xtLookup: lstart (0x%lx) >= size (0x%lx)",
- (ulong) lstart, (ulong) size);
+ if (lstart >= size)
return 0;
- }
}
/*
@@ -218,264 +218,6 @@ int xtLookup(struct inode *ip, s64 lstart,
return rc;
}
-
-/*
- * xtLookupList()
- *
- * function: map a single logical extent into a list of physical extent;
- *
- * parameter:
- * struct inode *ip,
- * struct lxdlist *lxdlist, lxd list (in)
- * struct xadlist *xadlist, xad list (in/out)
- * int flag)
- *
- * coverage of lxd by xad under assumption of
- * . lxd's are ordered and disjoint.
- * . xad's are ordered and disjoint.
- *
- * return:
- * 0: success
- *
- * note: a page being written (even a single byte) is backed fully,
- * except the last page which is only backed with blocks
- * required to cover the last byte;
- * the extent backing a page is fully contained within an xad;
- */
-int xtLookupList(struct inode *ip, struct lxdlist * lxdlist,
- struct xadlist * xadlist, int flag)
-{
- int rc = 0;
- struct btstack btstack;
- int cmp;
- s64 bn;
- struct metapage *mp;
- xtpage_t *p;
- int index;
- lxd_t *lxd;
- xad_t *xad, *pxd;
- s64 size, lstart, lend, xstart, xend, pstart;
- s64 llen, xlen, plen;
- s64 xaddr, paddr;
- int nlxd, npxd, maxnpxd;
-
- npxd = xadlist->nxad = 0;
- maxnpxd = xadlist->maxnxad;
- pxd = xadlist->xad;
-
- nlxd = lxdlist->nlxd;
- lxd = lxdlist->lxd;
-
- lstart = offsetLXD(lxd);
- llen = lengthLXD(lxd);
- lend = lstart + llen;
-
- size = (ip->i_size + (JFS_SBI(ip->i_sb)->bsize - 1)) >>
- JFS_SBI(ip->i_sb)->l2bsize;
-
- /*
- * search for the xad entry covering the logical extent
- */
- search:
- if (lstart >= size)
- return 0;
-
- if ((rc = xtSearch(ip, lstart, NULL, &cmp, &btstack, 0)))
- return rc;
-
- /*
- * compute the physical extent covering logical extent
- *
- * N.B. search may have failed (e.g., hole in sparse file),
- * and returned the index of the next entry.
- */
-//map:
- /* retrieve search result */
- XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
-
- /* is xad on the next sibling page ? */
- if (index == le16_to_cpu(p->header.nextindex)) {
- if (p->header.flag & BT_ROOT)
- goto mapend;
-
- if ((bn = le64_to_cpu(p->header.next)) == 0)
- goto mapend;
-
- XT_PUTPAGE(mp);
-
- /* get next sibling page */
- XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
- if (rc)
- return rc;
-
- index = XTENTRYSTART;
- }
-
- xad = &p->xad[index];
-
- /*
- * is lxd covered by xad ?
- */
- compare:
- xstart = offsetXAD(xad);
- xlen = lengthXAD(xad);
- xend = xstart + xlen;
- xaddr = addressXAD(xad);
-
- compare1:
- if (xstart < lstart)
- goto compare2;
-
- /* (lstart <= xstart) */
-
- /* lxd is NOT covered by xad */
- if (lend <= xstart) {
- /*
- * get next lxd
- */
- if (--nlxd == 0)
- goto mapend;
- lxd++;
-
- lstart = offsetLXD(lxd);
- llen = lengthLXD(lxd);
- lend = lstart + llen;
- if (lstart >= size)
- goto mapend;
-
- /* compare with the current xad */
- goto compare1;
- }
- /* lxd is covered by xad */
- else { /* (xstart < lend) */
-
- /* initialize new pxd */
- pstart = xstart;
- plen = min(lend - xstart, xlen);
- paddr = xaddr;
-
- goto cover;
- }
-
- /* (xstart < lstart) */
- compare2:
- /* lxd is covered by xad */
- if (lstart < xend) {
- /* initialize new pxd */
- pstart = lstart;
- plen = min(xend - lstart, llen);
- paddr = xaddr + (lstart - xstart);
-
- goto cover;
- }
- /* lxd is NOT covered by xad */
- else { /* (xend <= lstart) */
-
- /*
- * get next xad
- *
- * linear search next xad covering lxd on
- * the current xad page, and then tree search
- */
- if (index == le16_to_cpu(p->header.nextindex) - 1) {
- if (p->header.flag & BT_ROOT)
- goto mapend;
-
- XT_PUTPAGE(mp);
- goto search;
- } else {
- index++;
- xad++;
-
- /* compare with new xad */
- goto compare;
- }
- }
-
- /*
- * lxd is covered by xad and a new pxd has been initialized
- * (lstart <= xstart < lend) or (xstart < lstart < xend)
- */
- cover:
- /* finalize pxd corresponding to current xad */
- XT_PUTENTRY(pxd, xad->flag, pstart, plen, paddr);
-
- if (++npxd >= maxnpxd)
- goto mapend;
- pxd++;
-
- /*
- * lxd is fully covered by xad
- */
- if (lend <= xend) {
- /*
- * get next lxd
- */
- if (--nlxd == 0)
- goto mapend;
- lxd++;
-
- lstart = offsetLXD(lxd);
- llen = lengthLXD(lxd);
- lend = lstart + llen;
- if (lstart >= size)
- goto mapend;
-
- /*
- * test for old xad covering new lxd
- * (old xstart < new lstart)
- */
- goto compare2;
- }
- /*
- * lxd is partially covered by xad
- */
- else { /* (xend < lend) */
-
- /*
- * get next xad
- *
- * linear search next xad covering lxd on
- * the current xad page, and then next xad page search
- */
- if (index == le16_to_cpu(p->header.nextindex) - 1) {
- if (p->header.flag & BT_ROOT)
- goto mapend;
-
- if ((bn = le64_to_cpu(p->header.next)) == 0)
- goto mapend;
-
- XT_PUTPAGE(mp);
-
- /* get next sibling page */
- XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
- if (rc)
- return rc;
-
- index = XTENTRYSTART;
- xad = &p->xad[index];
- } else {
- index++;
- xad++;
- }
-
- /*
- * test for new xad covering old lxd
- * (old lstart < new xstart)
- */
- goto compare;
- }
-
- mapend:
- xadlist->nxad = npxd;
-
-//out:
- XT_PUTPAGE(mp);
-
- return rc;
-}
-
-
/*
* xtSearch()
*
@@ -758,7 +500,7 @@ static int xtSearch(struct inode *ip, s64 xoff, s64 *nextp,
/* push (bn, index) of the parent page/entry */
if (BT_STACK_FULL(btstack)) {
- jfs_error(ip->i_sb, "stack overrun in xtSearch!");
+ jfs_error(ip->i_sb, "stack overrun!\n");
XT_PUTPAGE(mp);
return -EIO;
}
@@ -844,10 +586,10 @@ int xtInsert(tid_t tid, /* transaction id */
hint = addressXAD(xad) + lengthXAD(xad) - 1;
} else
hint = 0;
- if ((rc = DQUOT_ALLOC_BLOCK(ip, xlen)))
+ if ((rc = dquot_alloc_block(ip, xlen)))
goto out;
if ((rc = dbAlloc(ip, hint, (s64) xlen, &xaddr))) {
- DQUOT_FREE_BLOCK(ip, xlen);
+ dquot_free_block(ip, xlen);
goto out;
}
}
@@ -876,7 +618,7 @@ int xtInsert(tid_t tid, /* transaction id */
/* undo data extent allocation */
if (*xaddrp == 0) {
dbFree(ip, xaddr, (s64) xlen);
- DQUOT_FREE_BLOCK(ip, xlen);
+ dquot_free_block(ip, xlen);
}
return rc;
}
@@ -905,8 +647,7 @@ int xtInsert(tid_t tid, /* transaction id */
XT_PUTENTRY(xad, xflag, xoff, xlen, xaddr);
/* advance next available entry index */
- p->header.nextindex =
- cpu_to_le16(le16_to_cpu(p->header.nextindex) + 1);
+ le16_add_cpu(&p->header.nextindex, 1);
/* Don't log it if there are no links to the file */
if (!test_cflag(COMMIT_Nolink, ip)) {
@@ -997,8 +738,7 @@ xtSplitUp(tid_t tid,
split->addr);
/* advance next available entry index */
- sp->header.nextindex =
- cpu_to_le16(le16_to_cpu(sp->header.nextindex) + 1);
+ le16_add_cpu(&sp->header.nextindex, 1);
/* Don't log it if there are no links to the file */
if (!test_cflag(COMMIT_Nolink, ip)) {
@@ -1167,9 +907,7 @@ xtSplitUp(tid_t tid,
JFS_SBI(ip->i_sb)->nbperpage, rcbn);
/* advance next available entry index. */
- sp->header.nextindex =
- cpu_to_le16(le16_to_cpu(sp->header.nextindex) +
- 1);
+ le16_add_cpu(&sp->header.nextindex, 1);
/* Don't log it if there are no links to the file */
if (!test_cflag(COMMIT_Nolink, ip)) {
@@ -1248,10 +986,9 @@ xtSplitPage(tid_t tid, struct inode *ip,
rbn = addressPXD(pxd);
/* Allocate blocks to quota. */
- if (DQUOT_ALLOC_BLOCK(ip, lengthPXD(pxd))) {
- rc = -EDQUOT;
+ rc = dquot_alloc_block(ip, lengthPXD(pxd));
+ if (rc)
goto clean_up;
- }
quota_allocation += lengthPXD(pxd);
@@ -1458,7 +1195,7 @@ xtSplitPage(tid_t tid, struct inode *ip,
/* Rollback quota allocation. */
if (quota_allocation)
- DQUOT_FREE_BLOCK(ip, quota_allocation);
+ dquot_free_block(ip, quota_allocation);
return (rc);
}
@@ -1498,6 +1235,7 @@ xtSplitRoot(tid_t tid,
struct pxdlist *pxdlist;
struct tlock *tlck;
struct xtlock *xtlck;
+ int rc;
sp = &JFS_IP(ip)->i_xtroot;
@@ -1515,9 +1253,10 @@ xtSplitRoot(tid_t tid,
return -EIO;
/* Allocate blocks to quota. */
- if (DQUOT_ALLOC_BLOCK(ip, lengthPXD(pxd))) {
+ rc = dquot_alloc_block(ip, lengthPXD(pxd));
+ if (rc) {
release_metapage(rmp);
- return -EDQUOT;
+ return rc;
}
jfs_info("xtSplitRoot: ip:0x%p rmp:0x%p", ip, rmp);
@@ -1647,7 +1386,7 @@ int xtExtend(tid_t tid, /* transaction id */
if (cmp != 0) {
XT_PUTPAGE(mp);
- jfs_error(ip->i_sb, "xtExtend: xtSearch did not find extent");
+ jfs_error(ip->i_sb, "xtSearch did not find extent\n");
return -EIO;
}
@@ -1655,7 +1394,7 @@ int xtExtend(tid_t tid, /* transaction id */
xad = &p->xad[index];
if ((offsetXAD(xad) + lengthXAD(xad)) != xoff) {
XT_PUTPAGE(mp);
- jfs_error(ip->i_sb, "xtExtend: extension is not contiguous");
+ jfs_error(ip->i_sb, "extension is not contiguous\n");
return -EIO;
}
@@ -1738,8 +1477,7 @@ int xtExtend(tid_t tid, /* transaction id */
XT_PUTENTRY(xad, XAD_NEW, xoff, len, xaddr);
/* advance next available entry index */
- p->header.nextindex =
- cpu_to_le16(le16_to_cpu(p->header.nextindex) + 1);
+ le16_add_cpu(&p->header.nextindex, 1);
}
/* get back old entry */
@@ -1815,7 +1553,7 @@ printf("xtTailgate: nxoff:0x%lx nxlen:0x%x nxaddr:0x%lx\n",
if (cmp != 0) {
XT_PUTPAGE(mp);
- jfs_error(ip->i_sb, "xtTailgate: couldn't find extent");
+ jfs_error(ip->i_sb, "couldn't find extent\n");
return -EIO;
}
@@ -1823,8 +1561,7 @@ printf("xtTailgate: nxoff:0x%lx nxlen:0x%x nxaddr:0x%lx\n",
nextindex = le16_to_cpu(p->header.nextindex);
if (index != nextindex - 1) {
XT_PUTPAGE(mp);
- jfs_error(ip->i_sb,
- "xtTailgate: the entry found is not the last entry");
+ jfs_error(ip->i_sb, "the entry found is not the last entry\n");
return -EIO;
}
@@ -1905,8 +1642,7 @@ printf("xtTailgate: xoff:0x%lx xlen:0x%x xaddr:0x%lx\n",
XT_PUTENTRY(xad, XAD_NEW, xoff, xlen, xaddr);
/* advance next available entry index */
- p->header.nextindex =
- cpu_to_le16(le16_to_cpu(p->header.nextindex) + 1);
+ le16_add_cpu(&p->header.nextindex, 1);
}
/* get back old XAD */
@@ -1998,7 +1734,7 @@ int xtUpdate(tid_t tid, struct inode *ip, xad_t * nxad)
if (cmp != 0) {
XT_PUTPAGE(mp);
- jfs_error(ip->i_sb, "xtUpdate: Could not find extent");
+ jfs_error(ip->i_sb, "Could not find extent\n");
return -EIO;
}
@@ -2022,7 +1758,7 @@ int xtUpdate(tid_t tid, struct inode *ip, xad_t * nxad)
(nxoff + nxlen > xoff + xlen)) {
XT_PUTPAGE(mp);
jfs_error(ip->i_sb,
- "xtUpdate: nXAD in not completely contained within XAD");
+ "nXAD in not completely contained within XAD\n");
return -EIO;
}
@@ -2171,7 +1907,7 @@ int xtUpdate(tid_t tid, struct inode *ip, xad_t * nxad)
if (xoff >= nxoff) {
XT_PUTPAGE(mp);
- jfs_error(ip->i_sb, "xtUpdate: xoff >= nxoff");
+ jfs_error(ip->i_sb, "xoff >= nxoff\n");
return -EIO;
}
/* #endif _JFS_WIP_COALESCE */
@@ -2312,14 +2048,13 @@ int xtUpdate(tid_t tid, struct inode *ip, xad_t * nxad)
if (cmp != 0) {
XT_PUTPAGE(mp);
- jfs_error(ip->i_sb, "xtUpdate: xtSearch failed");
+ jfs_error(ip->i_sb, "xtSearch failed\n");
return -EIO;
}
if (index0 != index) {
XT_PUTPAGE(mp);
- jfs_error(ip->i_sb,
- "xtUpdate: unexpected value of index");
+ jfs_error(ip->i_sb, "unexpected value of index\n");
return -EIO;
}
}
@@ -2567,8 +2302,7 @@ int xtAppend(tid_t tid, /* transaction id */
XT_PUTENTRY(xad, xflag, xoff, xlen, xaddr);
/* advance next available entry index */
- p->header.nextindex =
- cpu_to_le16(le16_to_cpu(p->header.nextindex) + 1);
+ le16_add_cpu(&p->header.nextindex, 1);
xtlck->lwm.offset =
(xtlck->lwm.offset) ? min(index,(int) xtlck->lwm.offset) : index;
@@ -2631,8 +2365,7 @@ int xtDelete(tid_t tid, struct inode *ip, s64 xoff, s32 xlen, int flag)
* delete the entry from the leaf page
*/
nextindex = le16_to_cpu(p->header.nextindex);
- p->header.nextindex =
- cpu_to_le16(le16_to_cpu(p->header.nextindex) - 1);
+ le16_add_cpu(&p->header.nextindex, -1);
/*
* if the leaf page bocome empty, free the page
@@ -2795,9 +2528,7 @@ xtDeleteUp(tid_t tid, struct inode *ip,
(nextindex - index -
1) << L2XTSLOTSIZE);
- p->header.nextindex =
- cpu_to_le16(le16_to_cpu(p->header.nextindex) -
- 1);
+ le16_add_cpu(&p->header.nextindex, -1);
jfs_info("xtDeleteUp(entry): 0x%lx[%d]",
(ulong) parent->bn, index);
}
@@ -3918,7 +3649,7 @@ s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int flag)
getChild:
/* save current parent entry for the child page */
if (BT_STACK_FULL(&btstack)) {
- jfs_error(ip->i_sb, "stack overrun in xtTruncate!");
+ jfs_error(ip->i_sb, "stack overrun!\n");
XT_PUTPAGE(mp);
return -EIO;
}
@@ -3949,7 +3680,7 @@ s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int flag)
ip->i_size = newsize;
/* update quota allocation to reflect freed blocks */
- DQUOT_FREE_BLOCK(ip, nfreed);
+ dquot_free_block(ip, nfreed);
/*
* free tlock of invalidated pages
@@ -4019,8 +3750,7 @@ s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size)
if (cmp != 0) {
XT_PUTPAGE(mp);
- jfs_error(ip->i_sb,
- "xtTruncate_pmap: did not find extent");
+ jfs_error(ip->i_sb, "did not find extent\n");
return -EIO;
}
} else {
@@ -4119,7 +3849,7 @@ s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size)
getChild:
/* save current parent entry for the child page */
if (BT_STACK_FULL(&btstack)) {
- jfs_error(ip->i_sb, "stack overrun in xtTruncate_pmap!");
+ jfs_error(ip->i_sb, "stack overrun!\n");
XT_PUTPAGE(mp);
return -EIO;
}
@@ -4144,13 +3874,9 @@ s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size)
}
#ifdef CONFIG_JFS_STATISTICS
-int jfs_xtstat_read(char *buffer, char **start, off_t offset, int length,
- int *eof, void *data)
+static int jfs_xtstat_proc_show(struct seq_file *m, void *v)
{
- int len = 0;
- off_t begin;
-
- len += sprintf(buffer,
+ seq_printf(m,
"JFS Xtree statistics\n"
"====================\n"
"searches = %d\n"
@@ -4159,19 +3885,19 @@ int jfs_xtstat_read(char *buffer, char **start, off_t offset, int length,
xtStat.search,
xtStat.fastSearch,
xtStat.split);
+ return 0;
+}
- begin = offset;
- *start = buffer + begin;
- len -= begin;
-
- if (len > length)
- len = length;
- else
- *eof = 1;
-
- if (len < 0)
- len = 0;
-
- return len;
+static int jfs_xtstat_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, jfs_xtstat_proc_show, NULL);
}
+
+const struct file_operations jfs_xtstat_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = jfs_xtstat_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
#endif
diff --git a/fs/jfs/jfs_xtree.h b/fs/jfs/jfs_xtree.h
index 70815c8a3d6..08c0c749b98 100644
--- a/fs/jfs/jfs_xtree.h
+++ b/fs/jfs/jfs_xtree.h
@@ -110,8 +110,6 @@ typedef union {
*/
extern int xtLookup(struct inode *ip, s64 lstart, s64 llen,
int *pflag, s64 * paddr, int *plen, int flag);
-extern int xtLookupList(struct inode *ip, struct lxdlist * lxdlist,
- struct xadlist * xadlist, int flag);
extern void xtInitRoot(tid_t tid, struct inode *ip);
extern int xtInsert(tid_t tid, struct inode *ip,
int xflag, s64 xoff, int xlen, s64 * xaddrp, int flag);
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index 0ba6778edaa..d59c7defb1e 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -18,6 +18,7 @@
*/
#include <linux/fs.h>
+#include <linux/namei.h>
#include <linux/ctype.h>
#include <linux/quotaops.h>
#include <linux/exportfs.h>
@@ -35,7 +36,7 @@
/*
* forward references
*/
-struct dentry_operations jfs_ci_dentry_operations;
+const struct dentry_operations jfs_ci_dentry_operations;
static s64 commitZeroLink(tid_t, struct inode *);
@@ -71,8 +72,8 @@ static inline void free_ea_wmap(struct inode *inode)
* RETURN: Errors from subroutines
*
*/
-static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
- struct nameidata *nd)
+static int jfs_create(struct inode *dip, struct dentry *dentry, umode_t mode,
+ bool excl)
{
int rc = 0;
tid_t tid; /* transaction id */
@@ -85,6 +86,8 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
jfs_info("jfs_create: dip:0x%p name:%s", dip, dentry->d_name.name);
+ dquot_initialize(dip);
+
/*
* search parent directory for entry/freespace
* (dtSearch() returns parent directory page pinned)
@@ -112,7 +115,7 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
if (rc)
goto out3;
- rc = jfs_init_security(tid, ip, dip);
+ rc = jfs_init_security(tid, ip, dip, &dentry->d_name);
if (rc) {
txAbort(tid, 0);
goto out3;
@@ -155,7 +158,6 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
ip->i_fop = &jfs_file_operations;
ip->i_mapping->a_ops = &jfs_aops;
- insert_inode_hash(ip);
mark_inode_dirty(ip);
dip->i_ctime = dip->i_mtime = CURRENT_TIME;
@@ -170,10 +172,13 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
mutex_unlock(&JFS_IP(dip)->commit_mutex);
if (rc) {
free_ea_wmap(ip);
- ip->i_nlink = 0;
+ clear_nlink(ip);
+ unlock_new_inode(ip);
iput(ip);
- } else
+ } else {
+ unlock_new_inode(ip);
d_instantiate(dentry, ip);
+ }
out2:
free_UCSname(&dname);
@@ -200,7 +205,7 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
* note:
* EACCESS: user needs search+write permission on the parent directory
*/
-static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
+static int jfs_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode)
{
int rc = 0;
tid_t tid; /* transaction id */
@@ -213,11 +218,7 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
jfs_info("jfs_mkdir: dip:0x%p name:%s", dip, dentry->d_name.name);
- /* link count overflow on parent directory ? */
- if (dip->i_nlink == JFS_LINK_MAX) {
- rc = -EMLINK;
- goto out1;
- }
+ dquot_initialize(dip);
/*
* search parent directory for entry/freespace
@@ -246,7 +247,7 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
if (rc)
goto out3;
- rc = jfs_init_security(tid, ip, dip);
+ rc = jfs_init_security(tid, ip, dip, &dentry->d_name);
if (rc) {
txAbort(tid, 0);
goto out3;
@@ -285,11 +286,10 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
goto out3;
}
- ip->i_nlink = 2; /* for '.' */
+ set_nlink(ip, 2); /* for '.' */
ip->i_op = &jfs_dir_inode_operations;
ip->i_fop = &jfs_dir_operations;
- insert_inode_hash(ip);
mark_inode_dirty(ip);
/* update parent directory inode */
@@ -305,10 +305,13 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
mutex_unlock(&JFS_IP(dip)->commit_mutex);
if (rc) {
free_ea_wmap(ip);
- ip->i_nlink = 0;
+ clear_nlink(ip);
+ unlock_new_inode(ip);
iput(ip);
- } else
+ } else {
+ unlock_new_inode(ip);
d_instantiate(dentry, ip);
+ }
out2:
free_UCSname(&dname);
@@ -352,7 +355,8 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
jfs_info("jfs_rmdir: dip:0x%p name:%s", dip, dentry->d_name.name);
/* Init inode for quota operations. */
- DQUOT_INIT(ip);
+ dquot_initialize(dip);
+ dquot_initialize(ip);
/* directory must be empty to be removed */
if (!dtEmpty(ip)) {
@@ -479,7 +483,8 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
jfs_info("jfs_unlink: dip:0x%p name:%s", dip, dentry->d_name.name);
/* Init inode for quota operations. */
- DQUOT_INIT(ip);
+ dquot_initialize(dip);
+ dquot_initialize(ip);
if ((rc = get_UCSname(&dname, dentry)))
goto out;
@@ -795,11 +800,7 @@ static int jfs_link(struct dentry *old_dentry,
jfs_info("jfs_link: %s %s", old_dentry->d_name.name,
dentry->d_name.name);
- if (ip->i_nlink == JFS_LINK_MAX)
- return -EMLINK;
-
- if (ip->i_nlink == 0)
- return -ENOENT;
+ dquot_initialize(dir);
tid = txBegin(ip->i_sb, 0);
@@ -827,14 +828,14 @@ static int jfs_link(struct dentry *old_dentry,
ip->i_ctime = CURRENT_TIME;
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
mark_inode_dirty(dir);
- atomic_inc(&ip->i_count);
+ ihold(ip);
iplist[0] = ip;
iplist[1] = dir;
rc = txCommit(tid, 2, &iplist[0], 0);
if (rc) {
- ip->i_nlink--; /* never instantiated */
+ drop_nlink(ip); /* never instantiated */
iput(ip);
} else
d_instantiate(dentry, ip);
@@ -883,7 +884,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
unchar *i_fastsymlink;
s64 xlen = 0;
int bmask = 0, xsize;
- s64 extent = 0, xaddr;
+ s64 xaddr;
struct metapage *mp;
struct super_block *sb;
struct tblock *tblk;
@@ -892,6 +893,8 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
jfs_info("jfs_symlink: dip:0x%p name:%s", dip, name);
+ dquot_initialize(dip);
+
ssize = strlen(name) + 1;
/*
@@ -917,7 +920,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
- rc = jfs_init_security(tid, ip, dip);
+ rc = jfs_init_security(tid, ip, dip, &dentry->d_name);
if (rc)
goto out3;
@@ -942,7 +945,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
*/
if (ssize <= IDATASIZE) {
- ip->i_op = &jfs_symlink_inode_operations;
+ ip->i_op = &jfs_fast_symlink_inode_operations;
i_fastsymlink = JFS_IP(ip)->i_inline;
memcpy(i_fastsymlink, name, ssize);
@@ -964,7 +967,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
else {
jfs_info("jfs_symlink: allocate extent ip:0x%p", ip);
- ip->i_op = &page_symlink_inode_operations;
+ ip->i_op = &jfs_symlink_inode_operations;
ip->i_mapping->a_ops = &jfs_aops;
/*
@@ -981,7 +984,6 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
txAbort(tid, 0);
goto out3;
}
- extent = xaddr;
ip->i_size = ssize - 1;
while (ssize) {
/* This is kind of silly since PATH_MAX == 4K */
@@ -1019,7 +1021,6 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
goto out3;
}
- insert_inode_hash(ip);
mark_inode_dirty(ip);
dip->i_ctime = dip->i_mtime = CURRENT_TIME;
@@ -1038,10 +1039,13 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
mutex_unlock(&JFS_IP(dip)->commit_mutex);
if (rc) {
free_ea_wmap(ip);
- ip->i_nlink = 0;
+ clear_nlink(ip);
+ unlock_new_inode(ip);
iput(ip);
- } else
+ } else {
+ unlock_new_inode(ip);
d_instantiate(dentry, ip);
+ }
out2:
free_UCSname(&dname);
@@ -1081,6 +1085,9 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
jfs_info("jfs_rename: %s %s", old_dentry->d_name.name,
new_dentry->d_name.name);
+ dquot_initialize(old_dir);
+ dquot_initialize(new_dir);
+
old_ip = old_dentry->d_inode;
new_ip = new_dentry->d_inode;
@@ -1122,15 +1129,11 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
rc = -ENOTEMPTY;
goto out3;
}
- } else if ((new_dir != old_dir) &&
- (new_dir->i_nlink == JFS_LINK_MAX)) {
- rc = -EMLINK;
- goto out3;
}
} else if (new_ip) {
IWRITE_LOCK(new_ip, RDWRLOCK_NORMAL);
/* Init inode for quota operations. */
- DQUOT_INIT(new_ip);
+ dquot_initialize(new_ip);
}
/*
@@ -1173,7 +1176,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (!S_ISDIR(old_ip->i_mode) && new_ip)
IWRITE_UNLOCK(new_ip);
jfs_error(new_ip->i_sb,
- "jfs_rename: new_ip->i_nlink != 0");
+ "new_ip->i_nlink != 0\n");
return -EIO;
}
tblk = tid_to_tblock(tid);
@@ -1337,7 +1340,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
* FUNCTION: Create a special file (device)
*/
static int jfs_mknod(struct inode *dir, struct dentry *dentry,
- int mode, dev_t rdev)
+ umode_t mode, dev_t rdev)
{
struct jfs_inode_info *jfs_ip;
struct btstack btstack;
@@ -1354,6 +1357,8 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
jfs_info("jfs_mknod: %s", dentry->d_name.name);
+ dquot_initialize(dir);
+
if ((rc = get_UCSname(&dname, dentry)))
goto out;
@@ -1373,7 +1378,7 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
if (rc)
goto out3;
- rc = jfs_init_security(tid, ip, dir);
+ rc = jfs_init_security(tid, ip, dir, &dentry->d_name);
if (rc) {
txAbort(tid, 0);
goto out3;
@@ -1399,7 +1404,6 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
jfs_ip->dev = new_encode_dev(rdev);
init_special_inode(ip, ip->i_mode, rdev);
- insert_inode_hash(ip);
mark_inode_dirty(ip);
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
@@ -1416,10 +1420,13 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
mutex_unlock(&JFS_IP(dir)->commit_mutex);
if (rc) {
free_ea_wmap(ip);
- ip->i_nlink = 0;
+ clear_nlink(ip);
+ unlock_new_inode(ip);
iput(ip);
- } else
+ } else {
+ unlock_new_inode(ip);
d_instantiate(dentry, ip);
+ }
out1:
free_UCSname(&dname);
@@ -1429,51 +1436,32 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
return rc;
}
-static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, struct nameidata *nd)
+static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, unsigned int flags)
{
struct btstack btstack;
ino_t inum;
struct inode *ip;
struct component_name key;
- const char *name = dentry->d_name.name;
- int len = dentry->d_name.len;
int rc;
- jfs_info("jfs_lookup: name = %s", name);
-
- if (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2)
- dentry->d_op = &jfs_ci_dentry_operations;
-
- if ((name[0] == '.') && (len == 1))
- inum = dip->i_ino;
- else if (strcmp(name, "..") == 0)
- inum = PARENT(dip);
- else {
- if ((rc = get_UCSname(&key, dentry)))
- return ERR_PTR(rc);
- rc = dtSearch(dip, &key, &inum, &btstack, JFS_LOOKUP);
- free_UCSname(&key);
- if (rc == -ENOENT) {
- d_add(dentry, NULL);
- return ERR_PTR(0);
- } else if (rc) {
- jfs_err("jfs_lookup: dtSearch returned %d", rc);
- return ERR_PTR(rc);
- }
- }
-
- ip = jfs_iget(dip->i_sb, inum);
- if (IS_ERR(ip)) {
- jfs_err("jfs_lookup: iget failed on inum %d", (uint) inum);
- return ERR_CAST(ip);
+ jfs_info("jfs_lookup: name = %s", dentry->d_name.name);
+
+ if ((rc = get_UCSname(&key, dentry)))
+ return ERR_PTR(rc);
+ rc = dtSearch(dip, &key, &inum, &btstack, JFS_LOOKUP);
+ free_UCSname(&key);
+ if (rc == -ENOENT) {
+ ip = NULL;
+ } else if (rc) {
+ jfs_err("jfs_lookup: dtSearch returned %d", rc);
+ ip = ERR_PTR(rc);
+ } else {
+ ip = jfs_iget(dip->i_sb, inum);
+ if (IS_ERR(ip))
+ jfs_err("jfs_lookup: iget failed on inum %d", (uint)inum);
}
- dentry = d_splice_alias(ip, dentry);
-
- if (dentry && (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2))
- dentry->d_op = &jfs_ci_dentry_operations;
-
- return dentry;
+ return d_splice_alias(ip, dentry);
}
static struct inode *jfs_nfs_get_inode(struct super_block *sb,
@@ -1511,25 +1499,12 @@ struct dentry *jfs_fh_to_parent(struct super_block *sb, struct fid *fid,
struct dentry *jfs_get_parent(struct dentry *dentry)
{
- struct super_block *sb = dentry->d_inode->i_sb;
- struct dentry *parent = ERR_PTR(-ENOENT);
- struct inode *inode;
unsigned long parent_ino;
parent_ino =
le32_to_cpu(JFS_IP(dentry->d_inode)->i_dtroot.header.idotdot);
- inode = jfs_iget(sb, parent_ino);
- if (IS_ERR(inode)) {
- parent = ERR_CAST(inode);
- } else {
- parent = d_alloc_anon(inode);
- if (!parent) {
- parent = ERR_PTR(-ENOMEM);
- iput(inode);
- }
- }
- return parent;
+ return d_obtain_alias(jfs_iget(dentry->d_inode->i_sb, parent_ino));
}
const struct inode_operations jfs_dir_inode_operations = {
@@ -1546,23 +1521,25 @@ const struct inode_operations jfs_dir_inode_operations = {
.getxattr = jfs_getxattr,
.listxattr = jfs_listxattr,
.removexattr = jfs_removexattr,
-#ifdef CONFIG_JFS_POSIX_ACL
.setattr = jfs_setattr,
- .permission = jfs_permission,
+#ifdef CONFIG_JFS_POSIX_ACL
+ .get_acl = jfs_get_acl,
+ .set_acl = jfs_set_acl,
#endif
};
const struct file_operations jfs_dir_operations = {
.read = generic_read_dir,
- .readdir = jfs_readdir,
+ .iterate = jfs_readdir,
.fsync = jfs_fsync,
.unlocked_ioctl = jfs_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = jfs_compat_ioctl,
#endif
+ .llseek = generic_file_llseek,
};
-static int jfs_ci_hash(struct dentry *dir, struct qstr *this)
+static int jfs_ci_hash(const struct dentry *dir, struct qstr *this)
{
unsigned long hash;
int i;
@@ -1575,32 +1552,57 @@ static int jfs_ci_hash(struct dentry *dir, struct qstr *this)
return 0;
}
-static int jfs_ci_compare(struct dentry *dir, struct qstr *a, struct qstr *b)
+static int jfs_ci_compare(const struct dentry *parent, const struct dentry *dentry,
+ unsigned int len, const char *str, const struct qstr *name)
{
int i, result = 1;
- if (a->len != b->len)
+ if (len != name->len)
goto out;
- for (i=0; i < a->len; i++) {
- if (tolower(a->name[i]) != tolower(b->name[i]))
+ for (i=0; i < len; i++) {
+ if (tolower(str[i]) != tolower(name->name[i]))
goto out;
}
result = 0;
+out:
+ return result;
+}
+static int jfs_ci_revalidate(struct dentry *dentry, unsigned int flags)
+{
/*
- * We want creates to preserve case. A negative dentry, a, that
- * has a different case than b may cause a new entry to be created
- * with the wrong case. Since we can't tell if a comes from a negative
- * dentry, we blindly replace it with b. This should be harmless if
- * a is not a negative dentry.
+ * This is not negative dentry. Always valid.
+ *
+ * Note, rename() to existing directory entry will have ->d_inode,
+ * and will use existing name which isn't specified name by user.
+ *
+ * We may be able to drop this positive dentry here. But dropping
+ * positive dentry isn't good idea. So it's unsupported like
+ * rename("filename", "FILENAME") for now.
*/
- memcpy((unsigned char *)a->name, b->name, a->len);
-out:
- return result;
+ if (dentry->d_inode)
+ return 1;
+
+ /*
+ * This may be nfsd (or something), anyway, we can't see the
+ * intent of this. So, since this can be for creation, drop it.
+ */
+ if (!flags)
+ return 0;
+
+ /*
+ * Drop the negative dentry, in order to make sure to use the
+ * case sensitive name which is specified by user if this is
+ * for creation.
+ */
+ if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
+ return 0;
+ return 1;
}
-struct dentry_operations jfs_ci_dentry_operations =
+const struct dentry_operations jfs_ci_dentry_operations =
{
.d_hash = jfs_ci_hash,
.d_compare = jfs_ci_compare,
+ .d_revalidate = jfs_ci_revalidate,
};
diff --git a/fs/jfs/resize.c b/fs/jfs/resize.c
index 7f24a0bb08c..90b3bc21e9b 100644
--- a/fs/jfs/resize.c
+++ b/fs/jfs/resize.c
@@ -57,7 +57,7 @@
* 2. compute new FSCKSize from new LVSize;
* 3. set new FSSize as MIN(FSSize, LVSize-(LogSize+FSCKSize)) where
* assert(new FSSize >= old FSSize),
- * i.e., file system must not be shrinked;
+ * i.e., file system must not be shrunk;
*/
int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
{
@@ -80,7 +80,8 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
int log_formatted = 0;
struct inode *iplist[1];
struct jfs_superblock *j_sb, *j_sb2;
- uint old_agsize;
+ s64 old_agsize;
+ int agsizechanged = 0;
struct buffer_head *bh, *bh2;
/* If the volume hasn't grown, get out now */
@@ -181,7 +182,7 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
*/
newFSSize = newLVSize - newLogSize - newFSCKSize;
- /* file system cannot be shrinked */
+ /* file system cannot be shrunk */
if (newFSSize < bmp->db_mapsize) {
rc = -EINVAL;
goto out;
@@ -333,6 +334,9 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
*/
if ((rc = dbExtendFS(ipbmap, XAddress, nblocks)))
goto error_out;
+
+ agsizechanged |= (bmp->db_agsize != old_agsize);
+
/*
* the map now has extended to cover additional nblocks:
* dn_mapsize = oldMapsize + nblocks;
@@ -432,7 +436,7 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
* will correctly identify the new ag);
*/
/* if new AG size the same as old AG size, done! */
- if (bmp->db_agsize != old_agsize) {
+ if (agsizechanged) {
if ((rc = diExtendFS(ipimap, ipbmap)))
goto error_out;
@@ -526,7 +530,7 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
goto resume;
error_out:
- jfs_error(sb, "jfs_extendfs");
+ jfs_error(sb, "\n");
resume:
/*
diff --git a/fs/jfs/super.c b/fs/jfs/super.c
index 50ea6545173..adf8cb045b9 100644
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -22,14 +22,18 @@
#include <linux/parser.h>
#include <linux/completion.h>
#include <linux/vfs.h>
+#include <linux/quotaops.h>
#include <linux/mount.h>
#include <linux/moduleparam.h>
#include <linux/kthread.h>
#include <linux/posix_acl.h>
#include <linux/buffer_head.h>
#include <linux/exportfs.h>
+#include <linux/crc32.h>
+#include <linux/slab.h>
#include <asm/uaccess.h>
#include <linux/seq_file.h>
+#include <linux/blkdev.h>
#include "jfs_incore.h"
#include "jfs_filsys.h"
@@ -40,19 +44,20 @@
#include "jfs_imap.h"
#include "jfs_acl.h"
#include "jfs_debug.h"
+#include "jfs_xattr.h"
MODULE_DESCRIPTION("The Journaled Filesystem (JFS)");
MODULE_AUTHOR("Steve Best/Dave Kleikamp/Barry Arndt, IBM");
MODULE_LICENSE("GPL");
-static struct kmem_cache * jfs_inode_cachep;
+static struct kmem_cache *jfs_inode_cachep;
static const struct super_operations jfs_super_operations;
static const struct export_operations jfs_export_operations;
static struct file_system_type jfs_fs_type;
#define MAX_COMMIT_THREADS 64
-static int commit_threads = 0;
+static int commit_threads;
module_param(commit_threads, int, 0);
MODULE_PARM_DESC(commit_threads, "Number of commit threads");
@@ -79,8 +84,7 @@ static void jfs_handle_error(struct super_block *sb)
panic("JFS (device %s): panic forced after error\n",
sb->s_id);
else if (sbi->flag & JFS_ERR_REMOUNT_RO) {
- jfs_err("ERROR: (device %s): remounting filesystem "
- "as read-only\n",
+ jfs_err("ERROR: (device %s): remounting filesystem as read-only\n",
sb->s_id);
sb->s_flags |= MS_RDONLY;
}
@@ -88,16 +92,20 @@ static void jfs_handle_error(struct super_block *sb)
/* nothing is done for continue beyond marking the superblock dirty */
}
-void jfs_error(struct super_block *sb, const char * function, ...)
+void jfs_error(struct super_block *sb, const char *fmt, ...)
{
- static char error_buf[256];
+ struct va_format vaf;
va_list args;
- va_start(args, function);
- vsnprintf(error_buf, sizeof(error_buf), function, args);
- va_end(args);
+ va_start(args, fmt);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
- printk(KERN_ERR "ERROR: (device %s): %s\n", sb->s_id, error_buf);
+ pr_err("ERROR: (device %s): %pf: %pV\n",
+ sb->s_id, __builtin_return_address(0), &vaf);
+
+ va_end(args);
jfs_handle_error(sb);
}
@@ -112,6 +120,13 @@ static struct inode *jfs_alloc_inode(struct super_block *sb)
return &jfs_inode->vfs_inode;
}
+static void jfs_i_callback(struct rcu_head *head)
+{
+ struct inode *inode = container_of(head, struct inode, i_rcu);
+ struct jfs_inode_info *ji = JFS_IP(inode);
+ kmem_cache_free(jfs_inode_cachep, ji);
+}
+
static void jfs_destroy_inode(struct inode *inode)
{
struct jfs_inode_info *ji = JFS_IP(inode);
@@ -125,19 +140,7 @@ static void jfs_destroy_inode(struct inode *inode)
ji->active_ag = -1;
}
spin_unlock_irq(&ji->ag_lock);
-
-#ifdef CONFIG_JFS_POSIX_ACL
- if (ji->i_acl != JFS_ACL_NOT_CACHED) {
- posix_acl_release(ji->i_acl);
- ji->i_acl = JFS_ACL_NOT_CACHED;
- }
- if (ji->i_default_acl != JFS_ACL_NOT_CACHED) {
- posix_acl_release(ji->i_default_acl);
- ji->i_default_acl = JFS_ACL_NOT_CACHED;
- }
-#endif
-
- kmem_cache_free(jfs_inode_cachep, ji);
+ call_rcu(&inode->i_rcu, jfs_i_callback);
}
static int jfs_statfs(struct dentry *dentry, struct kstatfs *buf)
@@ -155,7 +158,7 @@ static int jfs_statfs(struct dentry *dentry, struct kstatfs *buf)
/*
* If we really return the number of allocated & free inodes, some
* applications will fail because they won't see enough free inodes.
- * We'll try to calculate some guess as to how may inodes we can
+ * We'll try to calculate some guess as to how many inodes we can
* really allocate
*
* buf->f_files = atomic_read(&imap->im_numinos);
@@ -167,6 +170,9 @@ static int jfs_statfs(struct dentry *dentry, struct kstatfs *buf)
buf->f_files = maxinodes;
buf->f_ffree = maxinodes - (atomic_read(&imap->im_numinos) -
atomic_read(&imap->im_numfree));
+ buf->f_fsid.val[0] = (u32)crc32_le(0, sbi->uuid, sizeof(sbi->uuid)/2);
+ buf->f_fsid.val[1] = (u32)crc32_le(0, sbi->uuid + sizeof(sbi->uuid)/2,
+ sizeof(sbi->uuid)/2);
buf->f_namelen = JFS_NAME_MAX;
return 0;
@@ -178,16 +184,17 @@ static void jfs_put_super(struct super_block *sb)
int rc;
jfs_info("In jfs_put_super");
+
+ dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);
+
rc = jfs_umount(sb);
if (rc)
jfs_err("jfs_umount failed with return code %d", rc);
- if (sbi->nls_tab)
- unload_nls(sbi->nls_tab);
- sbi->nls_tab = NULL;
+
+ unload_nls(sbi->nls_tab);
truncate_inode_pages(sbi->direct_inode->i_mapping, 0);
iput(sbi->direct_inode);
- sbi->direct_inode = NULL;
kfree(sbi);
}
@@ -195,10 +202,11 @@ static void jfs_put_super(struct super_block *sb)
enum {
Opt_integrity, Opt_nointegrity, Opt_iocharset, Opt_resize,
Opt_resize_nosize, Opt_errors, Opt_ignore, Opt_err, Opt_quota,
- Opt_usrquota, Opt_grpquota, Opt_uid, Opt_gid, Opt_umask
+ Opt_usrquota, Opt_grpquota, Opt_uid, Opt_gid, Opt_umask,
+ Opt_discard, Opt_nodiscard, Opt_discard_minblk
};
-static match_table_t tokens = {
+static const match_table_t tokens = {
{Opt_integrity, "integrity"},
{Opt_nointegrity, "nointegrity"},
{Opt_iocharset, "iocharset=%s"},
@@ -212,6 +220,9 @@ static match_table_t tokens = {
{Opt_uid, "uid=%u"},
{Opt_gid, "gid=%u"},
{Opt_umask, "umask=%u"},
+ {Opt_discard, "discard"},
+ {Opt_nodiscard, "nodiscard"},
+ {Opt_discard_minblk, "discard=%u"},
{Opt_err, NULL}
};
@@ -253,8 +264,7 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize,
else {
nls_map = load_nls(args[0].from);
if (!nls_map) {
- printk(KERN_ERR
- "JFS: charset not found\n");
+ pr_err("JFS: charset not found\n");
goto cleanup;
}
}
@@ -262,7 +272,10 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize,
case Opt_resize:
{
char *resize = args[0].from;
- *newLVSize = simple_strtoull(resize, &resize, 0);
+ int rc = kstrtoll(resize, 0, newLVSize);
+
+ if (rc)
+ goto cleanup;
break;
}
case Opt_resize_nosize:
@@ -270,8 +283,7 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize,
*newLVSize = sb->s_bdev->bd_inode->i_size >>
sb->s_blocksize_bits;
if (*newLVSize == 0)
- printk(KERN_ERR
- "JFS: Cannot determine volume size\n");
+ pr_err("JFS: Cannot determine volume size\n");
break;
}
case Opt_errors:
@@ -292,8 +304,7 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize,
*flag &= ~JFS_ERR_REMOUNT_RO;
*flag |= JFS_ERR_PANIC;
} else {
- printk(KERN_ERR
- "JFS: %s is an invalid error handler\n",
+ pr_err("JFS: %s is an invalid error handler\n",
errors);
goto cleanup;
}
@@ -312,44 +323,96 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize,
case Opt_usrquota:
case Opt_grpquota:
case Opt_quota:
- printk(KERN_ERR
- "JFS: quota operations not supported\n");
+ pr_err("JFS: quota operations not supported\n");
break;
#endif
case Opt_uid:
{
char *uid = args[0].from;
- sbi->uid = simple_strtoul(uid, &uid, 0);
+ uid_t val;
+ int rc = kstrtouint(uid, 0, &val);
+
+ if (rc)
+ goto cleanup;
+ sbi->uid = make_kuid(current_user_ns(), val);
+ if (!uid_valid(sbi->uid))
+ goto cleanup;
break;
}
+
case Opt_gid:
{
char *gid = args[0].from;
- sbi->gid = simple_strtoul(gid, &gid, 0);
+ gid_t val;
+ int rc = kstrtouint(gid, 0, &val);
+
+ if (rc)
+ goto cleanup;
+ sbi->gid = make_kgid(current_user_ns(), val);
+ if (!gid_valid(sbi->gid))
+ goto cleanup;
break;
}
+
case Opt_umask:
{
char *umask = args[0].from;
- sbi->umask = simple_strtoul(umask, &umask, 8);
+ int rc = kstrtouint(umask, 8, &sbi->umask);
+
+ if (rc)
+ goto cleanup;
if (sbi->umask & ~0777) {
- printk(KERN_ERR
- "JFS: Invalid value of umask\n");
+ pr_err("JFS: Invalid value of umask\n");
goto cleanup;
}
break;
}
+
+ case Opt_discard:
+ {
+ struct request_queue *q = bdev_get_queue(sb->s_bdev);
+ /* if set to 1, even copying files will cause
+ * trimming :O
+ * -> user has more control over the online trimming
+ */
+ sbi->minblks_trim = 64;
+ if (blk_queue_discard(q))
+ *flag |= JFS_DISCARD;
+ else
+ pr_err("JFS: discard option not supported on device\n");
+ break;
+ }
+
+ case Opt_nodiscard:
+ *flag &= ~JFS_DISCARD;
+ break;
+
+ case Opt_discard_minblk:
+ {
+ struct request_queue *q = bdev_get_queue(sb->s_bdev);
+ char *minblks_trim = args[0].from;
+ int rc;
+ if (blk_queue_discard(q)) {
+ *flag |= JFS_DISCARD;
+ rc = kstrtouint(minblks_trim, 0,
+ &sbi->minblks_trim);
+ if (rc)
+ goto cleanup;
+ } else
+ pr_err("JFS: discard option not supported on device\n");
+ break;
+ }
+
default:
- printk("jfs: Unrecognized mount option \"%s\" "
- " or missing value\n", p);
+ printk("jfs: Unrecognized mount option \"%s\" or missing value\n",
+ p);
goto cleanup;
}
}
if (nls_map != (void *) -1) {
/* Discard old (if remount) */
- if (sbi->nls_tab)
- unload_nls(sbi->nls_tab);
+ unload_nls(sbi->nls_tab);
sbi->nls_tab = nls_map;
}
return 1;
@@ -365,14 +428,15 @@ static int jfs_remount(struct super_block *sb, int *flags, char *data)
s64 newLVSize = 0;
int rc = 0;
int flag = JFS_SBI(sb)->flag;
+ int ret;
- if (!parse_options(data, sb, &newLVSize, &flag)) {
+ sync_filesystem(sb);
+ if (!parse_options(data, sb, &newLVSize, &flag))
return -EINVAL;
- }
+
if (newLVSize) {
if (sb->s_flags & MS_RDONLY) {
- printk(KERN_ERR
- "JFS: resize requires volume to be mounted read-write\n");
+ pr_err("JFS: resize requires volume to be mounted read-write\n");
return -EROFS;
}
rc = jfs_extendfs(sb, newLVSize, 0);
@@ -388,9 +452,18 @@ static int jfs_remount(struct super_block *sb, int *flags, char *data)
truncate_inode_pages(JFS_SBI(sb)->direct_inode->i_mapping, 0);
JFS_SBI(sb)->flag = flag;
- return jfs_mount_rw(sb, 1);
+ ret = jfs_mount_rw(sb, 1);
+
+ /* mark the fs r/w for quota activity */
+ sb->s_flags &= ~MS_RDONLY;
+
+ dquot_resume(sb, -1);
+ return ret;
}
if ((!(sb->s_flags & MS_RDONLY)) && (*flags & MS_RDONLY)) {
+ rc = dquot_suspend(sb, -1);
+ if (rc < 0)
+ return rc;
rc = jfs_umount_rw(sb);
JFS_SBI(sb)->flag = flag;
return rc;
@@ -400,8 +473,10 @@ static int jfs_remount(struct super_block *sb, int *flags, char *data)
rc = jfs_umount_rw(sb);
if (rc)
return rc;
+
JFS_SBI(sb)->flag = flag;
- return jfs_mount_rw(sb, 1);
+ ret = jfs_mount_rw(sb, 1);
+ return ret;
}
JFS_SBI(sb)->flag = flag;
@@ -421,20 +496,22 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
if (!new_valid_dev(sb->s_bdev->bd_dev))
return -EOVERFLOW;
- sbi = kzalloc(sizeof (struct jfs_sb_info), GFP_KERNEL);
+ sbi = kzalloc(sizeof(struct jfs_sb_info), GFP_KERNEL);
if (!sbi)
return -ENOMEM;
+
sb->s_fs_info = sbi;
+ sb->s_max_links = JFS_LINK_MAX;
sbi->sb = sb;
- sbi->uid = sbi->gid = sbi->umask = -1;
+ sbi->uid = INVALID_UID;
+ sbi->gid = INVALID_GID;
+ sbi->umask = -1;
/* initialize the mount flag and determine the default error handler */
flag = JFS_ERR_REMOUNT_RO;
- if (!parse_options((char *) data, sb, &newLVSize, &flag)) {
- kfree(sbi);
- return -EINVAL;
- }
+ if (!parse_options((char *) data, sb, &newLVSize, &flag))
+ goto out_kfree;
sbi->flag = flag;
#ifdef CONFIG_JFS_POSIX_ACL
@@ -442,8 +519,8 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
#endif
if (newLVSize) {
- printk(KERN_ERR "resize option for remount only\n");
- return -EINVAL;
+ pr_err("resize option for remount only\n");
+ goto out_kfree;
}
/*
@@ -456,6 +533,11 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
*/
sb->s_op = &jfs_super_operations;
sb->s_export_op = &jfs_export_operations;
+ sb->s_xattr = jfs_xattr_handlers;
+#ifdef CONFIG_QUOTA
+ sb->dq_op = &dquot_operations;
+ sb->s_qcop = &dquot_quotactl_ops;
+#endif
/*
* Initialize direct-mapping inode/address-space
@@ -463,10 +545,9 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
inode = new_inode(sb);
if (inode == NULL) {
ret = -ENOMEM;
- goto out_kfree;
+ goto out_unload;
}
inode->i_ino = 0;
- inode->i_nlink = 1;
inode->i_size = sb->s_bdev->bd_inode->i_size;
inode->i_mapping->a_ops = &jfs_metapage_aops;
insert_inode_hash(inode);
@@ -476,9 +557,8 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
rc = jfs_mount(sb);
if (rc) {
- if (!silent) {
+ if (!silent)
jfs_err("jfs_mount failed w/return code = %d", rc);
- }
goto out_mount_failed;
}
if (sb->s_flags & MS_RDONLY)
@@ -496,18 +576,18 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
sb->s_magic = JFS_SUPER_MAGIC;
+ if (sbi->mntflag & JFS_OS2)
+ sb->s_d_op = &jfs_ci_dentry_operations;
+
inode = jfs_iget(sb, ROOT_I);
if (IS_ERR(inode)) {
ret = PTR_ERR(inode);
- goto out_no_root;
+ goto out_no_rw;
}
- sb->s_root = d_alloc_root(inode);
+ sb->s_root = d_make_root(inode);
if (!sb->s_root)
goto out_no_root;
- if (sbi->mntflag & JFS_OS2)
- sb->s_root->d_op = &jfs_ci_dentry_operations;
-
/* logical blocks are represented by 40 bits in pxd_t, etc. */
sb->s_maxbytes = ((u64) sb->s_blocksize) << 40;
#if BITS_PER_LONG == 32
@@ -515,66 +595,88 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
* Page cache is indexed by long.
* I would use MAX_LFS_FILESIZE, but it's only half as big
*/
- sb->s_maxbytes = min(((u64) PAGE_CACHE_SIZE << 32) - 1, sb->s_maxbytes);
+ sb->s_maxbytes = min(((u64) PAGE_CACHE_SIZE << 32) - 1,
+ (u64)sb->s_maxbytes);
#endif
sb->s_time_gran = 1;
return 0;
out_no_root:
- jfs_err("jfs_read_super: get root inode failed");
- if (inode)
- iput(inode);
+ jfs_err("jfs_read_super: get root dentry failed");
out_no_rw:
rc = jfs_umount(sb);
- if (rc) {
+ if (rc)
jfs_err("jfs_umount failed with return code %d", rc);
- }
out_mount_failed:
filemap_write_and_wait(sbi->direct_inode->i_mapping);
truncate_inode_pages(sbi->direct_inode->i_mapping, 0);
make_bad_inode(sbi->direct_inode);
iput(sbi->direct_inode);
sbi->direct_inode = NULL;
-out_kfree:
+out_unload:
if (sbi->nls_tab)
unload_nls(sbi->nls_tab);
+out_kfree:
kfree(sbi);
return ret;
}
-static void jfs_write_super_lockfs(struct super_block *sb)
+static int jfs_freeze(struct super_block *sb)
{
struct jfs_sb_info *sbi = JFS_SBI(sb);
struct jfs_log *log = sbi->log;
+ int rc = 0;
if (!(sb->s_flags & MS_RDONLY)) {
txQuiesce(sb);
- lmLogShutdown(log);
- updateSuper(sb, FM_CLEAN);
+ rc = lmLogShutdown(log);
+ if (rc) {
+ jfs_error(sb, "lmLogShutdown failed\n");
+
+ /* let operations fail rather than hang */
+ txResume(sb);
+
+ return rc;
+ }
+ rc = updateSuper(sb, FM_CLEAN);
+ if (rc) {
+ jfs_err("jfs_freeze: updateSuper failed\n");
+ /*
+ * Don't fail here. Everything succeeded except
+ * marking the superblock clean, so there's really
+ * no harm in leaving it frozen for now.
+ */
+ }
}
+ return 0;
}
-static void jfs_unlockfs(struct super_block *sb)
+static int jfs_unfreeze(struct super_block *sb)
{
struct jfs_sb_info *sbi = JFS_SBI(sb);
struct jfs_log *log = sbi->log;
int rc = 0;
if (!(sb->s_flags & MS_RDONLY)) {
- updateSuper(sb, FM_MOUNT);
- if ((rc = lmLogInit(log)))
- jfs_err("jfs_unlock failed with return code %d", rc);
- else
- txResume(sb);
+ rc = updateSuper(sb, FM_MOUNT);
+ if (rc) {
+ jfs_error(sb, "updateSuper failed\n");
+ goto out;
+ }
+ rc = lmLogInit(log);
+ if (rc)
+ jfs_error(sb, "lmLogInit failed\n");
+out:
+ txResume(sb);
}
+ return rc;
}
-static int jfs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data, struct vfsmount *mnt)
+static struct dentry *jfs_do_mount(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, jfs_fill_super,
- mnt);
+ return mount_bdev(fs_type, flags, dev_name, data, jfs_fill_super);
}
static int jfs_sync_fs(struct super_block *sb, int wait)
@@ -583,6 +685,11 @@ static int jfs_sync_fs(struct super_block *sb, int wait)
/* log == NULL indicates read-only mount */
if (log) {
+ /*
+ * Write quota structures to quota file, sync_blockdev() will
+ * write them to disk later
+ */
+ dquot_writeback_dquots(sb, -1);
jfs_flush_journal(log, wait);
jfs_syncpt(log, 0);
}
@@ -590,18 +697,20 @@ static int jfs_sync_fs(struct super_block *sb, int wait)
return 0;
}
-static int jfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
+static int jfs_show_options(struct seq_file *seq, struct dentry *root)
{
- struct jfs_sb_info *sbi = JFS_SBI(vfs->mnt_sb);
+ struct jfs_sb_info *sbi = JFS_SBI(root->d_sb);
- if (sbi->uid != -1)
- seq_printf(seq, ",uid=%d", sbi->uid);
- if (sbi->gid != -1)
- seq_printf(seq, ",gid=%d", sbi->gid);
+ if (uid_valid(sbi->uid))
+ seq_printf(seq, ",uid=%d", from_kuid(&init_user_ns, sbi->uid));
+ if (gid_valid(sbi->gid))
+ seq_printf(seq, ",gid=%d", from_kgid(&init_user_ns, sbi->gid));
if (sbi->umask != -1)
seq_printf(seq, ",umask=%03o", sbi->umask);
if (sbi->flag & JFS_NOINTEGRITY)
seq_puts(seq, ",nointegrity");
+ if (sbi->flag & JFS_DISCARD)
+ seq_printf(seq, ",discard=%u", sbi->minblks_trim);
if (sbi->nls_tab)
seq_printf(seq, ",iocharset=%s", sbi->nls_tab->charset);
if (sbi->flag & JFS_ERR_CONTINUE)
@@ -624,7 +733,7 @@ static int jfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
/* Read data from quotafile - avoid pagecache and such because we cannot afford
* acquiring the locks... As quota files are never truncated and quota code
- * itself serializes the operations (and noone else should touch the files)
+ * itself serializes the operations (and no one else should touch the files)
* we don't have to be afraid of races */
static ssize_t jfs_quota_read(struct super_block *sb, int type, char *data,
size_t len, loff_t off)
@@ -714,8 +823,10 @@ static ssize_t jfs_quota_write(struct super_block *sb, int type,
blk++;
}
out:
- if (len == towrite)
+ if (len == towrite) {
+ mutex_unlock(&inode->i_mutex);
return err;
+ }
if (inode->i_size < off+len-towrite)
i_size_write(inode, off+len-towrite);
inode->i_version++;
@@ -732,11 +843,11 @@ static const struct super_operations jfs_super_operations = {
.destroy_inode = jfs_destroy_inode,
.dirty_inode = jfs_dirty_inode,
.write_inode = jfs_write_inode,
- .delete_inode = jfs_delete_inode,
+ .evict_inode = jfs_evict_inode,
.put_super = jfs_put_super,
.sync_fs = jfs_sync_fs,
- .write_super_lockfs = jfs_write_super_lockfs,
- .unlockfs = jfs_unlockfs,
+ .freeze_fs = jfs_freeze,
+ .unfreeze_fs = jfs_unfreeze,
.statfs = jfs_statfs,
.remount_fs = jfs_remount,
.show_options = jfs_show_options,
@@ -755,12 +866,13 @@ static const struct export_operations jfs_export_operations = {
static struct file_system_type jfs_fs_type = {
.owner = THIS_MODULE,
.name = "jfs",
- .get_sb = jfs_get_sb,
+ .mount = jfs_do_mount,
.kill_sb = kill_block_super,
.fs_flags = FS_REQUIRES_DEV,
};
+MODULE_ALIAS_FS("jfs");
-static void init_once(struct kmem_cache *cachep, void *foo)
+static void init_once(void *foo)
{
struct jfs_inode_info *jfs_ip = (struct jfs_inode_info *) foo;
@@ -771,10 +883,6 @@ static void init_once(struct kmem_cache *cachep, void *foo)
init_rwsem(&jfs_ip->xattr_sem);
spin_lock_init(&jfs_ip->ag_lock);
jfs_ip->active_ag = -1;
-#ifdef CONFIG_JFS_POSIX_ACL
- jfs_ip->i_acl = JFS_ACL_NOT_CACHED;
- jfs_ip->i_default_acl = JFS_ACL_NOT_CACHED;
-#endif
inode_init_once(&jfs_ip->vfs_inode);
}
@@ -824,7 +932,8 @@ static int __init init_jfs_fs(void)
commit_threads = MAX_COMMIT_THREADS;
for (i = 0; i < commit_threads; i++) {
- jfsCommitThread[i] = kthread_run(jfs_lazycommit, NULL, "jfsCommit");
+ jfsCommitThread[i] = kthread_run(jfs_lazycommit, NULL,
+ "jfsCommit");
if (IS_ERR(jfsCommitThread[i])) {
rc = PTR_ERR(jfsCommitThread[i]);
jfs_err("init_jfs_fs: fork failed w/rc = %d", rc);
@@ -844,8 +953,14 @@ static int __init init_jfs_fs(void)
jfs_proc_init();
#endif
- return register_filesystem(&jfs_fs_type);
+ rc = register_filesystem(&jfs_fs_type);
+ if (!rc)
+ return 0;
+#ifdef PROC_FS_JFS
+ jfs_proc_clean();
+#endif
+ kthread_stop(jfsSyncThread);
kill_committask:
for (i = 0; i < commit_threads; i++)
kthread_stop(jfsCommitThread[i]);
@@ -876,6 +991,12 @@ static void __exit exit_jfs_fs(void)
jfs_proc_clean();
#endif
unregister_filesystem(&jfs_fs_type);
+
+ /*
+ * Make sure all delayed rcu free inodes are flushed before we
+ * destroy cache.
+ */
+ rcu_barrier();
kmem_cache_destroy(jfs_inode_cachep);
}
diff --git a/fs/jfs/symlink.c b/fs/jfs/symlink.c
index 4af1a05aad0..205b946d8e0 100644
--- a/fs/jfs/symlink.c
+++ b/fs/jfs/symlink.c
@@ -29,9 +29,21 @@ static void *jfs_follow_link(struct dentry *dentry, struct nameidata *nd)
return NULL;
}
-const struct inode_operations jfs_symlink_inode_operations = {
+const struct inode_operations jfs_fast_symlink_inode_operations = {
.readlink = generic_readlink,
.follow_link = jfs_follow_link,
+ .setattr = jfs_setattr,
+ .setxattr = jfs_setxattr,
+ .getxattr = jfs_getxattr,
+ .listxattr = jfs_listxattr,
+ .removexattr = jfs_removexattr,
+};
+
+const struct inode_operations jfs_symlink_inode_operations = {
+ .readlink = generic_readlink,
+ .follow_link = page_follow_link_light,
+ .put_link = page_put_link,
+ .setattr = jfs_setattr,
.setxattr = jfs_setxattr,
.getxattr = jfs_getxattr,
.listxattr = jfs_listxattr,
diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c
index 9b7f2cdaae0..46325d5c34f 100644
--- a/fs/jfs/xattr.c
+++ b/fs/jfs/xattr.c
@@ -21,6 +21,7 @@
#include <linux/fs.h>
#include <linux/xattr.h>
#include <linux/posix_acl_xattr.h>
+#include <linux/slab.h>
#include <linux/quotaops.h>
#include <linux/security.h>
#include "jfs_incore.h"
@@ -85,46 +86,25 @@ struct ea_buffer {
#define EA_MALLOC 0x0008
+static int is_known_namespace(const char *name)
+{
+ if (strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) &&
+ strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) &&
+ strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) &&
+ strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN))
+ return false;
+
+ return true;
+}
+
/*
* These three routines are used to recognize on-disk extended attributes
* that are in a recognized namespace. If the attribute is not recognized,
* "os2." is prepended to the name
*/
-static inline int is_os2_xattr(struct jfs_ea *ea)
+static int is_os2_xattr(struct jfs_ea *ea)
{
- /*
- * Check for "system."
- */
- if ((ea->namelen >= XATTR_SYSTEM_PREFIX_LEN) &&
- !strncmp(ea->name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
- return false;
- /*
- * Check for "user."
- */
- if ((ea->namelen >= XATTR_USER_PREFIX_LEN) &&
- !strncmp(ea->name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
- return false;
- /*
- * Check for "security."
- */
- if ((ea->namelen >= XATTR_SECURITY_PREFIX_LEN) &&
- !strncmp(ea->name, XATTR_SECURITY_PREFIX,
- XATTR_SECURITY_PREFIX_LEN))
- return false;
- /*
- * Check for "trusted."
- */
- if ((ea->namelen >= XATTR_TRUSTED_PREFIX_LEN) &&
- !strncmp(ea->name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN))
- return false;
- /*
- * Add any other valid namespace prefixes here
- */
-
- /*
- * We assume it's OS/2's flat namespace
- */
- return true;
+ return !is_known_namespace(ea->name);
}
static inline int name_size(struct jfs_ea *ea)
@@ -260,14 +240,14 @@ static int ea_write(struct inode *ip, struct jfs_ea_list *ealist, int size,
nblocks = (size + (sb->s_blocksize - 1)) >> sb->s_blocksize_bits;
/* Allocate new blocks to quota. */
- if (DQUOT_ALLOC_BLOCK(ip, nblocks)) {
- return -EDQUOT;
- }
+ rc = dquot_alloc_block(ip, nblocks);
+ if (rc)
+ return rc;
rc = dbAlloc(ip, INOHINT(ip), nblocks, &blkno);
if (rc) {
/*Rollback quota allocation. */
- DQUOT_FREE_BLOCK(ip, nblocks);
+ dquot_free_block(ip, nblocks);
return rc;
}
@@ -332,7 +312,7 @@ static int ea_write(struct inode *ip, struct jfs_ea_list *ealist, int size,
failed:
/* Rollback quota allocation. */
- DQUOT_FREE_BLOCK(ip, nblocks);
+ dquot_free_block(ip, nblocks);
dbFree(ip, blkno, nblocks);
return rc;
@@ -402,7 +382,7 @@ static int ea_read(struct inode *ip, struct jfs_ea_list *ealist)
nbytes = sizeDXD(&ji->ea);
if (!nbytes) {
- jfs_error(sb, "ea_read: nbytes is 0");
+ jfs_error(sb, "nbytes is 0\n");
return -EIO;
}
@@ -502,7 +482,7 @@ static int ea_get(struct inode *inode, struct ea_buffer *ea_buf, int min_size)
current_blocks = 0;
} else {
if (!(ji->ea.flag & DXD_EXTENT)) {
- jfs_error(sb, "ea_get: invalid ea.flag)");
+ jfs_error(sb, "invalid ea.flag\n");
return -EIO;
}
current_blocks = (ea_size + sb->s_blocksize - 1) >>
@@ -538,7 +518,8 @@ static int ea_get(struct inode *inode, struct ea_buffer *ea_buf, int min_size)
if (blocks_needed > current_blocks) {
/* Allocate new blocks to quota. */
- if (DQUOT_ALLOC_BLOCK(inode, blocks_needed))
+ rc = dquot_alloc_block(inode, blocks_needed);
+ if (rc)
return -EDQUOT;
quota_allocation = blocks_needed;
@@ -602,7 +583,7 @@ static int ea_get(struct inode *inode, struct ea_buffer *ea_buf, int min_size)
clean_up:
/* Rollback quota allocation */
if (quota_allocation)
- DQUOT_FREE_BLOCK(inode, quota_allocation);
+ dquot_free_block(inode, quota_allocation);
return (rc);
}
@@ -677,7 +658,7 @@ static int ea_put(tid_t tid, struct inode *inode, struct ea_buffer *ea_buf,
/* If old blocks exist, they must be removed from quota allocation. */
if (old_blocks)
- DQUOT_FREE_BLOCK(inode, old_blocks);
+ dquot_free_block(inode, old_blocks);
inode->i_ctime = CURRENT_TIME;
@@ -685,96 +666,29 @@ static int ea_put(tid_t tid, struct inode *inode, struct ea_buffer *ea_buf,
}
/*
- * can_set_system_xattr
- *
- * This code is specific to the system.* namespace. It contains policy
- * which doesn't belong in the main xattr codepath.
- */
-static int can_set_system_xattr(struct inode *inode, const char *name,
- const void *value, size_t value_len)
-{
-#ifdef CONFIG_JFS_POSIX_ACL
- struct posix_acl *acl;
- int rc;
-
- if (!is_owner_or_cap(inode))
- return -EPERM;
-
- /*
- * POSIX_ACL_XATTR_ACCESS is tied to i_mode
- */
- if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) {
- acl = posix_acl_from_xattr(value, value_len);
- if (IS_ERR(acl)) {
- rc = PTR_ERR(acl);
- printk(KERN_ERR "posix_acl_from_xattr returned %d\n",
- rc);
- return rc;
- }
- if (acl) {
- mode_t mode = inode->i_mode;
- rc = posix_acl_equiv_mode(acl, &mode);
- posix_acl_release(acl);
- if (rc < 0) {
- printk(KERN_ERR
- "posix_acl_equiv_mode returned %d\n",
- rc);
- return rc;
- }
- inode->i_mode = mode;
- mark_inode_dirty(inode);
- }
- /*
- * We're changing the ACL. Get rid of the cached one
- */
- acl =JFS_IP(inode)->i_acl;
- if (acl != JFS_ACL_NOT_CACHED)
- posix_acl_release(acl);
- JFS_IP(inode)->i_acl = JFS_ACL_NOT_CACHED;
-
- return 0;
- } else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) {
- acl = posix_acl_from_xattr(value, value_len);
- if (IS_ERR(acl)) {
- rc = PTR_ERR(acl);
- printk(KERN_ERR "posix_acl_from_xattr returned %d\n",
- rc);
- return rc;
- }
- posix_acl_release(acl);
-
- /*
- * We're changing the default ACL. Get rid of the cached one
- */
- acl =JFS_IP(inode)->i_default_acl;
- if (acl && (acl != JFS_ACL_NOT_CACHED))
- posix_acl_release(acl);
- JFS_IP(inode)->i_default_acl = JFS_ACL_NOT_CACHED;
-
- return 0;
- }
-#endif /* CONFIG_JFS_POSIX_ACL */
- return -EOPNOTSUPP;
-}
-
-/*
* Most of the permission checking is done by xattr_permission in the vfs.
- * The local file system is responsible for handling the system.* namespace.
* We also need to verify that this is a namespace that we recognize.
*/
static int can_set_xattr(struct inode *inode, const char *name,
const void *value, size_t value_len)
{
- if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
- return can_set_system_xattr(inode, name, value, value_len);
+ if (!strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN)) {
+ /*
+ * This makes sure that we aren't trying to set an
+ * attribute in a different namespace by prefixing it
+ * with "os2."
+ */
+ if (is_known_namespace(name + XATTR_OS2_PREFIX_LEN))
+ return -EOPNOTSUPP;
+ return 0;
+ }
/*
* Don't allow setting an attribute in an unknown namespace.
*/
if (strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) &&
strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) &&
- strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) &&
- strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN))
+ strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
return -EOPNOTSUPP;
return 0;
@@ -877,6 +791,19 @@ int __jfs_setxattr(tid_t tid, struct inode *inode, const char *name,
/* Completely new ea list */
xattr_size = sizeof (struct jfs_ea_list);
+ /*
+ * The size of EA value is limitted by on-disk format up to
+ * __le16, there would be an overflow if the size is equal
+ * to XATTR_SIZE_MAX (65536). In order to avoid this issue,
+ * we can pre-checkup the value size against USHRT_MAX, and
+ * return -E2BIG in this case, which is consistent with the
+ * VFS setxattr interface.
+ */
+ if (value_len >= USHRT_MAX) {
+ rc = -E2BIG;
+ goto release;
+ }
+
ea = (struct jfs_ea *) ((char *) ealist + xattr_size);
ea->flag = 0;
ea->namelen = namelen;
@@ -891,7 +818,7 @@ int __jfs_setxattr(tid_t tid, struct inode *inode, const char *name,
/* DEBUG - If we did this right, these number match */
if (xattr_size != new_size) {
printk(KERN_ERR
- "jfs_xsetattr: xattr_size = %d, new_size = %d\n",
+ "__jfs_setxattr: xattr_size = %d, new_size = %d\n",
xattr_size, new_size);
rc = -EINVAL;
@@ -927,6 +854,14 @@ int jfs_setxattr(struct dentry *dentry, const char *name, const void *value,
int rc;
tid_t tid;
+ /*
+ * If this is a request for a synthetic attribute in the system.*
+ * namespace use the generic infrastructure to resolve a handler
+ * for it via sb->s_xattr.
+ */
+ if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
+ return generic_setxattr(dentry, name, value, value_len, flags);
+
if ((rc = can_set_xattr(inode, name, value, value_len)))
return rc;
@@ -956,19 +891,8 @@ ssize_t __jfs_getxattr(struct inode *inode, const char *name, void *data,
int xattr_size;
ssize_t size;
int namelen = strlen(name);
- char *os2name = NULL;
char *value;
- if (strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) {
- os2name = kmalloc(namelen - XATTR_OS2_PREFIX_LEN + 1,
- GFP_KERNEL);
- if (!os2name)
- return -ENOMEM;
- strcpy(os2name, name + XATTR_OS2_PREFIX_LEN);
- name = os2name;
- namelen -= XATTR_OS2_PREFIX_LEN;
- }
-
down_read(&JFS_IP(inode)->xattr_sem);
xattr_size = ea_get(inode, &ea_buf, 0);
@@ -1006,8 +930,6 @@ ssize_t __jfs_getxattr(struct inode *inode, const char *name, void *data,
out:
up_read(&JFS_IP(inode)->xattr_sem);
- kfree(os2name);
-
return size;
}
@@ -1016,6 +938,27 @@ ssize_t jfs_getxattr(struct dentry *dentry, const char *name, void *data,
{
int err;
+ /*
+ * If this is a request for a synthetic attribute in the system.*
+ * namespace use the generic infrastructure to resolve a handler
+ * for it via sb->s_xattr.
+ */
+ if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
+ return generic_getxattr(dentry, name, data, buf_size);
+
+ if (strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) {
+ /*
+ * skip past "os2." prefix
+ */
+ name += XATTR_OS2_PREFIX_LEN;
+ /*
+ * Don't allow retrieving properly prefixed attributes
+ * by prepending them with "os2."
+ */
+ if (is_known_namespace(name))
+ return -EOPNOTSUPP;
+ }
+
err = __jfs_getxattr(dentry->d_inode, name, data, buf_size);
return err;
@@ -1091,6 +1034,14 @@ int jfs_removexattr(struct dentry *dentry, const char *name)
int rc;
tid_t tid;
+ /*
+ * If this is a request for a synthetic attribute in the system.*
+ * namespace use the generic infrastructure to resolve a handler
+ * for it via sb->s_xattr.
+ */
+ if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
+ return generic_removexattr(dentry, name);
+
if ((rc = can_set_xattr(inode, name, NULL, 0)))
return rc;
@@ -1105,37 +1056,51 @@ int jfs_removexattr(struct dentry *dentry, const char *name)
return rc;
}
+/*
+ * List of handlers for synthetic system.* attributes. All real ondisk
+ * attributes are handled directly.
+ */
+const struct xattr_handler *jfs_xattr_handlers[] = {
+#ifdef CONFIG_JFS_POSIX_ACL
+ &posix_acl_access_xattr_handler,
+ &posix_acl_default_xattr_handler,
+#endif
+ NULL,
+};
+
+
#ifdef CONFIG_JFS_SECURITY
-int jfs_init_security(tid_t tid, struct inode *inode, struct inode *dir)
+static int jfs_initxattrs(struct inode *inode, const struct xattr *xattr_array,
+ void *fs_info)
{
- int rc;
- size_t len;
- void *value;
- char *suffix;
+ const struct xattr *xattr;
+ tid_t *tid = fs_info;
char *name;
-
- rc = security_inode_init_security(inode, dir, &suffix, &value, &len);
- if (rc) {
- if (rc == -EOPNOTSUPP)
- return 0;
- return rc;
- }
- name = kmalloc(XATTR_SECURITY_PREFIX_LEN + 1 + strlen(suffix),
- GFP_NOFS);
- if (!name) {
- rc = -ENOMEM;
- goto kmalloc_failed;
+ int err = 0;
+
+ for (xattr = xattr_array; xattr->name != NULL; xattr++) {
+ name = kmalloc(XATTR_SECURITY_PREFIX_LEN +
+ strlen(xattr->name) + 1, GFP_NOFS);
+ if (!name) {
+ err = -ENOMEM;
+ break;
+ }
+ strcpy(name, XATTR_SECURITY_PREFIX);
+ strcpy(name + XATTR_SECURITY_PREFIX_LEN, xattr->name);
+
+ err = __jfs_setxattr(*tid, inode, name,
+ xattr->value, xattr->value_len, 0);
+ kfree(name);
+ if (err < 0)
+ break;
}
- strcpy(name, XATTR_SECURITY_PREFIX);
- strcpy(name + XATTR_SECURITY_PREFIX_LEN, suffix);
-
- rc = __jfs_setxattr(tid, inode, name, value, len, 0);
-
- kfree(name);
-kmalloc_failed:
- kfree(suffix);
- kfree(value);
+ return err;
+}
- return rc;
+int jfs_init_security(tid_t tid, struct inode *inode, struct inode *dir,
+ const struct qstr *qstr)
+{
+ return security_inode_init_security(inode, dir, qstr,
+ &jfs_initxattrs, &tid);
}
#endif