summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2009-06-18 11:16:55 +1000
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2009-06-18 11:16:55 +1000
commit4b337c5f245b6587ba844ac7bb13c313a2912f7b (patch)
tree999c6a6580b76a083c8efb9dabff709d1c49fcd0 /fs
parent492b057c426e4aa747484958e18e9da29003985d (diff)
parent3fe0344faf7fdcb158bd5c1a9aec960a8d70c8e8 (diff)
downloadkernel-crypto-4b337c5f245b6587ba844ac7bb13c313a2912f7b.tar.gz
kernel-crypto-4b337c5f245b6587ba844ac7bb13c313a2912f7b.tar.xz
kernel-crypto-4b337c5f245b6587ba844ac7bb13c313a2912f7b.zip
Merge commit 'origin/master' into next
Diffstat (limited to 'fs')
-rw-r--r--fs/9p/vfs_super.c3
-rw-r--r--fs/Kconfig16
-rw-r--r--fs/adfs/adfs.h55
-rw-r--r--fs/adfs/dir.c8
-rw-r--r--fs/adfs/dir_f.c8
-rw-r--r--fs/adfs/dir_fplus.c8
-rw-r--r--fs/adfs/file.c4
-rw-r--r--fs/adfs/inode.c10
-rw-r--r--fs/adfs/map.c6
-rw-r--r--fs/adfs/super.c17
-rw-r--r--fs/afs/misc.c16
-rw-r--r--fs/afs/vlocation.c2
-rw-r--r--fs/befs/linuxvfs.c24
-rw-r--r--fs/compat_ioctl.c6
-rw-r--r--fs/debugfs/file.c65
-rw-r--r--fs/debugfs/inode.c11
-rw-r--r--fs/drop_caches.c2
-rw-r--r--fs/efs/dir.c5
-rw-r--r--fs/efs/namei.c9
-rw-r--r--fs/efs/symlink.c7
-rw-r--r--fs/ext3/acl.c13
-rw-r--r--fs/ext4/acl.c13
-rw-r--r--fs/fat/dir.c29
-rw-r--r--fs/fat/namei_vfat.c4
-rw-r--r--fs/fcntl.c33
-rw-r--r--fs/fs-writeback.c6
-rw-r--r--fs/fuse/inode.c3
-rw-r--r--fs/ioctl.c2
-rw-r--r--fs/isofs/joliet.c36
-rw-r--r--fs/jfs/jfs_extent.c1
-rw-r--r--fs/minix/bitmap.c25
-rw-r--r--fs/minix/dir.c5
-rw-r--r--fs/minix/inode.c4
-rw-r--r--fs/ncpfs/ncplib_kernel.c8
-rw-r--r--fs/nfs/iostat.h6
-rw-r--r--fs/nls/nls_base.c166
-rw-r--r--fs/nls/nls_utf8.c13
-rw-r--r--fs/ntfs/inode.c3
-rw-r--r--fs/ntfs/logfile.c3
-rw-r--r--fs/proc/base.c19
-rw-r--r--fs/proc/meminfo.c4
-rw-r--r--fs/proc/page.c162
-rw-r--r--fs/select.c40
-rw-r--r--fs/super.c12
-rw-r--r--fs/sysfs/symlink.c5
-rw-r--r--fs/sysv/dir.c5
-rw-r--r--fs/sysv/inode.c11
-rw-r--r--fs/ubifs/budget.c4
-rw-r--r--fs/ubifs/dir.c19
-rw-r--r--fs/ubifs/io.c34
-rw-r--r--fs/ubifs/recovery.c31
-rw-r--r--fs/ubifs/super.c73
-rw-r--r--fs/ubifs/ubifs.h13
53 files changed, 664 insertions, 423 deletions
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index ab5547ff29a..38d695d66a0 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -37,7 +37,6 @@
#include <linux/mount.h>
#include <linux/idr.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <net/9p/9p.h>
#include <net/9p/client.h>
@@ -231,10 +230,8 @@ v9fs_umount_begin(struct super_block *sb)
{
struct v9fs_session_info *v9ses;
- lock_kernel();
v9ses = sb->s_fs_info;
v9fs_session_cancel(v9ses);
- unlock_kernel();
}
static const struct super_operations v9fs_super_ops = {
diff --git a/fs/Kconfig b/fs/Kconfig
index 525da2e8f73..d78e950402c 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -39,6 +39,13 @@ config FS_POSIX_ACL
bool
default n
+source "fs/xfs/Kconfig"
+source "fs/gfs2/Kconfig"
+source "fs/ocfs2/Kconfig"
+source "fs/btrfs/Kconfig"
+
+endif # BLOCK
+
config FILE_LOCKING
bool "Enable POSIX file locking API" if EMBEDDED
default y
@@ -47,13 +54,6 @@ config FILE_LOCKING
for filesystems like NFS and for the flock() system
call. Disabling this option saves about 11k.
-source "fs/xfs/Kconfig"
-source "fs/gfs2/Kconfig"
-source "fs/ocfs2/Kconfig"
-source "fs/btrfs/Kconfig"
-
-endif # BLOCK
-
source "fs/notify/Kconfig"
source "fs/quota/Kconfig"
@@ -134,7 +134,7 @@ config TMPFS_POSIX_ACL
config HUGETLBFS
bool "HugeTLB file system support"
depends on X86 || IA64 || PPC64 || SPARC64 || (SUPERH && MMU) || \
- (S390 && 64BIT) || BROKEN
+ (S390 && 64BIT) || SYS_SUPPORTS_HUGETLBFS || BROKEN
help
hugetlbfs is a filesystem backing for HugeTLB pages, based on
ramfs. For architectures that support it, say Y here and read
diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h
index a6665f37f45..9cc18775b83 100644
--- a/fs/adfs/adfs.h
+++ b/fs/adfs/adfs.h
@@ -1,3 +1,6 @@
+#include <linux/fs.h>
+#include <linux/adfs_fs.h>
+
/* Internal data structures for ADFS */
#define ADFS_FREE_FRAG 0
@@ -17,6 +20,58 @@
struct buffer_head;
/*
+ * adfs file system inode data in memory
+ */
+struct adfs_inode_info {
+ loff_t mmu_private;
+ unsigned long parent_id; /* object id of parent */
+ __u32 loadaddr; /* RISC OS load address */
+ __u32 execaddr; /* RISC OS exec address */
+ unsigned int filetype; /* RISC OS file type */
+ unsigned int attr; /* RISC OS permissions */
+ unsigned int stamped:1; /* RISC OS file has date/time */
+ struct inode vfs_inode;
+};
+
+/*
+ * Forward-declare this
+ */
+struct adfs_discmap;
+struct adfs_dir_ops;
+
+/*
+ * ADFS file system superblock data in memory
+ */
+struct adfs_sb_info {
+ struct adfs_discmap *s_map; /* bh list containing map */
+ struct adfs_dir_ops *s_dir; /* directory operations */
+
+ uid_t s_uid; /* owner uid */
+ gid_t s_gid; /* owner gid */
+ umode_t s_owner_mask; /* ADFS owner perm -> unix perm */
+ umode_t s_other_mask; /* ADFS other perm -> unix perm */
+
+ __u32 s_ids_per_zone; /* max. no ids in one zone */
+ __u32 s_idlen; /* length of ID in map */
+ __u32 s_map_size; /* sector size of a map */
+ unsigned long s_size; /* total size (in blocks) of this fs */
+ signed int s_map2blk; /* shift left by this for map->sector */
+ unsigned int s_log2sharesize;/* log2 share size */
+ __le32 s_version; /* disc format version */
+ unsigned int s_namelen; /* maximum number of characters in name */
+};
+
+static inline struct adfs_sb_info *ADFS_SB(struct super_block *sb)
+{
+ return sb->s_fs_info;
+}
+
+static inline struct adfs_inode_info *ADFS_I(struct inode *inode)
+{
+ return container_of(inode, struct adfs_inode_info, vfs_inode);
+}
+
+/*
* Directory handling
*/
struct adfs_dir {
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index 4d4073447d1..23aa52f548a 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -9,15 +9,7 @@
*
* Common directory handling for ADFS
*/
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/adfs_fs.h>
-#include <linux/time.h>
-#include <linux/stat.h>
-#include <linux/spinlock.h>
#include <linux/smp_lock.h>
-#include <linux/buffer_head.h> /* for file_fsync() */
-
#include "adfs.h"
/*
diff --git a/fs/adfs/dir_f.c b/fs/adfs/dir_f.c
index 31df6adf0de..bafc71222e2 100644
--- a/fs/adfs/dir_f.c
+++ b/fs/adfs/dir_f.c
@@ -9,15 +9,7 @@
*
* E and F format directory handling
*/
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/adfs_fs.h>
-#include <linux/time.h>
-#include <linux/stat.h>
-#include <linux/spinlock.h>
#include <linux/buffer_head.h>
-#include <linux/string.h>
-
#include "adfs.h"
#include "dir_f.h"
diff --git a/fs/adfs/dir_fplus.c b/fs/adfs/dir_fplus.c
index 139e0f345f1..1796bb352d0 100644
--- a/fs/adfs/dir_fplus.c
+++ b/fs/adfs/dir_fplus.c
@@ -7,15 +7,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/adfs_fs.h>
-#include <linux/time.h>
-#include <linux/stat.h>
-#include <linux/spinlock.h>
#include <linux/buffer_head.h>
-#include <linux/string.h>
-
#include "adfs.h"
#include "dir_fplus.h"
diff --git a/fs/adfs/file.c b/fs/adfs/file.c
index 8224d54a2af..005ea34d175 100644
--- a/fs/adfs/file.c
+++ b/fs/adfs/file.c
@@ -19,10 +19,6 @@
*
* adfs regular file handling primitives
*/
-#include <linux/fs.h>
-#include <linux/buffer_head.h> /* for file_fsync() */
-#include <linux/adfs_fs.h>
-
#include "adfs.h"
const struct file_operations adfs_file_operations = {
diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c
index 05b3a677201..798cb071d13 100644
--- a/fs/adfs/inode.c
+++ b/fs/adfs/inode.c
@@ -7,17 +7,8 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/adfs_fs.h>
-#include <linux/time.h>
-#include <linux/stat.h>
-#include <linux/string.h>
-#include <linux/mm.h>
#include <linux/smp_lock.h>
-#include <linux/module.h>
#include <linux/buffer_head.h>
-
#include "adfs.h"
/*
@@ -395,4 +386,3 @@ int adfs_write_inode(struct inode *inode, int wait)
unlock_kernel();
return ret;
}
-MODULE_LICENSE("GPL");
diff --git a/fs/adfs/map.c b/fs/adfs/map.c
index 568081b93f7..d1a5932bb0f 100644
--- a/fs/adfs/map.c
+++ b/fs/adfs/map.c
@@ -7,14 +7,8 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/adfs_fs.h>
-#include <linux/spinlock.h>
#include <linux/buffer_head.h>
-
#include <asm/unaligned.h>
-
#include "adfs.h"
/*
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 0ec5aaf47aa..aad92f0a104 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -8,26 +8,12 @@
* published by the Free Software Foundation.
*/
#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/adfs_fs.h>
-#include <linux/slab.h>
-#include <linux/time.h>
-#include <linux/stat.h>
-#include <linux/string.h>
#include <linux/init.h>
#include <linux/buffer_head.h>
-#include <linux/vfs.h>
#include <linux/parser.h>
-#include <linux/bitops.h>
#include <linux/mount.h>
#include <linux/seq_file.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
-#include <stdarg.h>
-
+#include <linux/statfs.h>
#include "adfs.h"
#include "dir_f.h"
#include "dir_fplus.h"
@@ -534,3 +520,4 @@ static void __exit exit_adfs_fs(void)
module_init(init_adfs_fs)
module_exit(exit_adfs_fs)
+MODULE_LICENSE("GPL");
diff --git a/fs/afs/misc.c b/fs/afs/misc.c
index 2d33a5f7d21..0dd4dafee10 100644
--- a/fs/afs/misc.c
+++ b/fs/afs/misc.c
@@ -12,6 +12,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
+#include <rxrpc/packet.h>
#include "internal.h"
#include "afs_fs.h"
@@ -54,6 +55,21 @@ int afs_abort_to_error(u32 abort_code)
case 0x2f6df24: return -ENOLCK;
case 0x2f6df26: return -ENOTEMPTY;
case 0x2f6df78: return -EDQUOT;
+
+ case RXKADINCONSISTENCY: return -EPROTO;
+ case RXKADPACKETSHORT: return -EPROTO;
+ case RXKADLEVELFAIL: return -EKEYREJECTED;
+ case RXKADTICKETLEN: return -EKEYREJECTED;
+ case RXKADOUTOFSEQUENCE: return -EPROTO;
+ case RXKADNOAUTH: return -EKEYREJECTED;
+ case RXKADBADKEY: return -EKEYREJECTED;
+ case RXKADBADTICKET: return -EKEYREJECTED;
+ case RXKADUNKNOWNKEY: return -EKEYREJECTED;
+ case RXKADEXPIRED: return -EKEYEXPIRED;
+ case RXKADSEALEDINCON: return -EKEYREJECTED;
+ case RXKADDATALEN: return -EKEYREJECTED;
+ case RXKADILLEGALLEVEL: return -EKEYREJECTED;
+
default: return -EREMOTEIO;
}
}
diff --git a/fs/afs/vlocation.c b/fs/afs/vlocation.c
index ec2a7431e45..6e689208def 100644
--- a/fs/afs/vlocation.c
+++ b/fs/afs/vlocation.c
@@ -65,6 +65,8 @@ static int afs_vlocation_access_vl_by_name(struct afs_vlocation *vl,
goto out;
goto rotate;
case -ENOMEDIUM:
+ case -EKEYREJECTED:
+ case -EKEYEXPIRED:
goto out;
default:
ret = -EIO;
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index 9367b6297d8..615d5496fe0 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -513,7 +513,7 @@ befs_utf2nls(struct super_block *sb, const char *in,
{
struct nls_table *nls = BEFS_SB(sb)->nls;
int i, o;
- wchar_t uni;
+ unicode_t uni;
int unilen, utflen;
char *result;
/* The utf8->nls conversion won't make the final nls string bigger
@@ -539,16 +539,16 @@ befs_utf2nls(struct super_block *sb, const char *in,
for (i = o = 0; i < in_len; i += utflen, o += unilen) {
/* convert from UTF-8 to Unicode */
- utflen = utf8_mbtowc(&uni, &in[i], in_len - i);
- if (utflen < 0) {
+ utflen = utf8_to_utf32(&in[i], in_len - i, &uni);
+ if (utflen < 0)
goto conv_err;
- }
/* convert from Unicode to nls */
+ if (uni > MAX_WCHAR_T)
+ goto conv_err;
unilen = nls->uni2char(uni, &result[o], in_len - o);
- if (unilen < 0) {
+ if (unilen < 0)
goto conv_err;
- }
}
result[o] = '\0';
*out_len = o;
@@ -619,15 +619,13 @@ befs_nls2utf(struct super_block *sb, const char *in,
/* convert from nls to unicode */
unilen = nls->char2uni(&in[i], in_len - i, &uni);
- if (unilen < 0) {
+ if (unilen < 0)
goto conv_err;
- }
/* convert from unicode to UTF-8 */
- utflen = utf8_wctomb(&result[o], uni, 3);
- if (utflen <= 0) {
+ utflen = utf32_to_utf8(uni, &result[o], 3);
+ if (utflen <= 0)
goto conv_err;
- }
}
result[o] = '\0';
@@ -737,8 +735,6 @@ parse_options(char *options, befs_mount_options * opts)
static void
befs_put_super(struct super_block *sb)
{
- lock_kernel();
-
kfree(BEFS_SB(sb)->mount_opts.iocharset);
BEFS_SB(sb)->mount_opts.iocharset = NULL;
@@ -749,8 +745,6 @@ befs_put_super(struct super_block *sb)
kfree(sb->s_fs_info);
sb->s_fs_info = NULL;
-
- unlock_kernel();
}
/* Allocate private field of the superblock, fill it.
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 0aac371bff0..c5ded5ff72b 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -788,12 +788,6 @@ static int sg_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
if (put_user(compat_ptr(data), &sgio->usr_ptr))
return -EFAULT;
- if (copy_in_user(&sgio->status, &sgio32->status,
- (4 * sizeof(unsigned char)) +
- (2 * sizeof(unsigned short)) +
- (3 * sizeof(int))))
- return -EFAULT;
-
err = sys_ioctl(fd, cmd, (unsigned long) sgio);
if (err >= 0) {
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c
index 33a90120f6a..4d74fc72c19 100644
--- a/fs/debugfs/file.c
+++ b/fs/debugfs/file.c
@@ -67,6 +67,8 @@ static int debugfs_u8_get(void *data, u64 *val)
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_u8_ro, debugfs_u8_get, NULL, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_u8_wo, NULL, debugfs_u8_set, "%llu\n");
/**
* debugfs_create_u8 - create a debugfs file that is used to read and write an unsigned 8-bit value
@@ -95,6 +97,13 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%llu\n");
struct dentry *debugfs_create_u8(const char *name, mode_t mode,
struct dentry *parent, u8 *value)
{
+ /* if there are no write bits set, make read only */
+ if (!(mode & S_IWUGO))
+ return debugfs_create_file(name, mode, parent, value, &fops_u8_ro);
+ /* if there are no read bits set, make write only */
+ if (!(mode & S_IRUGO))
+ return debugfs_create_file(name, mode, parent, value, &fops_u8_wo);
+
return debugfs_create_file(name, mode, parent, value, &fops_u8);
}
EXPORT_SYMBOL_GPL(debugfs_create_u8);
@@ -110,6 +119,8 @@ static int debugfs_u16_get(void *data, u64 *val)
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_u16_ro, debugfs_u16_get, NULL, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_u16_wo, NULL, debugfs_u16_set, "%llu\n");
/**
* debugfs_create_u16 - create a debugfs file that is used to read and write an unsigned 16-bit value
@@ -138,6 +149,13 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, "%llu\n");
struct dentry *debugfs_create_u16(const char *name, mode_t mode,
struct dentry *parent, u16 *value)
{
+ /* if there are no write bits set, make read only */
+ if (!(mode & S_IWUGO))
+ return debugfs_create_file(name, mode, parent, value, &fops_u16_ro);
+ /* if there are no read bits set, make write only */
+ if (!(mode & S_IRUGO))
+ return debugfs_create_file(name, mode, parent, value, &fops_u16_wo);
+
return debugfs_create_file(name, mode, parent, value, &fops_u16);
}
EXPORT_SYMBOL_GPL(debugfs_create_u16);
@@ -153,6 +171,8 @@ static int debugfs_u32_get(void *data, u64 *val)
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_u32_ro, debugfs_u32_get, NULL, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_u32_wo, NULL, debugfs_u32_set, "%llu\n");
/**
* debugfs_create_u32 - create a debugfs file that is used to read and write an unsigned 32-bit value
@@ -181,6 +201,13 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%llu\n");
struct dentry *debugfs_create_u32(const char *name, mode_t mode,
struct dentry *parent, u32 *value)
{
+ /* if there are no write bits set, make read only */
+ if (!(mode & S_IWUGO))
+ return debugfs_create_file(name, mode, parent, value, &fops_u32_ro);
+ /* if there are no read bits set, make write only */
+ if (!(mode & S_IRUGO))
+ return debugfs_create_file(name, mode, parent, value, &fops_u32_wo);
+
return debugfs_create_file(name, mode, parent, value, &fops_u32);
}
EXPORT_SYMBOL_GPL(debugfs_create_u32);
@@ -197,6 +224,8 @@ static int debugfs_u64_get(void *data, u64 *val)
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_u64_ro, debugfs_u64_get, NULL, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%llu\n");
/**
* debugfs_create_u64 - create a debugfs file that is used to read and write an unsigned 64-bit value
@@ -225,15 +254,28 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%llu\n");
struct dentry *debugfs_create_u64(const char *name, mode_t mode,
struct dentry *parent, u64 *value)
{
+ /* if there are no write bits set, make read only */
+ if (!(mode & S_IWUGO))
+ return debugfs_create_file(name, mode, parent, value, &fops_u64_ro);
+ /* if there are no read bits set, make write only */
+ if (!(mode & S_IRUGO))
+ return debugfs_create_file(name, mode, parent, value, &fops_u64_wo);
+
return debugfs_create_file(name, mode, parent, value, &fops_u64);
}
EXPORT_SYMBOL_GPL(debugfs_create_u64);
DEFINE_SIMPLE_ATTRIBUTE(fops_x8, debugfs_u8_get, debugfs_u8_set, "0x%02llx\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_x8_ro, debugfs_u8_get, NULL, "0x%02llx\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_x8_wo, NULL, debugfs_u8_set, "0x%02llx\n");
DEFINE_SIMPLE_ATTRIBUTE(fops_x16, debugfs_u16_get, debugfs_u16_set, "0x%04llx\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_x16_ro, debugfs_u16_get, NULL, "0x%04llx\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_x16_wo, NULL, debugfs_u16_set, "0x%04llx\n");
DEFINE_SIMPLE_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, "0x%08llx\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_x32_ro, debugfs_u32_get, NULL, "0x%08llx\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_x32_wo, NULL, debugfs_u32_set, "0x%08llx\n");
/*
* debugfs_create_x{8,16,32} - create a debugfs file that is used to read and write an unsigned {8,16,32}-bit value
@@ -256,6 +298,13 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, "0x%08llx\n"
struct dentry *debugfs_create_x8(const char *name, mode_t mode,
struct dentry *parent, u8 *value)
{
+ /* if there are no write bits set, make read only */
+ if (!(mode & S_IWUGO))
+ return debugfs_create_file(name, mode, parent, value, &fops_x8_ro);
+ /* if there are no read bits set, make write only */
+ if (!(mode & S_IRUGO))
+ return debugfs_create_file(name, mode, parent, value, &fops_x8_wo);
+
return debugfs_create_file(name, mode, parent, value, &fops_x8);
}
EXPORT_SYMBOL_GPL(debugfs_create_x8);
@@ -273,6 +322,13 @@ EXPORT_SYMBOL_GPL(debugfs_create_x8);
struct dentry *debugfs_create_x16(const char *name, mode_t mode,
struct dentry *parent, u16 *value)
{
+ /* if there are no write bits set, make read only */
+ if (!(mode & S_IWUGO))
+ return debugfs_create_file(name, mode, parent, value, &fops_x16_ro);
+ /* if there are no read bits set, make write only */
+ if (!(mode & S_IRUGO))
+ return debugfs_create_file(name, mode, parent, value, &fops_x16_wo);
+
return debugfs_create_file(name, mode, parent, value, &fops_x16);
}
EXPORT_SYMBOL_GPL(debugfs_create_x16);
@@ -290,6 +346,13 @@ EXPORT_SYMBOL_GPL(debugfs_create_x16);
struct dentry *debugfs_create_x32(const char *name, mode_t mode,
struct dentry *parent, u32 *value)
{
+ /* if there are no write bits set, make read only */
+ if (!(mode & S_IWUGO))
+ return debugfs_create_file(name, mode, parent, value, &fops_x32_ro);
+ /* if there are no read bits set, make write only */
+ if (!(mode & S_IRUGO))
+ return debugfs_create_file(name, mode, parent, value, &fops_x32_wo);
+
return debugfs_create_file(name, mode, parent, value, &fops_x32);
}
EXPORT_SYMBOL_GPL(debugfs_create_x32);
@@ -419,7 +482,7 @@ static const struct file_operations fops_blob = {
};
/**
- * debugfs_create_blob - create a debugfs file that is used to read and write a binary blob
+ * debugfs_create_blob - create a debugfs file that is used to read a binary blob
* @name: a pointer to a string containing the name of the file to create.
* @mode: the permission that the file should have
* @parent: a pointer to the parent dentry for this file. This should be a
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index 0662ba6de85..d22438ef767 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -403,6 +403,7 @@ void debugfs_remove_recursive(struct dentry *dentry)
}
child = list_entry(parent->d_subdirs.next, struct dentry,
d_u.d_child);
+ next_sibling:
/*
* If "child" isn't empty, walk down the tree and
@@ -417,6 +418,16 @@ void debugfs_remove_recursive(struct dentry *dentry)
__debugfs_remove(child, parent);
if (parent->d_subdirs.next == &child->d_u.d_child) {
/*
+ * Try the next sibling.
+ */
+ if (child->d_u.d_child.next != &parent->d_subdirs) {
+ child = list_entry(child->d_u.d_child.next,
+ struct dentry,
+ d_u.d_child);
+ goto next_sibling;
+ }
+
+ /*
* Avoid infinite loop if we fail to remove
* one dentry.
*/
diff --git a/fs/drop_caches.c b/fs/drop_caches.c
index b6a719a909f..a2edb791344 100644
--- a/fs/drop_caches.c
+++ b/fs/drop_caches.c
@@ -24,7 +24,7 @@ static void drop_pagecache_sb(struct super_block *sb)
continue;
__iget(inode);
spin_unlock(&inode_lock);
- __invalidate_mapping_pages(inode->i_mapping, 0, -1, true);
+ invalidate_mapping_pages(inode->i_mapping, 0, -1);
iput(toput_inode);
toput_inode = inode;
spin_lock(&inode_lock);
diff --git a/fs/efs/dir.c b/fs/efs/dir.c
index 49308a29798..7ee6f7e3a60 100644
--- a/fs/efs/dir.c
+++ b/fs/efs/dir.c
@@ -5,12 +5,12 @@
*/
#include <linux/buffer_head.h>
-#include <linux/smp_lock.h>
#include "efs.h"
static int efs_readdir(struct file *, void *, filldir_t);
const struct file_operations efs_dir_operations = {
+ .llseek = generic_file_llseek,
.read = generic_read_dir,
.readdir = efs_readdir,
};
@@ -33,8 +33,6 @@ static int efs_readdir(struct file *filp, void *dirent, filldir_t filldir) {
if (inode->i_size & (EFS_DIRBSIZE-1))
printk(KERN_WARNING "EFS: WARNING: readdir(): directory size not a multiple of EFS_DIRBSIZE\n");
- lock_kernel();
-
/* work out where this entry can be found */
block = filp->f_pos >> EFS_DIRBSIZE_BITS;
@@ -107,7 +105,6 @@ static int efs_readdir(struct file *filp, void *dirent, filldir_t filldir) {
filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot;
out:
- unlock_kernel();
return 0;
}
diff --git a/fs/efs/namei.c b/fs/efs/namei.c
index c3fb5f9c4a4..1511bf9e5f8 100644
--- a/fs/efs/namei.c
+++ b/fs/efs/namei.c
@@ -8,7 +8,6 @@
#include <linux/buffer_head.h>
#include <linux/string.h>
-#include <linux/smp_lock.h>
#include <linux/exportfs.h>
#include "efs.h"
@@ -63,16 +62,12 @@ struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry, struct namei
efs_ino_t inodenum;
struct inode * inode = NULL;
- lock_kernel();
inodenum = efs_find_entry(dir, dentry->d_name.name, dentry->d_name.len);
if (inodenum) {
inode = efs_iget(dir->i_sb, inodenum);
- if (IS_ERR(inode)) {
- unlock_kernel();
+ if (IS_ERR(inode))
return ERR_CAST(inode);
- }
}
- unlock_kernel();
return d_splice_alias(inode, dentry);
}
@@ -115,11 +110,9 @@ struct dentry *efs_get_parent(struct dentry *child)
struct dentry *parent = ERR_PTR(-ENOENT);
efs_ino_t ino;
- lock_kernel();
ino = efs_find_entry(child->d_inode, "..", 2);
if (ino)
parent = d_obtain_alias(efs_iget(child->d_inode->i_sb, ino));
- unlock_kernel();
return parent;
}
diff --git a/fs/efs/symlink.c b/fs/efs/symlink.c
index 41911ec83aa..75117d0dac2 100644
--- a/fs/efs/symlink.c
+++ b/fs/efs/symlink.c
@@ -9,7 +9,6 @@
#include <linux/string.h>
#include <linux/pagemap.h>
#include <linux/buffer_head.h>
-#include <linux/smp_lock.h>
#include "efs.h"
static int efs_symlink_readpage(struct file *file, struct page *page)
@@ -22,9 +21,8 @@ static int efs_symlink_readpage(struct file *file, struct page *page)
err = -ENAMETOOLONG;
if (size > 2 * EFS_BLOCKSIZE)
- goto fail_notlocked;
+ goto fail;
- lock_kernel();
/* read first 512 bytes of link target */
err = -EIO;
bh = sb_bread(inode->i_sb, efs_bmap(inode, 0));
@@ -40,14 +38,11 @@ static int efs_symlink_readpage(struct file *file, struct page *page)
brelse(bh);
}
link[size] = '\0';
- unlock_kernel();
SetPageUptodate(page);
kunmap(page);
unlock_page(page);
return 0;
fail:
- unlock_kernel();
-fail_notlocked:
SetPageError(page);
kunmap(page);
unlock_page(page);
diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c
index d81ef2fdb08..e0c74545171 100644
--- a/fs/ext3/acl.c
+++ b/fs/ext3/acl.c
@@ -129,12 +129,15 @@ fail:
static inline struct posix_acl *
ext3_iget_acl(struct inode *inode, struct posix_acl **i_acl)
{
- struct posix_acl *acl = EXT3_ACL_NOT_CACHED;
+ struct posix_acl *acl = ACCESS_ONCE(*i_acl);
- spin_lock(&inode->i_lock);
- if (*i_acl != EXT3_ACL_NOT_CACHED)
- acl = posix_acl_dup(*i_acl);
- spin_unlock(&inode->i_lock);
+ if (acl) {
+ spin_lock(&inode->i_lock);
+ acl = *i_acl;
+ if (acl != EXT3_ACL_NOT_CACHED)
+ acl = posix_acl_dup(acl);
+ spin_unlock(&inode->i_lock);
+ }
return acl;
}
diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c
index 647e0d65a28..605aeed96d6 100644
--- a/fs/ext4/acl.c
+++ b/fs/ext4/acl.c
@@ -129,12 +129,15 @@ fail:
static inline struct posix_acl *
ext4_iget_acl(struct inode *inode, struct posix_acl **i_acl)
{
- struct posix_acl *acl = EXT4_ACL_NOT_CACHED;
+ struct posix_acl *acl = ACCESS_ONCE(*i_acl);
- spin_lock(&inode->i_lock);
- if (*i_acl != EXT4_ACL_NOT_CACHED)
- acl = posix_acl_dup(*i_acl);
- spin_unlock(&inode->i_lock);
+ if (acl) {
+ spin_lock(&inode->i_lock);
+ acl = *i_acl;
+ if (acl != EXT4_ACL_NOT_CACHED)
+ acl = posix_acl_dup(acl);
+ spin_unlock(&inode->i_lock);
+ }
return acl;
}
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 3b8e71b412f..38ff75a0fe2 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -22,6 +22,19 @@
#include <asm/uaccess.h>
#include "fat.h"
+/*
+ * Maximum buffer size of short name.
+ * [(MSDOS_NAME + '.') * max one char + nul]
+ * For msdos style, ['.' (hidden) + MSDOS_NAME + '.' + nul]
+ */
+#define FAT_MAX_SHORT_SIZE ((MSDOS_NAME + 1) * NLS_MAX_CHARSET_SIZE + 1)
+/*
+ * Maximum buffer size of unicode chars from slots.
+ * [(max longname slots * 13 (size in a slot) + nul) * sizeof(wchar_t)]
+ */
+#define FAT_MAX_UNI_CHARS ((MSDOS_SLOTS - 1) * 13 + 1)
+#define FAT_MAX_UNI_SIZE (FAT_MAX_UNI_CHARS * sizeof(wchar_t))
+
static inline loff_t fat_make_i_pos(struct super_block *sb,
struct buffer_head *bh,
struct msdos_dir_entry *de)
@@ -171,7 +184,8 @@ static inline int fat_uni_to_x8(struct msdos_sb_info *sbi, const wchar_t *uni,
unsigned char *buf, int size)
{
if (sbi->options.utf8)
- return utf8_wcstombs(buf, uni, size);
+ return utf16s_to_utf8s(uni, FAT_MAX_UNI_CHARS,
+ UTF16_HOST_ENDIAN, buf, size);
else
return uni16_to_x8(buf, uni, size, sbi->options.unicode_xlate,
sbi->nls_io);
@@ -325,19 +339,6 @@ parse_long:
}
/*
- * Maximum buffer size of short name.
- * [(MSDOS_NAME + '.') * max one char + nul]
- * For msdos style, ['.' (hidden) + MSDOS_NAME + '.' + nul]
- */
-#define FAT_MAX_SHORT_SIZE ((MSDOS_NAME + 1) * NLS_MAX_CHARSET_SIZE + 1)
-/*
- * Maximum buffer size of unicode chars from slots.
- * [(max longname slots * 13 (size in a slot) + nul) * sizeof(wchar_t)]
- */
-#define FAT_MAX_UNI_CHARS ((MSDOS_SLOTS - 1) * 13 + 1)
-#define FAT_MAX_UNI_SIZE (FAT_MAX_UNI_CHARS * sizeof(wchar_t))
-
-/*
* Return values: negative -> error, 0 -> not found, positive -> found,
* value is the total amount of slots, including the shortname entry.
*/
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
index 8d6fdcfd41d..73471b7ecc8 100644
--- a/fs/fat/namei_vfat.c
+++ b/fs/fat/namei_vfat.c
@@ -502,11 +502,11 @@ xlate_to_uni(const unsigned char *name, int len, unsigned char *outname,
if (utf8) {
int name_len = strlen(name);
- *outlen = utf8_mbstowcs((wchar_t *)outname, name, PATH_MAX);
+ *outlen = utf8s_to_utf16s(name, PATH_MAX, (wchar_t *) outname);
/*
* We stripped '.'s before and set len appropriately,
- * but utf8_mbstowcs doesn't care about len
+ * but utf8s_to_utf16s doesn't care about len
*/
*outlen -= (name_len - len);
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 1ad703150de..a040b764f8e 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -198,15 +198,19 @@ static int setfl(int fd, struct file * filp, unsigned long arg)
}
static void f_modown(struct file *filp, struct pid *pid, enum pid_type type,
- uid_t uid, uid_t euid, int force)
+ int force)
{
write_lock_irq(&filp->f_owner.lock);
if (force || !filp->f_owner.pid) {
put_pid(filp->f_owner.pid);
filp->f_owner.pid = get_pid(pid);
filp->f_owner.pid_type = type;
- filp->f_owner.uid = uid;
- filp->f_owner.euid = euid;
+
+ if (pid) {
+ const struct cred *cred = current_cred();
+ filp->f_owner.uid = cred->uid;
+ filp->f_owner.euid = cred->euid;
+ }
}
write_unlock_irq(&filp->f_owner.lock);
}
@@ -214,14 +218,13 @@ static void f_modown(struct file *filp, struct pid *pid, enum pid_type type,
int __f_setown(struct file *filp, struct pid *pid, enum pid_type type,
int force)
{
- const struct cred *cred = current_cred();
int err;
-
+
err = security_file_set_fowner(filp);
if (err)
return err;
- f_modown(filp, pid, type, cred->uid, cred->euid, force);
+ f_modown(filp, pid, type, force);
return 0;
}
EXPORT_SYMBOL(__f_setown);
@@ -247,7 +250,7 @@ EXPORT_SYMBOL(f_setown);
void f_delown(struct file *filp)
{
- f_modown(filp, NULL, PIDTYPE_PID, 0, 0, 1);
+ f_modown(filp, NULL, PIDTYPE_PID, 1);
}
pid_t f_getown(struct file *filp)
@@ -425,14 +428,20 @@ static inline int sigio_perm(struct task_struct *p,
}
static void send_sigio_to_task(struct task_struct *p,
- struct fown_struct *fown,
+ struct fown_struct *fown,
int fd,
int reason)
{
- if (!sigio_perm(p, fown, fown->signum))
+ /*
+ * F_SETSIG can change ->signum lockless in parallel, make
+ * sure we read it once and use the same value throughout.
+ */
+ int signum = ACCESS_ONCE(fown->signum);
+
+ if (!sigio_perm(p, fown, signum))
return;
- switch (fown->signum) {
+ switch (signum) {
siginfo_t si;
default:
/* Queue a rt signal with the appropriate fd as its
@@ -441,7 +450,7 @@ static void send_sigio_to_task(struct task_struct *p,
delivered even if we can't queue. Failure to
queue in this case _should_ be reported; we fall
back to SIGIO in that case. --sct */
- si.si_signo = fown->signum;
+ si.si_signo = signum;
si.si_errno = 0;
si.si_code = reason;
/* Make sure we are called with one of the POLL_*
@@ -453,7 +462,7 @@ static void send_sigio_to_task(struct task_struct *p,
else
si.si_band = band_table[reason - POLL_IN];
si.si_fd = fd;
- if (!group_send_sig_info(fown->signum, &si, p))
+ if (!group_send_sig_info(signum, &si, p))
break;
/* fall-through: fall back on the old plain SIGIO signal */
case 0:
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 40308e98c6a..caf049146ca 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -321,7 +321,7 @@ __sync_single_inode(struct inode *inode, struct writeback_control *wbc)
spin_lock(&inode_lock);
inode->i_state &= ~I_SYNC;
- if (!(inode->i_state & I_FREEING)) {
+ if (!(inode->i_state & (I_FREEING | I_CLEAR))) {
if (!(inode->i_state & I_DIRTY) &&
mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) {
/*
@@ -492,7 +492,7 @@ void generic_sync_sb_inodes(struct super_block *sb,
break;
}
- if (inode->i_state & I_NEW) {
+ if (inode->i_state & (I_NEW | I_WILL_FREE)) {
requeue_io(inode);
continue;
}
@@ -523,7 +523,7 @@ void generic_sync_sb_inodes(struct super_block *sb,
if (current_is_pdflush() && !writeback_acquire(bdi))
break;
- BUG_ON(inode->i_state & I_FREEING);
+ BUG_ON(inode->i_state & (I_FREEING | I_CLEAR));
__iget(inode);
pages_skipped = wbc->pages_skipped;
__writeback_single_inode(inode, wbc);
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index f0df55a5292..d8673ccf90b 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -19,7 +19,6 @@
#include <linux/random.h>
#include <linux/sched.h>
#include <linux/exportfs.h>
-#include <linux/smp_lock.h>
MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
MODULE_DESCRIPTION("Filesystem in Userspace");
@@ -260,9 +259,7 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid,
static void fuse_umount_begin(struct super_block *sb)
{
- lock_kernel();
fuse_abort_conn(get_fuse_conn_super(sb));
- unlock_kernel();
}
static void fuse_send_destroy(struct fuse_conn *fc)
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 286f38dfc6c..001f8d3118f 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -70,9 +70,7 @@ static int ioctl_fibmap(struct file *filp, int __user *p)
res = get_user(block, p);
if (res)
return res;
- lock_kernel();
res = mapping->a_ops->bmap(mapping, block);
- unlock_kernel();
return put_user(res, p);
}
diff --git a/fs/isofs/joliet.c b/fs/isofs/joliet.c
index 92c14b850e9..a048de81c09 100644
--- a/fs/isofs/joliet.c
+++ b/fs/isofs/joliet.c
@@ -37,37 +37,6 @@ uni16_to_x8(unsigned char *ascii, __be16 *uni, int len, struct nls_table *nls)
return (op - ascii);
}
-/* Convert big endian wide character string to utf8 */
-static int
-wcsntombs_be(__u8 *s, const __u8 *pwcs, int inlen, int maxlen)
-{
- const __u8 *ip;
- __u8 *op;
- int size;
- __u16 c;
-
- op = s;
- ip = pwcs;
- while ((*ip || ip[1]) && (maxlen > 0) && (inlen > 0)) {
- c = (*ip << 8) | ip[1];
- if (c > 0x7f) {
- size = utf8_wctomb(op, c, maxlen);
- if (size == -1) {
- /* Ignore character and move on */
- maxlen--;
- } else {
- op += size;
- maxlen -= size;
- }
- } else {
- *op++ = (__u8) c;
- }
- ip += 2;
- inlen--;
- }
- return (op - s);
-}
-
int
get_joliet_filename(struct iso_directory_record * de, unsigned char *outname, struct inode * inode)
{
@@ -79,8 +48,9 @@ get_joliet_filename(struct iso_directory_record * de, unsigned char *outname, st
nls = ISOFS_SB(inode->i_sb)->s_nls_iocharset;
if (utf8) {
- len = wcsntombs_be(outname, de->name,
- de->name_len[0] >> 1, PAGE_SIZE);
+ len = utf16s_to_utf8s((const wchar_t *) de->name,
+ de->name_len[0] >> 1, UTF16_BIG_ENDIAN,
+ outname, PAGE_SIZE);
} else {
len = uni16_to_x8(outname, (__be16 *) de->name,
de->name_len[0] >> 1, nls);
diff --git a/fs/jfs/jfs_extent.c b/fs/jfs/jfs_extent.c
index bbbd5f202e3..41d6045dbeb 100644
--- a/fs/jfs/jfs_extent.c
+++ b/fs/jfs/jfs_extent.c
@@ -391,6 +391,7 @@ int extHint(struct inode *ip, s64 offset, xad_t * xp)
}
XADaddress(xp, xaddr);
XADlength(xp, xlen);
+ XADoffset(xp, prev);
/*
* only preserve the abnr flag within the xad flags
* of the returned hint.
diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c
index 3aebe322271..6ac693faae4 100644
--- a/fs/minix/bitmap.c
+++ b/fs/minix/bitmap.c
@@ -12,13 +12,14 @@
/* bitmap.c contains the code that handles the inode and block bitmaps */
#include "minix.h"
-#include <linux/smp_lock.h>
#include <linux/buffer_head.h>
#include <linux/bitops.h>
#include <linux/sched.h>
static const int nibblemap[] = { 4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0 };
+static DEFINE_SPINLOCK(bitmap_lock);
+
static unsigned long count_free(struct buffer_head *map[], unsigned numblocks, __u32 numbits)
{
unsigned i, j, sum = 0;
@@ -69,11 +70,11 @@ void minix_free_block(struct inode *inode, unsigned long block)
return;
}
bh = sbi->s_zmap[zone];
- lock_kernel();
+ spin_lock(&bitmap_lock);
if (!minix_test_and_clear_bit(bit, bh->b_data))
printk("minix_free_block (%s:%lu): bit already cleared\n",
sb->s_id, block);
- unlock_kernel();
+ spin_unlock(&bitmap_lock);
mark_buffer_dirty(bh);
return;
}
@@ -88,18 +89,18 @@ int minix_new_block(struct inode * inode)
struct buffer_head *bh = sbi->s_zmap[i];
int j;
- lock_kernel();
+ spin_lock(&bitmap_lock);
j = minix_find_first_zero_bit(bh->b_data, bits_per_zone);
if (j < bits_per_zone) {
minix_set_bit(j, bh->b_data);
- unlock_kernel();
+ spin_unlock(&bitmap_lock);
mark_buffer_dirty(bh);
j += i * bits_per_zone + sbi->s_firstdatazone-1;
if (j < sbi->s_firstdatazone || j >= sbi->s_nzones)
break;
return j;
}
- unlock_kernel();
+ spin_unlock(&bitmap_lock);
}
return 0;
}
@@ -211,10 +212,10 @@ void minix_free_inode(struct inode * inode)
minix_clear_inode(inode); /* clear on-disk copy */
bh = sbi->s_imap[ino];
- lock_kernel();
+ spin_lock(&bitmap_lock);
if (!minix_test_and_clear_bit(bit, bh->b_data))
printk("minix_free_inode: bit %lu already cleared\n", bit);
- unlock_kernel();
+ spin_unlock(&bitmap_lock);
mark_buffer_dirty(bh);
out:
clear_inode(inode); /* clear in-memory copy */
@@ -237,7 +238,7 @@ struct inode * minix_new_inode(const struct inode * dir, int * error)
j = bits_per_zone;
bh = NULL;
*error = -ENOSPC;
- lock_kernel();
+ spin_lock(&bitmap_lock);
for (i = 0; i < sbi->s_imap_blocks; i++) {
bh = sbi->s_imap[i];
j = minix_find_first_zero_bit(bh->b_data, bits_per_zone);
@@ -245,17 +246,17 @@ struct inode * minix_new_inode(const struct inode * dir, int * error)
break;
}
if (!bh || j >= bits_per_zone) {
- unlock_kernel();
+ spin_unlock(&bitmap_lock);
iput(inode);
return NULL;
}
if (minix_test_and_set_bit(j, bh->b_data)) { /* shouldn't happen */
- unlock_kernel();
+ spin_unlock(&bitmap_lock);
printk("minix_new_inode: bit already set\n");
iput(inode);
return NULL;
}
- unlock_kernel();
+ spin_unlock(&bitmap_lock);
mark_buffer_dirty(bh);
j += i * bits_per_zone;
if (!j || j > sbi->s_ninodes) {
diff --git a/fs/minix/dir.c b/fs/minix/dir.c
index e5f206467e4..d407e7a0b6f 100644
--- a/fs/minix/dir.c
+++ b/fs/minix/dir.c
@@ -11,7 +11,6 @@
#include "minix.h"
#include <linux/buffer_head.h>
#include <linux/highmem.h>
-#include <linux/smp_lock.h>
#include <linux/swap.h>
typedef struct minix_dir_entry minix_dirent;
@@ -20,6 +19,7 @@ typedef struct minix3_dir_entry minix3_dirent;
static int minix_readdir(struct file *, void *, filldir_t);
const struct file_operations minix_dir_operations = {
+ .llseek = generic_file_llseek,
.read = generic_read_dir,
.readdir = minix_readdir,
.fsync = simple_fsync,
@@ -102,8 +102,6 @@ static int minix_readdir(struct file * filp, void * dirent, filldir_t filldir)
char *name;
__u32 inumber;
- lock_kernel();
-
pos = (pos + chunk_size-1) & ~(chunk_size-1);
if (pos >= inode->i_size)
goto done;
@@ -146,7 +144,6 @@ static int minix_readdir(struct file * filp, void * dirent, filldir_t filldir)
done:
filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset;
- unlock_kernel();
return 0;
}
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index f91a2369359..74ea82d7216 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -35,8 +35,6 @@ static void minix_put_super(struct super_block *sb)
int i;
struct minix_sb_info *sbi = minix_sb(sb);
- lock_kernel();
-
if (!(sb->s_flags & MS_RDONLY)) {
if (sbi->s_version != MINIX_V3) /* s_state is now out from V3 sb */
sbi->s_ms->s_state = sbi->s_mount_state;
@@ -50,8 +48,6 @@ static void minix_put_super(struct super_block *sb)
kfree(sbi->s_imap);
sb->s_fs_info = NULL;
kfree(sbi);
-
- unlock_kernel();
}
static struct kmem_cache * minix_inode_cachep;
diff --git a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c
index 97645f11211..0ec6237a597 100644
--- a/fs/ncpfs/ncplib_kernel.c
+++ b/fs/ncpfs/ncplib_kernel.c
@@ -1113,11 +1113,13 @@ ncp__io2vol(struct ncp_server *server, unsigned char *vname, unsigned int *vlen,
if (NCP_IS_FLAG(server, NCP_FLAG_UTF8)) {
int k;
+ unicode_t u;
- k = utf8_mbtowc(&ec, iname, iname_end - iname);
- if (k < 0)
+ k = utf8_to_utf32(iname, iname_end - iname, &u);
+ if (k < 0 || u > MAX_WCHAR_T)
return -EINVAL;
iname += k;
+ ec = u;
} else {
if (*iname == NCP_ESC) {
int k;
@@ -1214,7 +1216,7 @@ ncp__vol2io(struct ncp_server *server, unsigned char *iname, unsigned int *ilen,
if (NCP_IS_FLAG(server, NCP_FLAG_UTF8)) {
int k;
- k = utf8_wctomb(iname, ec, iname_end - iname);
+ k = utf32_to_utf8(ec, iname, iname_end - iname);
if (k < 0) {
err = -ENAMETOOLONG;
goto quit;
diff --git a/fs/nfs/iostat.h b/fs/nfs/iostat.h
index a2ab2529b5c..ceda50aad73 100644
--- a/fs/nfs/iostat.h
+++ b/fs/nfs/iostat.h
@@ -31,7 +31,7 @@ static inline void nfs_inc_server_stats(const struct nfs_server *server,
cpu = get_cpu();
iostats = per_cpu_ptr(server->io_stats, cpu);
iostats->events[stat]++;
- put_cpu_no_resched();
+ put_cpu();
}
static inline void nfs_inc_stats(const struct inode *inode,
@@ -50,7 +50,7 @@ static inline void nfs_add_server_stats(const struct nfs_server *server,
cpu = get_cpu();
iostats = per_cpu_ptr(server->io_stats, cpu);
iostats->bytes[stat] += addend;
- put_cpu_no_resched();
+ put_cpu();
}
static inline void nfs_add_stats(const struct inode *inode,
@@ -71,7 +71,7 @@ static inline void nfs_add_fscache_stats(struct inode *inode,
cpu = get_cpu();
iostats = per_cpu_ptr(NFS_SERVER(inode)->io_stats, cpu);
iostats->fscache[stat] += addend;
- put_cpu_no_resched();
+ put_cpu();
}
#endif
diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c
index 9b0efdad891..477d37d83b3 100644
--- a/fs/nls/nls_base.c
+++ b/fs/nls/nls_base.c
@@ -15,6 +15,7 @@
#include <linux/errno.h>
#include <linux/kmod.h>
#include <linux/spinlock.h>
+#include <asm/byteorder.h>
static struct nls_table default_table;
static struct nls_table *tables = &default_table;
@@ -43,10 +44,17 @@ static const struct utf8_table utf8_table[] =
{0, /* end of table */}
};
-int
-utf8_mbtowc(wchar_t *p, const __u8 *s, int n)
+#define UNICODE_MAX 0x0010ffff
+#define PLANE_SIZE 0x00010000
+
+#define SURROGATE_MASK 0xfffff800
+#define SURROGATE_PAIR 0x0000d800
+#define SURROGATE_LOW 0x00000400
+#define SURROGATE_BITS 0x000003ff
+
+int utf8_to_utf32(const u8 *s, int len, unicode_t *pu)
{
- long l;
+ unsigned long l;
int c0, c, nc;
const struct utf8_table *t;
@@ -57,12 +65,13 @@ utf8_mbtowc(wchar_t *p, const __u8 *s, int n)
nc++;
if ((c0 & t->cmask) == t->cval) {
l &= t->lmask;
- if (l < t->lval)
+ if (l < t->lval || l > UNICODE_MAX ||
+ (l & SURROGATE_MASK) == SURROGATE_PAIR)
return -1;
- *p = l;
+ *pu = (unicode_t) l;
return nc;
}
- if (n <= nc)
+ if (len <= nc)
return -1;
s++;
c = (*s ^ 0x80) & 0xFF;
@@ -72,90 +81,133 @@ utf8_mbtowc(wchar_t *p, const __u8 *s, int n)
}
return -1;
}
+EXPORT_SYMBOL(utf8_to_utf32);
-int
-utf8_mbstowcs(wchar_t *pwcs, const __u8 *s, int n)
+int utf32_to_utf8(unicode_t u, u8 *s, int maxlen)
{
- __u16 *op;
- const __u8 *ip;
- int size;
-
- op = pwcs;
- ip = s;
- while (*ip && n > 0) {
- if (*ip & 0x80) {
- size = utf8_mbtowc(op, ip, n);
- if (size == -1) {
- /* Ignore character and move on */
- ip++;
- n--;
- } else {
- op++;
- ip += size;
- n -= size;
- }
- } else {
- *op++ = *ip++;
- n--;
- }
- }
- return (op - pwcs);
-}
-
-int
-utf8_wctomb(__u8 *s, wchar_t wc, int maxlen)
-{
- long l;
+ unsigned long l;
int c, nc;
const struct utf8_table *t;
-
+
if (!s)
return 0;
-
- l = wc;
+
+ l = u;
+ if (l > UNICODE_MAX || (l & SURROGATE_MASK) == SURROGATE_PAIR)
+ return -1;
+
nc = 0;
for (t = utf8_table; t->cmask && maxlen; t++, maxlen--) {
nc++;
if (l <= t->lmask) {
c = t->shift;
- *s = t->cval | (l >> c);
+ *s = (u8) (t->cval | (l >> c));
while (c > 0) {
c -= 6;
s++;
- *s = 0x80 | ((l >> c) & 0x3F);
+ *s = (u8) (0x80 | ((l >> c) & 0x3F));
}
return nc;
}
}
return -1;
}
+EXPORT_SYMBOL(utf32_to_utf8);
-int
-utf8_wcstombs(__u8 *s, const wchar_t *pwcs, int maxlen)
+int utf8s_to_utf16s(const u8 *s, int len, wchar_t *pwcs)
{
- const __u16 *ip;
- __u8 *op;
+ u16 *op;
int size;
+ unicode_t u;
+
+ op = pwcs;
+ while (*s && len > 0) {
+ if (*s & 0x80) {
+ size = utf8_to_utf32(s, len, &u);
+ if (size < 0) {
+ /* Ignore character and move on */
+ size = 1;
+ } else if (u >= PLANE_SIZE) {
+ u -= PLANE_SIZE;
+ *op++ = (wchar_t) (SURROGATE_PAIR |
+ ((u >> 10) & SURROGATE_BITS));
+ *op++ = (wchar_t) (SURROGATE_PAIR |
+ SURROGATE_LOW |
+ (u & SURROGATE_BITS));
+ } else {
+ *op++ = (wchar_t) u;
+ }
+ s += size;
+ len -= size;
+ } else {
+ *op++ = *s++;
+ len--;
+ }
+ }
+ return op - pwcs;
+}
+EXPORT_SYMBOL(utf8s_to_utf16s);
+
+static inline unsigned long get_utf16(unsigned c, enum utf16_endian endian)
+{
+ switch (endian) {
+ default:
+ return c;
+ case UTF16_LITTLE_ENDIAN:
+ return __le16_to_cpu(c);
+ case UTF16_BIG_ENDIAN:
+ return __be16_to_cpu(c);
+ }
+}
+
+int utf16s_to_utf8s(const wchar_t *pwcs, int len, enum utf16_endian endian,
+ u8 *s, int maxlen)
+{
+ u8 *op;
+ int size;
+ unsigned long u, v;
op = s;
- ip = pwcs;
- while (*ip && maxlen > 0) {
- if (*ip > 0x7f) {
- size = utf8_wctomb(op, *ip, maxlen);
+ while (len > 0 && maxlen > 0) {
+ u = get_utf16(*pwcs, endian);
+ if (!u)
+ break;
+ pwcs++;
+ len--;
+ if (u > 0x7f) {
+ if ((u & SURROGATE_MASK) == SURROGATE_PAIR) {
+ if (u & SURROGATE_LOW) {
+ /* Ignore character and move on */
+ continue;
+ }
+ if (len <= 0)
+ break;
+ v = get_utf16(*pwcs, endian);
+ if ((v & SURROGATE_MASK) != SURROGATE_PAIR ||
+ !(v & SURROGATE_LOW)) {
+ /* Ignore character and move on */
+ continue;
+ }
+ u = PLANE_SIZE + ((u & SURROGATE_BITS) << 10)
+ + (v & SURROGATE_BITS);
+ pwcs++;
+ len--;
+ }
+ size = utf32_to_utf8(u, op, maxlen);
if (size == -1) {
/* Ignore character and move on */
- maxlen--;
} else {
op += size;
maxlen -= size;
}
} else {
- *op++ = (__u8) *ip;
+ *op++ = (u8) u;
+ maxlen--;
}
- ip++;
}
- return (op - s);
+ return op - s;
}
+EXPORT_SYMBOL(utf16s_to_utf8s);
int register_nls(struct nls_table * nls)
{
@@ -467,9 +519,5 @@ EXPORT_SYMBOL(unregister_nls);
EXPORT_SYMBOL(unload_nls);
EXPORT_SYMBOL(load_nls);
EXPORT_SYMBOL(load_nls_default);
-EXPORT_SYMBOL(utf8_mbtowc);
-EXPORT_SYMBOL(utf8_mbstowcs);
-EXPORT_SYMBOL(utf8_wctomb);
-EXPORT_SYMBOL(utf8_wcstombs);
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/fs/nls/nls_utf8.c b/fs/nls/nls_utf8.c
index aa2c42fdd97..0d60a44acac 100644
--- a/fs/nls/nls_utf8.c
+++ b/fs/nls/nls_utf8.c
@@ -15,7 +15,11 @@ static int uni2char(wchar_t uni, unsigned char *out, int boundlen)
{
int n;
- if ( (n = utf8_wctomb(out, uni, boundlen)) == -1) {
+ if (boundlen <= 0)
+ return -ENAMETOOLONG;
+
+ n = utf32_to_utf8(uni, out, boundlen);
+ if (n < 0) {
*out = '?';
return -EINVAL;
}
@@ -25,11 +29,14 @@ static int uni2char(wchar_t uni, unsigned char *out, int boundlen)
static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni)
{
int n;
+ unicode_t u;
- if ( (n = utf8_mbtowc(uni, rawstring, boundlen)) == -1) {
+ n = utf8_to_utf32(rawstring, boundlen, &u);
+ if (n < 0 || u > MAX_WCHAR_T) {
*uni = 0x003f; /* ? */
- n = -EINVAL;
+ return -EINVAL;
}
+ *uni = (wchar_t) u;
return n;
}
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index 82c5085559c..9938034762c 100644
--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -27,6 +27,7 @@
#include <linux/pagemap.h>
#include <linux/quotaops.h>
#include <linux/slab.h>
+#include <linux/log2.h>
#include "aops.h"
#include "attrib.h"
@@ -1570,7 +1571,7 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi)
ntfs_debug("Index collation rule is 0x%x.",
le32_to_cpu(ir->collation_rule));
ni->itype.index.block_size = le32_to_cpu(ir->index_block_size);
- if (ni->itype.index.block_size & (ni->itype.index.block_size - 1)) {
+ if (!is_power_of_2(ni->itype.index.block_size)) {
ntfs_error(vi->i_sb, "Index block size (%u) is not a power of "
"two.", ni->itype.index.block_size);
goto unm_err_out;
diff --git a/fs/ntfs/logfile.c b/fs/ntfs/logfile.c
index d7932e95b1f..89b02985c05 100644
--- a/fs/ntfs/logfile.c
+++ b/fs/ntfs/logfile.c
@@ -26,6 +26,7 @@
#include <linux/highmem.h>
#include <linux/buffer_head.h>
#include <linux/bitops.h>
+#include <linux/log2.h>
#include "attrib.h"
#include "aops.h"
@@ -65,7 +66,7 @@ static bool ntfs_check_restart_page_header(struct inode *vi,
logfile_log_page_size < NTFS_BLOCK_SIZE ||
logfile_system_page_size &
(logfile_system_page_size - 1) ||
- logfile_log_page_size & (logfile_log_page_size - 1)) {
+ !is_power_of_2(logfile_log_page_size)) {
ntfs_error(vi->i_sb, "$LogFile uses unsupported page size.");
return false;
}
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 1539e630c47..3ce5ae9e3d2 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1006,7 +1006,12 @@ static ssize_t oom_adjust_read(struct file *file, char __user *buf,
if (!task)
return -ESRCH;
- oom_adjust = task->oomkilladj;
+ task_lock(task);
+ if (task->mm)
+ oom_adjust = task->mm->oom_adj;
+ else
+ oom_adjust = OOM_DISABLE;
+ task_unlock(task);
put_task_struct(task);
len = snprintf(buffer, sizeof(buffer), "%i\n", oom_adjust);
@@ -1035,11 +1040,19 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf,
task = get_proc_task(file->f_path.dentry->d_inode);
if (!task)
return -ESRCH;
- if (oom_adjust < task->oomkilladj && !capable(CAP_SYS_RESOURCE)) {
+ task_lock(task);
+ if (!task->mm) {
+ task_unlock(task);
+ put_task_struct(task);
+ return -EINVAL;
+ }
+ if (oom_adjust < task->mm->oom_adj && !capable(CAP_SYS_RESOURCE)) {
+ task_unlock(task);
put_task_struct(task);
return -EACCES;
}
- task->oomkilladj = oom_adjust;
+ task->mm->oom_adj = oom_adjust;
+ task_unlock(task);
put_task_struct(task);
if (end - buffer == 0)
return -EIO;
diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c
index c6b0302af4c..d5c410d47fa 100644
--- a/fs/proc/meminfo.c
+++ b/fs/proc/meminfo.c
@@ -64,10 +64,8 @@ static int meminfo_proc_show(struct seq_file *m, void *v)
"Inactive(anon): %8lu kB\n"
"Active(file): %8lu kB\n"
"Inactive(file): %8lu kB\n"
-#ifdef CONFIG_UNEVICTABLE_LRU
"Unevictable: %8lu kB\n"
"Mlocked: %8lu kB\n"
-#endif
#ifdef CONFIG_HIGHMEM
"HighTotal: %8lu kB\n"
"HighFree: %8lu kB\n"
@@ -109,10 +107,8 @@ static int meminfo_proc_show(struct seq_file *m, void *v)
K(pages[LRU_INACTIVE_ANON]),
K(pages[LRU_ACTIVE_FILE]),
K(pages[LRU_INACTIVE_FILE]),
-#ifdef CONFIG_UNEVICTABLE_LRU
K(pages[LRU_UNEVICTABLE]),
K(global_page_state(NR_MLOCK)),
-#endif
#ifdef CONFIG_HIGHMEM
K(i.totalhigh),
K(i.freehigh),
diff --git a/fs/proc/page.c b/fs/proc/page.c
index e9983837d08..2707c6c7a20 100644
--- a/fs/proc/page.c
+++ b/fs/proc/page.c
@@ -6,11 +6,13 @@
#include <linux/mmzone.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <linux/hugetlb.h>
#include <asm/uaccess.h>
#include "internal.h"
#define KPMSIZE sizeof(u64)
#define KPMMASK (KPMSIZE - 1)
+
/* /proc/kpagecount - an array exposing page counts
*
* Each entry is a u64 representing the corresponding
@@ -32,20 +34,22 @@ static ssize_t kpagecount_read(struct file *file, char __user *buf,
return -EINVAL;
while (count > 0) {
- ppage = NULL;
if (pfn_valid(pfn))
ppage = pfn_to_page(pfn);
- pfn++;
+ else
+ ppage = NULL;
if (!ppage)
pcount = 0;
else
pcount = page_mapcount(ppage);
- if (put_user(pcount, out++)) {
+ if (put_user(pcount, out)) {
ret = -EFAULT;
break;
}
+ pfn++;
+ out++;
count -= KPMSIZE;
}
@@ -68,19 +72,122 @@ static const struct file_operations proc_kpagecount_operations = {
/* These macros are used to decouple internal flags from exported ones */
-#define KPF_LOCKED 0
-#define KPF_ERROR 1
-#define KPF_REFERENCED 2
-#define KPF_UPTODATE 3
-#define KPF_DIRTY 4
-#define KPF_LRU 5
-#define KPF_ACTIVE 6
-#define KPF_SLAB 7
-#define KPF_WRITEBACK 8
-#define KPF_RECLAIM 9
-#define KPF_BUDDY 10
+#define KPF_LOCKED 0
+#define KPF_ERROR 1
+#define KPF_REFERENCED 2
+#define KPF_UPTODATE 3
+#define KPF_DIRTY 4
+#define KPF_LRU 5
+#define KPF_ACTIVE 6
+#define KPF_SLAB 7
+#define KPF_WRITEBACK 8
+#define KPF_RECLAIM 9
+#define KPF_BUDDY 10
+
+/* 11-20: new additions in 2.6.31 */
+#define KPF_MMAP 11
+#define KPF_ANON 12
+#define KPF_SWAPCACHE 13
+#define KPF_SWAPBACKED 14
+#define KPF_COMPOUND_HEAD 15
+#define KPF_COMPOUND_TAIL 16
+#define KPF_HUGE 17
+#define KPF_UNEVICTABLE 18
+#define KPF_NOPAGE 20
+
+/* kernel hacking assistances
+ * WARNING: subject to change, never rely on them!
+ */
+#define KPF_RESERVED 32
+#define KPF_MLOCKED 33
+#define KPF_MAPPEDTODISK 34
+#define KPF_PRIVATE 35
+#define KPF_PRIVATE_2 36
+#define KPF_OWNER_PRIVATE 37
+#define KPF_ARCH 38
+#define KPF_UNCACHED 39
+
+static inline u64 kpf_copy_bit(u64 kflags, int ubit, int kbit)
+{
+ return ((kflags >> kbit) & 1) << ubit;
+}
-#define kpf_copy_bit(flags, dstpos, srcpos) (((flags >> srcpos) & 1) << dstpos)
+static u64 get_uflags(struct page *page)
+{
+ u64 k;
+ u64 u;
+
+ /*
+ * pseudo flag: KPF_NOPAGE
+ * it differentiates a memory hole from a page with no flags
+ */
+ if (!page)
+ return 1 << KPF_NOPAGE;
+
+ k = page->flags;
+ u = 0;
+
+ /*
+ * pseudo flags for the well known (anonymous) memory mapped pages
+ *
+ * Note that page->_mapcount is overloaded in SLOB/SLUB/SLQB, so the
+ * simple test in page_mapped() is not enough.
+ */
+ if (!PageSlab(page) && page_mapped(page))
+ u |= 1 << KPF_MMAP;
+ if (PageAnon(page))
+ u |= 1 << KPF_ANON;
+
+ /*
+ * compound pages: export both head/tail info
+ * they together define a compound page's start/end pos and order
+ */
+ if (PageHead(page))
+ u |= 1 << KPF_COMPOUND_HEAD;
+ if (PageTail(page))
+ u |= 1 << KPF_COMPOUND_TAIL;
+ if (PageHuge(page))
+ u |= 1 << KPF_HUGE;
+
+ u |= kpf_copy_bit(k, KPF_LOCKED, PG_locked);
+
+ /*
+ * Caveats on high order pages:
+ * PG_buddy will only be set on the head page; SLUB/SLQB do the same
+ * for PG_slab; SLOB won't set PG_slab at all on compound pages.
+ */
+ u |= kpf_copy_bit(k, KPF_SLAB, PG_slab);
+ u |= kpf_copy_bit(k, KPF_BUDDY, PG_buddy);
+
+ u |= kpf_copy_bit(k, KPF_ERROR, PG_error);
+ u |= kpf_copy_bit(k, KPF_DIRTY, PG_dirty);
+ u |= kpf_copy_bit(k, KPF_UPTODATE, PG_uptodate);
+ u |= kpf_copy_bit(k, KPF_WRITEBACK, PG_writeback);
+
+ u |= kpf_copy_bit(k, KPF_LRU, PG_lru);
+ u |= kpf_copy_bit(k, KPF_REFERENCED, PG_referenced);
+ u |= kpf_copy_bit(k, KPF_ACTIVE, PG_active);
+ u |= kpf_copy_bit(k, KPF_RECLAIM, PG_reclaim);
+
+ u |= kpf_copy_bit(k, KPF_SWAPCACHE, PG_swapcache);
+ u |= kpf_copy_bit(k, KPF_SWAPBACKED, PG_swapbacked);
+
+ u |= kpf_copy_bit(k, KPF_UNEVICTABLE, PG_unevictable);
+ u |= kpf_copy_bit(k, KPF_MLOCKED, PG_mlocked);
+
+#ifdef CONFIG_IA64_UNCACHED_ALLOCATOR
+ u |= kpf_copy_bit(k, KPF_UNCACHED, PG_uncached);
+#endif
+
+ u |= kpf_copy_bit(k, KPF_RESERVED, PG_reserved);
+ u |= kpf_copy_bit(k, KPF_MAPPEDTODISK, PG_mappedtodisk);
+ u |= kpf_copy_bit(k, KPF_PRIVATE, PG_private);
+ u |= kpf_copy_bit(k, KPF_PRIVATE_2, PG_private_2);
+ u |= kpf_copy_bit(k, KPF_OWNER_PRIVATE, PG_owner_priv_1);
+ u |= kpf_copy_bit(k, KPF_ARCH, PG_arch_1);
+
+ return u;
+};
static ssize_t kpageflags_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
@@ -90,7 +197,6 @@ static ssize_t kpageflags_read(struct file *file, char __user *buf,
unsigned long src = *ppos;
unsigned long pfn;
ssize_t ret = 0;
- u64 kflags, uflags;
pfn = src / KPMSIZE;
count = min_t(unsigned long, count, (max_pfn * KPMSIZE) - src);
@@ -98,32 +204,18 @@ static ssize_t kpageflags_read(struct file *file, char __user *buf,
return -EINVAL;
while (count > 0) {
- ppage = NULL;
if (pfn_valid(pfn))
ppage = pfn_to_page(pfn);
- pfn++;
- if (!ppage)
- kflags = 0;
else
- kflags = ppage->flags;
-
- uflags = kpf_copy_bit(kflags, KPF_LOCKED, PG_locked) |
- kpf_copy_bit(kflags, KPF_ERROR, PG_error) |
- kpf_copy_bit(kflags, KPF_REFERENCED, PG_referenced) |
- kpf_copy_bit(kflags, KPF_UPTODATE, PG_uptodate) |
- kpf_copy_bit(kflags, KPF_DIRTY, PG_dirty) |
- kpf_copy_bit(kflags, KPF_LRU, PG_lru) |
- kpf_copy_bit(kflags, KPF_ACTIVE, PG_active) |
- kpf_copy_bit(kflags, KPF_SLAB, PG_slab) |
- kpf_copy_bit(kflags, KPF_WRITEBACK, PG_writeback) |
- kpf_copy_bit(kflags, KPF_RECLAIM, PG_reclaim) |
- kpf_copy_bit(kflags, KPF_BUDDY, PG_buddy);
-
- if (put_user(uflags, out++)) {
+ ppage = NULL;
+
+ if (put_user(get_uflags(ppage), out)) {
ret = -EFAULT;
break;
}
+ pfn++;
+ out++;
count -= KPMSIZE;
}
diff --git a/fs/select.c b/fs/select.c
index 0fe0e1469df..d870237e42c 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -168,7 +168,7 @@ static struct poll_table_entry *poll_get_entry(struct poll_wqueues *p)
return table->entry++;
}
-static int pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key)
+static int __pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key)
{
struct poll_wqueues *pwq = wait->private;
DECLARE_WAITQUEUE(dummy_wait, pwq->polling_task);
@@ -194,6 +194,16 @@ static int pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key)
return default_wake_function(&dummy_wait, mode, sync, key);
}
+static int pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key)
+{
+ struct poll_table_entry *entry;
+
+ entry = container_of(wait, struct poll_table_entry, wait);
+ if (key && !((unsigned long)key & entry->key))
+ return 0;
+ return __pollwake(wait, mode, sync, key);
+}
+
/* Add a new entry */
static void __pollwait(struct file *filp, wait_queue_head_t *wait_address,
poll_table *p)
@@ -205,6 +215,7 @@ static void __pollwait(struct file *filp, wait_queue_head_t *wait_address,
get_file(filp);
entry->filp = filp;
entry->wait_address = wait_address;
+ entry->key = p->key;
init_waitqueue_func_entry(&entry->wait, pollwake);
entry->wait.private = pwq;
add_wait_queue(wait_address, &entry->wait);
@@ -362,6 +373,18 @@ get_max:
#define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR)
#define POLLEX_SET (POLLPRI)
+static inline void wait_key_set(poll_table *wait, unsigned long in,
+ unsigned long out, unsigned long bit)
+{
+ if (wait) {
+ wait->key = POLLEX_SET;
+ if (in & bit)
+ wait->key |= POLLIN_SET;
+ if (out & bit)
+ wait->key |= POLLOUT_SET;
+ }
+}
+
int do_select(int n, fd_set_bits *fds, struct timespec *end_time)
{
ktime_t expire, *to = NULL;
@@ -418,20 +441,25 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time)
if (file) {
f_op = file->f_op;
mask = DEFAULT_POLLMASK;
- if (f_op && f_op->poll)
- mask = (*f_op->poll)(file, retval ? NULL : wait);
+ if (f_op && f_op->poll) {
+ wait_key_set(wait, in, out, bit);
+ mask = (*f_op->poll)(file, wait);
+ }
fput_light(file, fput_needed);
if ((mask & POLLIN_SET) && (in & bit)) {
res_in |= bit;
retval++;
+ wait = NULL;
}
if ((mask & POLLOUT_SET) && (out & bit)) {
res_out |= bit;
retval++;
+ wait = NULL;
}
if ((mask & POLLEX_SET) && (ex & bit)) {
res_ex |= bit;
retval++;
+ wait = NULL;
}
}
}
@@ -685,8 +713,12 @@ static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait)
mask = POLLNVAL;
if (file != NULL) {
mask = DEFAULT_POLLMASK;
- if (file->f_op && file->f_op->poll)
+ if (file->f_op && file->f_op->poll) {
+ if (pwait)
+ pwait->key = pollfd->events |
+ POLLERR | POLLHUP;
mask = file->f_op->poll(file, pwait);
+ }
/* Mask out unneeded events. */
mask &= pollfd->events | POLLERR | POLLHUP;
fput_light(file, fput_needed);
diff --git a/fs/super.c b/fs/super.c
index 83b47416d00..d40d53a22fb 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -545,24 +545,18 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY)) {
if (force)
mark_files_ro(sb);
- else if (!fs_may_remount_ro(sb)) {
- unlock_kernel();
+ else if (!fs_may_remount_ro(sb))
return -EBUSY;
- }
retval = vfs_dq_off(sb, 1);
- if (retval < 0 && retval != -ENOSYS) {
- unlock_kernel();
+ if (retval < 0 && retval != -ENOSYS)
return -EBUSY;
- }
}
remount_rw = !(flags & MS_RDONLY) && (sb->s_flags & MS_RDONLY);
if (sb->s_op->remount_fs) {
retval = sb->s_op->remount_fs(sb, &flags, data);
- if (retval) {
- unlock_kernel();
+ if (retval)
return retval;
- }
}
sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
if (remount_rw)
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c
index a3ba217fbe7..1d897ad808e 100644
--- a/fs/sysfs/symlink.c
+++ b/fs/sysfs/symlink.c
@@ -192,8 +192,11 @@ static void *sysfs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
int error = -ENOMEM;
unsigned long page = get_zeroed_page(GFP_KERNEL);
- if (page)
+ if (page) {
error = sysfs_getlink(dentry, (char *) page);
+ if (error < 0)
+ free_page((unsigned long)page);
+ }
nd_set_link(nd, error ? ERR_PTR(error) : (char *)page);
return NULL;
}
diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c
index c7798079e64..4e50286a4cc 100644
--- a/fs/sysv/dir.c
+++ b/fs/sysv/dir.c
@@ -15,13 +15,13 @@
#include <linux/pagemap.h>
#include <linux/highmem.h>
-#include <linux/smp_lock.h>
#include <linux/swap.h>
#include "sysv.h"
static int sysv_readdir(struct file *, void *, filldir_t);
const struct file_operations sysv_dir_operations = {
+ .llseek = generic_file_llseek,
.read = generic_read_dir,
.readdir = sysv_readdir,
.fsync = simple_fsync,
@@ -74,8 +74,6 @@ static int sysv_readdir(struct file * filp, void * dirent, filldir_t filldir)
unsigned long n = pos >> PAGE_CACHE_SHIFT;
unsigned long npages = dir_pages(inode);
- lock_kernel();
-
pos = (pos + SYSV_DIRSIZE-1) & ~(SYSV_DIRSIZE-1);
if (pos >= inode->i_size)
goto done;
@@ -113,7 +111,6 @@ static int sysv_readdir(struct file * filp, void * dirent, filldir_t filldir)
done:
filp->f_pos = ((loff_t)n << PAGE_CACHE_SHIFT) | offset;
- unlock_kernel();
return 0;
}
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index 479923456a5..9824743832a 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -21,7 +21,6 @@
* the superblock.
*/
-#include <linux/smp_lock.h>
#include <linux/highuid.h>
#include <linux/slab.h>
#include <linux/init.h>
@@ -37,7 +36,6 @@ static int sysv_sync_fs(struct super_block *sb, int wait)
unsigned long time = get_seconds(), old_time;
lock_super(sb);
- lock_kernel();
/*
* If we are going to write out the super block,
@@ -52,7 +50,6 @@ static int sysv_sync_fs(struct super_block *sb, int wait)
mark_buffer_dirty(sbi->s_bh2);
}
- unlock_kernel();
unlock_super(sb);
return 0;
@@ -82,8 +79,6 @@ static void sysv_put_super(struct super_block *sb)
{
struct sysv_sb_info *sbi = SYSV_SB(sb);
- lock_kernel();
-
if (sb->s_dirt)
sysv_write_super(sb);
@@ -99,8 +94,6 @@ static void sysv_put_super(struct super_block *sb)
brelse(sbi->s_bh2);
kfree(sbi);
-
- unlock_kernel();
}
static int sysv_statfs(struct dentry *dentry, struct kstatfs *buf)
@@ -275,7 +268,6 @@ int sysv_write_inode(struct inode *inode, int wait)
return -EIO;
}
- lock_kernel();
raw_inode->i_mode = cpu_to_fs16(sbi, inode->i_mode);
raw_inode->i_uid = cpu_to_fs16(sbi, fs_high2lowuid(inode->i_uid));
raw_inode->i_gid = cpu_to_fs16(sbi, fs_high2lowgid(inode->i_gid));
@@ -291,7 +283,6 @@ int sysv_write_inode(struct inode *inode, int wait)
for (block = 0; block < 10+1+1+1; block++)
write3byte(sbi, (u8 *)&si->i_data[block],
&raw_inode->i_data[3*block]);
- unlock_kernel();
mark_buffer_dirty(bh);
if (wait) {
sync_dirty_buffer(bh);
@@ -315,9 +306,7 @@ static void sysv_delete_inode(struct inode *inode)
truncate_inode_pages(&inode->i_data, 0);
inode->i_size = 0;
sysv_truncate(inode);
- lock_kernel();
sysv_free_inode(inode);
- unlock_kernel();
}
static struct kmem_cache *sysv_inode_cachep;
diff --git a/fs/ubifs/budget.c b/fs/ubifs/budget.c
index af1914462f0..eaf6d891d46 100644
--- a/fs/ubifs/budget.c
+++ b/fs/ubifs/budget.c
@@ -91,7 +91,6 @@ static int shrink_liability(struct ubifs_info *c, int nr_to_write)
return nr_written;
}
-
/**
* run_gc - run garbage collector.
* @c: UBIFS file-system description object
@@ -628,7 +627,7 @@ void ubifs_convert_page_budget(struct ubifs_info *c)
*
* This function releases budget corresponding to a dirty inode. It is usually
* called when after the inode has been written to the media and marked as
- * clean.
+ * clean. It also causes the "no space" flags to be cleared.
*/
void ubifs_release_dirty_inode_budget(struct ubifs_info *c,
struct ubifs_inode *ui)
@@ -636,6 +635,7 @@ void ubifs_release_dirty_inode_budget(struct ubifs_info *c,
struct ubifs_budget_req req;
memset(&req, 0, sizeof(struct ubifs_budget_req));
+ /* The "no space" flags will be cleared because dd_growth is > 0 */
req.dd_growth = c->inode_budget + ALIGN(ui->data_len, 8);
ubifs_release_budget(c, &req);
}
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index f55d523c52b..552fb0111ff 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -528,6 +528,25 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
inode->i_nlink, dir->i_ino);
ubifs_assert(mutex_is_locked(&dir->i_mutex));
ubifs_assert(mutex_is_locked(&inode->i_mutex));
+
+ /*
+ * Return -ENOENT if we've raced with unlink and i_nlink is 0. Doing
+ * otherwise has the potential to corrupt the orphan inode list.
+ *
+ * Indeed, consider a scenario when 'vfs_link(dirA/fileA)' and
+ * 'vfs_unlink(dirA/fileA, dirB/fileB)' race. 'vfs_link()' does not
+ * lock 'dirA->i_mutex', so this is possible. Both of the functions
+ * lock 'fileA->i_mutex' though. Suppose 'vfs_unlink()' wins, and takes
+ * 'fileA->i_mutex' mutex first. Suppose 'fileA->i_nlink' is 1. In this
+ * case 'ubifs_unlink()' will drop the last reference, and put 'inodeA'
+ * to the list of orphans. After this, 'vfs_link()' will link
+ * 'dirB/fileB' to 'inodeA'. This is a problem because, for example,
+ * the subsequent 'vfs_unlink(dirB/fileB)' will add the same inode
+ * to the list of orphans.
+ */
+ if (inode->i_nlink == 0)
+ return -ENOENT;
+
err = dbg_check_synced_i_size(inode);
if (err)
return err;
diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c
index e8e632a1dcd..bc5857199ec 100644
--- a/fs/ubifs/io.c
+++ b/fs/ubifs/io.c
@@ -293,13 +293,14 @@ void ubifs_prep_grp_node(struct ubifs_info *c, void *node, int len, int last)
*
* This function is called when the write-buffer timer expires.
*/
-static void wbuf_timer_callback_nolock(unsigned long data)
+static enum hrtimer_restart wbuf_timer_callback_nolock(struct hrtimer *timer)
{
- struct ubifs_wbuf *wbuf = (struct ubifs_wbuf *)data;
+ struct ubifs_wbuf *wbuf = container_of(timer, struct ubifs_wbuf, timer);
wbuf->need_sync = 1;
wbuf->c->need_wbuf_sync = 1;
ubifs_wake_up_bgt(wbuf->c);
+ return HRTIMER_NORESTART;
}
/**
@@ -308,13 +309,12 @@ static void wbuf_timer_callback_nolock(unsigned long data)
*/
static void new_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
{
- ubifs_assert(!timer_pending(&wbuf->timer));
+ ubifs_assert(!hrtimer_active(&wbuf->timer));
- if (!wbuf->timeout)
+ if (!ktime_to_ns(wbuf->softlimit))
return;
-
- wbuf->timer.expires = jiffies + wbuf->timeout;
- add_timer(&wbuf->timer);
+ hrtimer_start_range_ns(&wbuf->timer, wbuf->softlimit, wbuf->delta,
+ HRTIMER_MODE_REL);
}
/**
@@ -329,7 +329,7 @@ static void cancel_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
* should be canceled.
*/
wbuf->need_sync = 0;
- del_timer(&wbuf->timer);
+ hrtimer_cancel(&wbuf->timer);
}
/**
@@ -825,6 +825,7 @@ out:
int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf)
{
size_t size;
+ ktime_t hardlimit;
wbuf->buf = kmalloc(c->min_io_size, GFP_KERNEL);
if (!wbuf->buf)
@@ -845,14 +846,21 @@ int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf)
wbuf->sync_callback = NULL;
mutex_init(&wbuf->io_mutex);
spin_lock_init(&wbuf->lock);
-
wbuf->c = c;
- init_timer(&wbuf->timer);
- wbuf->timer.function = wbuf_timer_callback_nolock;
- wbuf->timer.data = (unsigned long)wbuf;
- wbuf->timeout = DEFAULT_WBUF_TIMEOUT;
wbuf->next_ino = 0;
+ hrtimer_init(&wbuf->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ wbuf->timer.function = wbuf_timer_callback_nolock;
+ /*
+ * Make write-buffer soft limit to be 20% of the hard limit. The
+ * write-buffer timer is allowed to expire any time between the soft
+ * and hard limits.
+ */
+ hardlimit = ktime_set(DEFAULT_WBUF_TIMEOUT_SECS, 0);
+ wbuf->delta = (DEFAULT_WBUF_TIMEOUT_SECS * NSEC_PER_SEC) * 2 / 10;
+ wbuf->softlimit = ktime_sub_ns(hardlimit, wbuf->delta);
+ hrtimer_set_expires_range_ns(&wbuf->timer, wbuf->softlimit,
+ wbuf->delta);
return 0;
}
diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c
index 10662975d2e..805605250f1 100644
--- a/fs/ubifs/recovery.c
+++ b/fs/ubifs/recovery.c
@@ -343,33 +343,15 @@ int ubifs_write_rcvrd_mst_node(struct ubifs_info *c)
*
* This function returns %1 if @offs was in the last write to the LEB whose data
* is in @buf, otherwise %0 is returned. The determination is made by checking
- * for subsequent empty space starting from the next min_io_size boundary (or a
- * bit less than the common header size if min_io_size is one).
+ * for subsequent empty space starting from the next @c->min_io_size boundary.
*/
static int is_last_write(const struct ubifs_info *c, void *buf, int offs)
{
- int empty_offs;
- int check_len;
+ int empty_offs, check_len;
uint8_t *p;
- if (c->min_io_size == 1) {
- check_len = c->leb_size - offs;
- p = buf + check_len;
- for (; check_len > 0; check_len--)
- if (*--p != 0xff)
- break;
- /*
- * 'check_len' is the size of the corruption which cannot be
- * more than the size of 1 node if it was caused by an unclean
- * unmount.
- */
- if (check_len > UBIFS_MAX_NODE_SZ)
- return 0;
- return 1;
- }
-
/*
- * Round up to the next c->min_io_size boundary i.e. 'offs' is in the
+ * Round up to the next @c->min_io_size boundary i.e. @offs is in the
* last wbuf written. After that should be empty space.
*/
empty_offs = ALIGN(offs + 1, c->min_io_size);
@@ -392,7 +374,7 @@ static int is_last_write(const struct ubifs_info *c, void *buf, int offs)
*
* This function pads up to the next min_io_size boundary (if there is one) and
* sets empty space to all 0xff. @buf, @offs and @len are updated to the next
- * min_io_size boundary (if there is one).
+ * @c->min_io_size boundary.
*/
static void clean_buf(const struct ubifs_info *c, void **buf, int lnum,
int *offs, int *len)
@@ -402,11 +384,6 @@ static void clean_buf(const struct ubifs_info *c, void **buf, int lnum,
lnum = lnum;
dbg_rcvry("cleaning corruption at %d:%d", lnum, *offs);
- if (c->min_io_size == 1) {
- memset(*buf, 0xff, c->leb_size - *offs);
- return;
- }
-
ubifs_assert(!(*offs & 7));
empty_offs = ALIGN(*offs, c->min_io_size);
pad_len = empty_offs - *offs;
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 3260b73abe2..79fad43f3c5 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -361,6 +361,11 @@ static void ubifs_delete_inode(struct inode *inode)
out:
if (ui->dirty)
ubifs_release_dirty_inode_budget(c, ui);
+ else {
+ /* We've deleted something - clean the "no space" flags */
+ c->nospace = c->nospace_rp = 0;
+ smp_wmb();
+ }
clear_inode(inode);
}
@@ -792,7 +797,7 @@ static int alloc_wbufs(struct ubifs_info *c)
* does not need to be synchronized by timer.
*/
c->jheads[GCHD].wbuf.dtype = UBI_LONGTERM;
- c->jheads[GCHD].wbuf.timeout = 0;
+ c->jheads[GCHD].wbuf.softlimit = ktime_set(0, 0);
return 0;
}
@@ -933,6 +938,27 @@ static const match_table_t tokens = {
};
/**
+ * parse_standard_option - parse a standard mount option.
+ * @option: the option to parse
+ *
+ * Normally, standard mount options like "sync" are passed to file-systems as
+ * flags. However, when a "rootflags=" kernel boot parameter is used, they may
+ * be present in the options string. This function tries to deal with this
+ * situation and parse standard options. Returns 0 if the option was not
+ * recognized, and the corresponding integer flag if it was.
+ *
+ * UBIFS is only interested in the "sync" option, so do not check for anything
+ * else.
+ */
+static int parse_standard_option(const char *option)
+{
+ ubifs_msg("parse %s", option);
+ if (!strcmp(option, "sync"))
+ return MS_SYNCHRONOUS;
+ return 0;
+}
+
+/**
* ubifs_parse_options - parse mount parameters.
* @c: UBIFS file-system description object
* @options: parameters to parse
@@ -1008,9 +1034,19 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options,
break;
}
default:
- ubifs_err("unrecognized mount option \"%s\" "
- "or missing value", p);
- return -EINVAL;
+ {
+ unsigned long flag;
+ struct super_block *sb = c->vfs_sb;
+
+ flag = parse_standard_option(p);
+ if (!flag) {
+ ubifs_err("unrecognized mount option \"%s\" "
+ "or missing value", p);
+ return -EINVAL;
+ }
+ sb->s_flags |= flag;
+ break;
+ }
}
}
@@ -1180,6 +1216,7 @@ static int mount_ubifs(struct ubifs_info *c)
if (!ubifs_compr_present(c->default_compr)) {
ubifs_err("'compressor \"%s\" is not compiled in",
ubifs_compr_name(c->default_compr));
+ err = -ENOTSUPP;
goto out_free;
}
@@ -1656,7 +1693,7 @@ static void ubifs_remount_ro(struct ubifs_info *c)
for (i = 0; i < c->jhead_cnt; i++) {
ubifs_wbuf_sync(&c->jheads[i].wbuf);
- del_timer_sync(&c->jheads[i].wbuf.timer);
+ hrtimer_cancel(&c->jheads[i].wbuf.timer);
}
c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_DIRTY);
@@ -1719,7 +1756,7 @@ static void ubifs_put_super(struct super_block *sb)
if (c->jheads)
for (i = 0; i < c->jhead_cnt; i++) {
ubifs_wbuf_sync(&c->jheads[i].wbuf);
- del_timer_sync(&c->jheads[i].wbuf.timer);
+ hrtimer_cancel(&c->jheads[i].wbuf.timer);
}
/*
@@ -1911,6 +1948,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
INIT_LIST_HEAD(&c->orph_list);
INIT_LIST_HEAD(&c->orph_new);
+ c->vfs_sb = sb;
c->highest_inum = UBIFS_FIRST_INO;
c->lhead_lnum = c->ltail_lnum = UBIFS_LOG_LNUM;
@@ -1945,13 +1983,10 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
if (err)
goto out_bdi;
- c->vfs_sb = sb;
-
sb->s_fs_info = c;
sb->s_magic = UBIFS_SUPER_MAGIC;
sb->s_blocksize = UBIFS_BLOCK_SIZE;
sb->s_blocksize_bits = UBIFS_BLOCK_SHIFT;
- sb->s_dev = c->vi.cdev;
sb->s_maxbytes = c->max_inode_sz = key_max_inode_size(c);
if (c->max_inode_sz > MAX_LFS_FILESIZE)
sb->s_maxbytes = c->max_inode_sz = MAX_LFS_FILESIZE;
@@ -1996,16 +2031,9 @@ out_free:
static int sb_test(struct super_block *sb, void *data)
{
dev_t *dev = data;
+ struct ubifs_info *c = sb->s_fs_info;
- return sb->s_dev == *dev;
-}
-
-static int sb_set(struct super_block *sb, void *data)
-{
- dev_t *dev = data;
-
- sb->s_dev = *dev;
- return 0;
+ return c->vi.cdev == *dev;
}
static int ubifs_get_sb(struct file_system_type *fs_type, int flags,
@@ -2033,7 +2061,7 @@ static int ubifs_get_sb(struct file_system_type *fs_type, int flags,
dbg_gen("opened ubi%d_%d", vi.ubi_num, vi.vol_id);
- sb = sget(fs_type, &sb_test, &sb_set, &vi.cdev);
+ sb = sget(fs_type, &sb_test, &set_anon_super, &vi.cdev);
if (IS_ERR(sb)) {
err = PTR_ERR(sb);
goto out_close;
@@ -2073,16 +2101,11 @@ out_close:
return err;
}
-static void ubifs_kill_sb(struct super_block *sb)
-{
- generic_shutdown_super(sb);
-}
-
static struct file_system_type ubifs_fs_type = {
.name = "ubifs",
.owner = THIS_MODULE,
.get_sb = ubifs_get_sb,
- .kill_sb = ubifs_kill_sb
+ .kill_sb = kill_anon_super,
};
/*
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 0a8341e1408..1bf01d82006 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -95,8 +95,8 @@
*/
#define BGT_NAME_PATTERN "ubifs_bgt%d_%d"
-/* Default write-buffer synchronization timeout (5 secs) */
-#define DEFAULT_WBUF_TIMEOUT (5 * HZ)
+/* Default write-buffer synchronization timeout in seconds */
+#define DEFAULT_WBUF_TIMEOUT_SECS 5
/* Maximum possible inode number (only 32-bit inodes are supported now) */
#define MAX_INUM 0xFFFFFFFF
@@ -650,8 +650,10 @@ typedef int (*ubifs_lpt_scan_callback)(struct ubifs_info *c,
* @io_mutex: serializes write-buffer I/O
* @lock: serializes @buf, @lnum, @offs, @avail, @used, @next_ino and @inodes
* fields
+ * @softlimit: soft write-buffer timeout interval
+ * @delta: hard and soft timeouts delta (the timer expire inteval is @softlimit
+ * and @softlimit + @delta)
* @timer: write-buffer timer
- * @timeout: timer expire interval in jiffies
* @need_sync: it is set if its timer expired and needs sync
* @next_ino: points to the next position of the following inode number
* @inodes: stores the inode numbers of the nodes which are in wbuf
@@ -678,8 +680,9 @@ struct ubifs_wbuf {
int (*sync_callback)(struct ubifs_info *c, int lnum, int free, int pad);
struct mutex io_mutex;
spinlock_t lock;
- struct timer_list timer;
- int timeout;
+ ktime_t softlimit;
+ unsigned long long delta;
+ struct hrtimer timer;
int need_sync;
int next_ino;
ino_t *inodes;