diff options
Diffstat (limited to 'fs/jfs')
| -rw-r--r-- | fs/jfs/Makefile | 4 | ||||
| -rw-r--r-- | fs/jfs/acl.c | 136 | ||||
| -rw-r--r-- | fs/jfs/file.c | 43 | ||||
| -rw-r--r-- | fs/jfs/inode.c | 40 | ||||
| -rw-r--r-- | fs/jfs/ioctl.c | 51 | ||||
| -rw-r--r-- | fs/jfs/jfs_acl.h | 9 | ||||
| -rw-r--r-- | fs/jfs/jfs_discard.c | 121 | ||||
| -rw-r--r-- | fs/jfs/jfs_discard.h | 26 | ||||
| -rw-r--r-- | fs/jfs/jfs_dmap.c | 206 | ||||
| -rw-r--r-- | fs/jfs/jfs_dmap.h | 2 | ||||
| -rw-r--r-- | fs/jfs/jfs_dtree.c | 125 | ||||
| -rw-r--r-- | fs/jfs/jfs_dtree.h | 2 | ||||
| -rw-r--r-- | fs/jfs/jfs_extent.c | 8 | ||||
| -rw-r--r-- | fs/jfs/jfs_filsys.h | 3 | ||||
| -rw-r--r-- | fs/jfs/jfs_imap.c | 125 | ||||
| -rw-r--r-- | fs/jfs/jfs_incore.h | 12 | ||||
| -rw-r--r-- | fs/jfs/jfs_inode.c | 21 | ||||
| -rw-r--r-- | fs/jfs/jfs_inode.h | 4 | ||||
| -rw-r--r-- | fs/jfs/jfs_logmgr.c | 47 | ||||
| -rw-r--r-- | fs/jfs/jfs_logmgr.h | 2 | ||||
| -rw-r--r-- | fs/jfs/jfs_metapage.c | 20 | ||||
| -rw-r--r-- | fs/jfs/jfs_metapage.h | 2 | ||||
| -rw-r--r-- | fs/jfs/jfs_superblock.h | 1 | ||||
| -rw-r--r-- | fs/jfs/jfs_txnmgr.c | 23 | ||||
| -rw-r--r-- | fs/jfs/jfs_umount.c | 4 | ||||
| -rw-r--r-- | fs/jfs/jfs_xattr.h | 7 | ||||
| -rw-r--r-- | fs/jfs/jfs_xtree.c | 62 | ||||
| -rw-r--r-- | fs/jfs/namei.c | 167 | ||||
| -rw-r--r-- | fs/jfs/resize.c | 8 | ||||
| -rw-r--r-- | fs/jfs/super.c | 243 | ||||
| -rw-r--r-- | fs/jfs/xattr.c | 184 | 
31 files changed, 1024 insertions, 684 deletions
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 1057a4998e4..0c8ca830b11 100644 --- a/fs/jfs/acl.c +++ b/fs/jfs/acl.c @@ -27,7 +27,7 @@  #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; @@ -64,7 +64,7 @@ static struct posix_acl *jfs_get_acl(struct inode *inode, int type)  		else  			acl = ERR_PTR(size);  	} else { -		acl = posix_acl_from_xattr(value, size); +		acl = posix_acl_from_xattr(&init_user_ns, value, size);  	}  	kfree(value);  	if (!IS_ERR(acl)) @@ -72,7 +72,7 @@ static struct posix_acl *jfs_get_acl(struct inode *inode, int type)  	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; @@ -80,27 +80,32 @@ static int jfs_set_acl(tid_t tid, struct inode *inode, int type,  	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; -			break; -		case ACL_TYPE_DEFAULT: -			ea_name = POSIX_ACL_XATTR_DEFAULT; -			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;  	} @@ -114,94 +119,43 @@ out:  	return rc;  } -int jfs_check_acl(struct inode *inode, int mask) +int jfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)  { -	struct posix_acl *acl = jfs_get_acl(inode, ACL_TYPE_ACCESS); - -	if (IS_ERR(acl)) -		return PTR_ERR(acl); -	if (acl) { -		int error = posix_acl_permission(inode, acl, mask); -		posix_acl_release(acl); -		return error; -	} +	int rc; +	tid_t tid; -	return -EAGAIN; +	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_init_acl(tid_t tid, struct inode *inode, struct inode *dir)  { -	struct posix_acl *acl = NULL; -	struct posix_acl *clone; -	mode_t mode; +	struct posix_acl *default_acl, *acl;  	int rc = 0; -	if (S_ISLNK(inode->i_mode)) -		return 0; +	rc = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); +	if (rc) +		return rc; -	acl = jfs_get_acl(dir, ACL_TYPE_DEFAULT); -	if (IS_ERR(acl)) -		return PTR_ERR(acl); +	if (default_acl) { +		rc = __jfs_set_acl(tid, inode, ACL_TYPE_DEFAULT, default_acl); +		posix_acl_release(default_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: +		if (!rc) +			rc = __jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, acl);  		posix_acl_release(acl); -	} else -		inode->i_mode &= ~current_umask(); +	}  	JFS_IP(inode)->mode2 = (JFS_IP(inode)->mode2 & 0xffff0000) |  			       inode->i_mode;  	return rc;  } - -int jfs_acl_chmod(struct inode *inode) -{ -	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); -	return rc; -} diff --git a/fs/jfs/file.c b/fs/jfs/file.c index c5ce6c1d1ff..33aa0cc1f8b 100644 --- a/fs/jfs/file.c +++ b/fs/jfs/file.c @@ -19,6 +19,7 @@  #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" @@ -28,19 +29,26 @@  #include "jfs_acl.h"  #include "jfs_debug.h" -int jfs_fsync(struct file *file, int datasync) +int jfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)  {  	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;  } @@ -66,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);  	} @@ -101,8 +109,8 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr)  	if (is_quota_modification(inode, iattr))  		dquot_initialize(inode); -	if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) || -	    (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) { +	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; @@ -110,41 +118,46 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr)  	if ((iattr->ia_valid & ATTR_SIZE) &&  	    iattr->ia_size != i_size_read(inode)) { -		rc = vmtruncate(inode, iattr->ia_size); +		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 = jfs_acl_chmod(inode); +		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,  	.setattr	= jfs_setattr,  #ifdef CONFIG_JFS_POSIX_ACL -	.check_acl	= jfs_check_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 9978803ceed..bd3df1ca3c9 100644 --- a/fs/jfs/inode.c +++ b/fs/jfs/inode.c @@ -23,6 +23,7 @@  #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" @@ -125,7 +126,7 @@ int jfs_write_inode(struct inode *inode, struct writeback_control *wbc)  {  	int wait = wbc->sync_mode == WB_SYNC_ALL; -	if (test_cflag(COMMIT_Nolink, inode)) +	if (inode->i_nlink == 0)  		return 0;  	/*  	 * If COMMIT_DIRTY is not set, the inode isn't really dirty. @@ -153,7 +154,7 @@ void jfs_evict_inode(struct inode *inode)  		dquot_initialize(inode);  		if (JFS_IP(inode)->fileset == FILESYSTEM_I) { -			truncate_inode_pages(&inode->i_data, 0); +			truncate_inode_pages_final(&inode->i_data);  			if (test_cflag(COMMIT_Freewmap, inode))  				jfs_free_zero_link(inode); @@ -167,13 +168,13 @@ void jfs_evict_inode(struct inode *inode)  			dquot_free_inode(inode);  		}  	} else { -		truncate_inode_pages(&inode->i_data, 0); +		truncate_inode_pages_final(&inode->i_data);  	} -	end_writeback(inode); +	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; @@ -300,6 +301,16 @@ 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) @@ -308,11 +319,8 @@ static int jfs_write_begin(struct file *file, struct address_space *mapping,  	ret = nobh_write_begin(mapping, pos, len, flags, pagep, fsdata,  				jfs_get_block); -	if (unlikely(ret)) { -		loff_t isize = mapping->host->i_size; -		if (pos + len > isize) -			vmtruncate(mapping->host, isize); -	} +	if (unlikely(ret)) +		jfs_write_failed(mapping, pos + len);  	return ret;  } @@ -323,14 +331,15 @@ 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, inode->i_sb->s_bdev, iov, -				offset, nr_segs, jfs_get_block, NULL); +	ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, jfs_get_block);  	/*  	 * In case of error extending write may have instantiated a few @@ -338,10 +347,10 @@ static ssize_t jfs_direct_IO(int rw, struct kiocb *iocb,  	 */  	if (unlikely((rw & WRITE) && ret < 0)) {  		loff_t isize = i_size_read(inode); -		loff_t end = offset + iov_length(iov, nr_segs); +		loff_t end = offset + count;  		if (end > isize) -			vmtruncate(inode, isize); +			jfs_write_failed(mapping, end);  	}  	return ret; @@ -352,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 afe222bf300..93a1232894f 100644 --- a/fs/jfs/ioctl.c +++ b/fs/jfs/ioctl.c @@ -11,13 +11,17 @@  #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; @@ -54,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; @@ -68,11 +72,11 @@ long jfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  		unsigned int oldflags;  		int err; -		err = mnt_want_write(filp->f_path.mnt); +		err = mnt_want_write_file(filp);  		if (err)  			return err; -		if (!is_owner_or_cap(inode)) { +		if (!inode_owner_or_capable(inode)) {  			err = -EACCES;  			goto setflags_out;  		} @@ -120,9 +124,43 @@ long jfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  		inode->i_ctime = CURRENT_TIME_SEC;  		mark_inode_dirty(inode);  setflags_out: -		mnt_drop_write(filp->f_path.mnt); +		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;  	} @@ -142,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 54e07559878..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_check_acl(struct inode *, int); +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_acl_chmod(struct inode *inode);  #else @@ -32,10 +32,5 @@ static inline int jfs_init_acl(tid_t tid, struct inode *inode,  	return 0;  } -static inline int jfs_acl_chmod(struct inode *inode) -{ -	return 0; -} -  #endif  #endif		/* _H_JFS_ACL */ 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 c92ea3b3ea5..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 @@ -25,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. @@ -104,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); @@ -145,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()   * @@ -310,7 +310,6 @@ int dbSync(struct inode *ipbmap)  	return (0);  } -  /*   * NAME:	dbFree()   * @@ -337,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); @@ -346,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.  	 */ @@ -377,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); @@ -434,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;  	} @@ -719,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;  	} @@ -1050,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;  	} @@ -1095,7 +1099,6 @@ static int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks)  		/* we were not successful */  		release_metapage(mp); -  	return (rc);  } @@ -1128,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;  	} @@ -1206,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.  				 */ @@ -1259,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;  	} @@ -1375,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;  	} @@ -1411,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);  	} @@ -1427,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;  	} @@ -1469,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;  			} @@ -1509,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); @@ -1522,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); @@ -1581,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); @@ -1590,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 @@ -1643,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.  		 */ @@ -1664,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; @@ -1788,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.  		 */ @@ -1835,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; @@ -1847,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;  		} @@ -2145,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;  				} @@ -2155,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 @@ -2418,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;  	} @@ -2520,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];  		} @@ -2744,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.  			 * @@ -3161,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) @@ -3169,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.  	 */ @@ -3366,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; @@ -3463,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; @@ -3531,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); @@ -3602,7 +3702,7 @@ 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");  		}  	} diff --git a/fs/jfs/jfs_dmap.h b/fs/jfs/jfs_dmap.h index 6dcb906c55d..562b9a7e431 100644 --- a/fs/jfs/jfs_dmap.h +++ b/fs/jfs/jfs_dmap.h @@ -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 9197a1b0d02..984c2bbf4f6 100644 --- a/fs/jfs/jfs_dtree.c +++ b/fs/jfs/jfs_dtree.c @@ -124,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) @@ -776,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; @@ -3002,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 */ @@ -3033,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)) { @@ -3045,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; @@ -3053,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; @@ -3080,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 { @@ -3094,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;  			} @@ -3123,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 " @@ -3152,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 */ @@ -3171,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;  		}  	} @@ -3180,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;  	} @@ -3233,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); @@ -3252,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); @@ -3295,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); @@ -3309,7 +3318,7 @@ skip_one:  		}  		if (!overflow && (bn == 0)) { -			filp->f_pos = DIREND; +			ctx->pos = DIREND;  			break;  		} @@ -3373,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 2545bb31723..fd4169e6e69 100644 --- a/fs/jfs/jfs_dtree.h +++ b/fs/jfs/jfs_dtree.h @@ -265,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 5d3bbd10f8d..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 @@ -388,7 +388,7 @@ int extHint(struct inode *ip, s64 offset, xad_t * xp)  	if ((rc == 0) && xlen) {  		if (xlen != nbperpage) { -			jfs_error(ip->i_sb, "extHint: corrupt xtree"); +			jfs_error(ip->i_sb, "corrupt xtree\n");  			rc = -EIO;  		}  		XADaddress(xp, xaddr); @@ -481,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 @@ -575,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 3a09423b6c2..f321986e73d 100644 --- a/fs/jfs/jfs_imap.c +++ b/fs/jfs/jfs_imap.c @@ -386,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; @@ -397,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); @@ -457,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);  	} @@ -469,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); @@ -625,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;  	} @@ -893,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  	 */ @@ -930,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;  	} @@ -950,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;  	}  	/* @@ -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); @@ -1315,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;  } @@ -1379,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])) {  		/* @@ -1494,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; @@ -1519,8 +1516,7 @@ 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"); +						  "can't find free bit in wmap\n");  					return -EIO;  				} @@ -1661,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;  	} @@ -1681,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.  		 */ @@ -1812,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;  	} @@ -1825,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;  		} @@ -1840,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; @@ -1851,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;  	} @@ -1937,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; @@ -1949,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]) @@ -1963,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; @@ -2036,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)) { @@ -2082,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;  	} @@ -2190,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;  	} @@ -2208,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)) { @@ -2262,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;  			} @@ -2499,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 @@ -2615,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 @@ -2759,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 */ @@ -2789,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); @@ -2810,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 */ @@ -2910,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;  		} @@ -2921,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)) @@ -2988,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;  	} @@ -3078,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; @@ -3152,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 1439f119ec8..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	*/ @@ -191,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 2686531e235..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) @@ -95,7 +95,7 @@ struct inode *ialloc(struct inode *parent, umode_t mode)  	if (insert_inode_locked(inode) < 0) {  		rc = -EINVAL; -		goto fail_unlock; +		goto fail_put;  	}  	inode_init_owner(inode, parent, mode); @@ -156,8 +156,7 @@ struct inode *ialloc(struct inode *parent, umode_t mode)  fail_drop:  	dquot_drop(inode);  	inode->i_flags |= S_NOQUOTA; -fail_unlock: -	inode->i_nlink = 0; +	clear_nlink(inode);  	unlock_new_inode(inode);  fail_put:  	iput(inode); diff --git a/fs/jfs/jfs_inode.h b/fs/jfs/jfs_inode.h index 155e91eff07..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 *, 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 *, struct writeback_control *);  extern void jfs_evict_inode(struct inode *); -extern void jfs_dirty_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 *); diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c index e1b8493b9aa..0acddf60af5 100644 --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c @@ -67,6 +67,7 @@  #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> @@ -166,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);  /* @@ -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, FMODE_READ|FMODE_WRITE); +	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, FMODE_READ|FMODE_WRITE); +	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); 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 48b44bd8267..49ba7ff1bbb 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c @@ -416,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++; @@ -438,7 +438,7 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc)  		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; @@ -452,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); @@ -517,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; @@ -571,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)); @@ -583,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, @@ -647,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(); @@ -658,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;  			} 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_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 9466957ec84..564c4f279ac 100644 --- a/fs/jfs/jfs_txnmgr.c +++ b/fs/jfs/jfs_txnmgr.c @@ -636,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; @@ -1143,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; @@ -1310,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); @@ -2685,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;  } @@ -2801,7 +2800,7 @@ int jfs_lazycommit(void *arg)  		if (freezing(current)) {  			LAZY_UNLOCK(flags); -			refrigerator(); +			try_to_freeze();  		} else {  			DECLARE_WAITQUEUE(wq, current); @@ -2935,7 +2934,6 @@ int jfs_sync(void *arg)  {  	struct inode *ip;  	struct jfs_inode_info *jfs_ip; -	int rc;  	tid_t tid;  	do { @@ -2961,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); @@ -2979,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); @@ -2996,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(); 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_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 6c50871e622..5ad7748860c 100644 --- a/fs/jfs/jfs_xtree.c +++ b/fs/jfs/jfs_xtree.c @@ -64,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) @@ -499,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;  		} @@ -1385,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;  	} @@ -1393,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;  	} @@ -1552,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;  	} @@ -1560,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;  	} @@ -1734,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;  	} @@ -1758,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;  	} @@ -1907,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 */ @@ -2048,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;  		}  	} @@ -3650,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;  	} @@ -3751,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 { @@ -3851,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;  	} diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index 231ca4af9bc..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> @@ -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 */ @@ -114,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; @@ -171,12 +172,12 @@ 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 { -		d_instantiate(dentry, ip);  		unlock_new_inode(ip); +		d_instantiate(dentry, ip);  	}        out2: @@ -204,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 */ @@ -219,12 +220,6 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)  	dquot_initialize(dip); -	/* link count overflow on parent directory ? */ -	if (dip->i_nlink == JFS_LINK_MAX) { -		rc = -EMLINK; -		goto out1; -	} -  	/*  	 * search parent directory for entry/freespace  	 * (dtSearch() returns parent directory page pinned) @@ -252,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; @@ -291,7 +286,7 @@ 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; @@ -310,12 +305,12 @@ 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 { -		d_instantiate(dentry, ip);  		unlock_new_inode(ip); +		d_instantiate(dentry, ip);  	}        out2: @@ -805,12 +800,6 @@ 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); @@ -846,7 +835,7 @@ static int jfs_link(struct dentry *old_dentry,  	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); @@ -895,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; @@ -931,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; @@ -995,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 */ @@ -1051,12 +1039,12 @@ 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 { -		d_instantiate(dentry, ip);  		unlock_new_inode(ip); +		d_instantiate(dentry, ip);  	}        out2: @@ -1141,10 +1129,6 @@ 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); @@ -1192,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); @@ -1356,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; @@ -1394,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; @@ -1436,12 +1420,12 @@ 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 { -		d_instantiate(dentry, ip);  		unlock_new_inode(ip); +		d_instantiate(dentry, ip);  	}        out1: @@ -1452,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 NULL; -		} 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, @@ -1558,13 +1523,14 @@ const struct inode_operations jfs_dir_inode_operations = {  	.removexattr	= jfs_removexattr,  	.setattr	= jfs_setattr,  #ifdef CONFIG_JFS_POSIX_ACL -	.check_acl	= jfs_check_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 @@ -1573,7 +1539,7 @@ const struct file_operations jfs_dir_operations = {  	.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; @@ -1586,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;  }  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 1aba0039f1c..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,7 @@ 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; @@ -182,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; @@ -530,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 0669fc1cc3b..adf8cb045b9 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -33,6 +33,7 @@  #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" @@ -43,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"); @@ -82,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;  	} @@ -91,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);  } @@ -115,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); @@ -128,7 +140,7 @@ static void jfs_destroy_inode(struct inode *inode)  		ji->active_ag = -1;  	}  	spin_unlock_irq(&ji->ag_lock); -	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) @@ -146,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); @@ -190,7 +202,8 @@ 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 const match_table_t tokens = { @@ -207,6 +220,9 @@ static const 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}  }; @@ -248,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;  				}  			} @@ -257,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: @@ -265,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: @@ -287,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;  			} @@ -307,36 +323,89 @@ 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;  		}  	} @@ -361,14 +430,13 @@ static int jfs_remount(struct super_block *sb, int *flags, char *data)  	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); @@ -394,9 +462,8 @@ static int jfs_remount(struct super_block *sb, int *flags, char *data)  	}  	if ((!(sb->s_flags & MS_RDONLY)) && (*flags & MS_RDONLY)) {  		rc = dquot_suspend(sb, -1); -		if (rc < 0) { +		if (rc < 0)  			return rc; -		}  		rc = jfs_umount_rw(sb);  		JFS_SBI(sb)->flag = flag;  		return rc; @@ -429,13 +496,16 @@ 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; @@ -449,7 +519,7 @@ 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"); +		pr_err("resize option for remount only\n");  		goto out_kfree;  	} @@ -463,6 +533,7 @@ 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; @@ -477,7 +548,6 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)  		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); @@ -487,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) @@ -507,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_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 @@ -526,20 +595,19 @@ 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, (u64)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 dentry failed"); -	iput(inode);  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); @@ -558,11 +626,28 @@ 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;  } @@ -574,13 +659,18 @@ static int jfs_unfreeze(struct super_block *sb)  	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 0; +	return rc;  }  static struct dentry *jfs_do_mount(struct file_system_type *fs_type, @@ -595,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);  	} @@ -602,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) @@ -636,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) @@ -773,6 +870,7 @@ static struct file_system_type jfs_fs_type = {  	.kill_sb	= kill_block_super,  	.fs_flags	= FS_REQUIRES_DEV,  }; +MODULE_ALIAS_FS("jfs");  static void init_once(void *foo)  { @@ -834,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); @@ -854,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]); @@ -886,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/xattr.c b/fs/jfs/xattr.c index 2d7f165d0f1..46325d5c34f 100644 --- a/fs/jfs/xattr.c +++ b/fs/jfs/xattr.c @@ -382,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;  	} @@ -482,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) >> @@ -666,83 +666,12 @@ 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 -		 */ -		forget_cached_acl(inode, ACL_TYPE_ACCESS); - -		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 -		 */ -		forget_cached_acl(inode, ACL_TYPE_DEFAULT); - -		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 @@ -750,7 +679,7 @@ static int can_set_xattr(struct inode *inode, const char *name,  		 * with "os2."  		 */  		if (is_known_namespace(name + XATTR_OS2_PREFIX_LEN)) -				return -EOPNOTSUPP; +			return -EOPNOTSUPP;  		return 0;  	} @@ -862,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; @@ -876,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; @@ -912,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; @@ -988,6 +938,14 @@ 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 @@ -1076,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; @@ -1090,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  | 
