aboutsummaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/Kconfig2
-rw-r--r--fs/afs/Makefile1
-rw-r--r--fs/afs/afs.h8
-rw-r--r--fs/afs/afs_fs.h3
-rw-r--r--fs/afs/callback.c3
-rw-r--r--fs/afs/dir.c1
-rw-r--r--fs/afs/file.c2
-rw-r--r--fs/afs/flock.c558
-rw-r--r--fs/afs/fsclient.c155
-rw-r--r--fs/afs/internal.h30
-rw-r--r--fs/afs/main.c1
-rw-r--r--fs/afs/misc.c1
-rw-r--r--fs/afs/proc.c81
-rw-r--r--fs/afs/super.c3
-rw-r--r--fs/afs/vnode.c132
-rw-r--r--fs/anon_inodes.c10
-rw-r--r--fs/binfmt_elf.c109
-rw-r--r--fs/block_dev.c63
-rw-r--r--fs/buffer.c5
-rw-r--r--fs/compat_ioctl.c4
-rw-r--r--fs/drop_caches.c2
-rw-r--r--fs/ext2/file.c6
-rw-r--r--fs/ext2/super.c20
-rw-r--r--fs/ext3/inode.c2
-rw-r--r--fs/ext3/namei.c10
-rw-r--r--fs/ext3/super.c51
-rw-r--r--fs/ext4/balloc.c2
-rw-r--r--fs/ext4/namei.c10
-rw-r--r--fs/ext4/super.c48
-rw-r--r--fs/fat/dir.c31
-rw-r--r--fs/fat/fatent.c7
-rw-r--r--fs/fat/inode.c3
-rw-r--r--fs/freevxfs/vxfs_dir.h2
-rw-r--r--fs/gfs2/eaops.c1
-rw-r--r--fs/hfsplus/btree.c4
-rw-r--r--fs/hfsplus/dir.c2
-rw-r--r--fs/hfsplus/hfsplus_fs.h4
-rw-r--r--fs/hfsplus/inode.c5
-rw-r--r--fs/hfsplus/super.c4
-rw-r--r--fs/hfsplus/unicode.c230
-rw-r--r--fs/hugetlbfs/inode.c96
-rw-r--r--fs/ioctl.c22
-rw-r--r--fs/isofs/dir.c87
-rw-r--r--fs/isofs/inode.c417
-rw-r--r--fs/isofs/joliet.c10
-rw-r--r--fs/isofs/namei.c26
-rw-r--r--fs/jbd/commit.c3
-rw-r--r--fs/jbd/revoke.c5
-rw-r--r--fs/jbd2/commit.c3
-rw-r--r--fs/jbd2/revoke.c5
-rw-r--r--fs/namespace.c23
-rw-r--r--fs/ncpfs/file.c2
-rw-r--r--fs/nfs/client.c54
-rw-r--r--fs/nls/Makefile2
-rw-r--r--fs/open.c14
-rw-r--r--fs/partitions/acorn.c9
-rw-r--r--fs/proc/array.c15
-rw-r--r--fs/proc/base.c83
-rw-r--r--fs/proc/generic.c52
-rw-r--r--fs/proc/inode.c254
-rw-r--r--fs/proc/proc_misc.c7
-rw-r--r--fs/proc/proc_tty.c15
-rw-r--r--fs/quota.c118
-rw-r--r--fs/reiserfs/file.c1
-rw-r--r--fs/seq_file.c18
-rw-r--r--fs/super.c1
-rw-r--r--fs/udf/crc.c4
-rw-r--r--fs/udf/ialloc.c9
-rw-r--r--fs/udf/inode.c51
-rw-r--r--fs/ufs/super.c5
70 files changed, 2260 insertions, 767 deletions
diff --git a/fs/Kconfig b/fs/Kconfig
index 94b9d861bf9..ee11f8d9408 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -991,7 +991,7 @@ config TMPFS_POSIX_ACL
config HUGETLBFS
bool "HugeTLB file system support"
- depends on X86 || IA64 || PPC64 || SPARC64 || SUPERH || BROKEN
+ depends on X86 || IA64 || PPC64 || SPARC64 || (SUPERH && MMU) || 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/afs/Makefile b/fs/afs/Makefile
index 73ce561f3ea..a66671082cf 100644
--- a/fs/afs/Makefile
+++ b/fs/afs/Makefile
@@ -8,6 +8,7 @@ kafs-objs := \
cmservice.o \
dir.o \
file.o \
+ flock.o \
fsclient.o \
inode.o \
main.o \
diff --git a/fs/afs/afs.h b/fs/afs/afs.h
index 24525794814..c548aa346f0 100644
--- a/fs/afs/afs.h
+++ b/fs/afs/afs.h
@@ -37,6 +37,13 @@ typedef enum {
AFS_FTYPE_SYMLINK = 3,
} afs_file_type_t;
+typedef enum {
+ AFS_LOCK_READ = 0, /* read lock request */
+ AFS_LOCK_WRITE = 1, /* write lock request */
+} afs_lock_type_t;
+
+#define AFS_LOCKWAIT (5 * 60) /* time until a lock times out (seconds) */
+
/*
* AFS file identifier
*/
@@ -120,6 +127,7 @@ struct afs_file_status {
struct afs_fid parent; /* parent dir ID for non-dirs only */
time_t mtime_client; /* last time client changed data */
time_t mtime_server; /* last time server changed data */
+ s32 lock_count; /* file lock count (0=UNLK -1=WRLCK +ve=#RDLCK */
};
/*
diff --git a/fs/afs/afs_fs.h b/fs/afs/afs_fs.h
index a18c374ebe0..eb647323d8f 100644
--- a/fs/afs/afs_fs.h
+++ b/fs/afs/afs_fs.h
@@ -31,6 +31,9 @@ enum AFS_FS_Operations {
FSGETVOLUMEINFO = 148, /* AFS Get information about a volume */
FSGETVOLUMESTATUS = 149, /* AFS Get volume status information */
FSGETROOTVOLUME = 151, /* AFS Get root volume name */
+ FSSETLOCK = 156, /* AFS Request a file lock */
+ FSEXTENDLOCK = 157, /* AFS Extend a file lock */
+ FSRELEASELOCK = 158, /* AFS Release a file lock */
FSLOOKUP = 161, /* AFS lookup file in directory */
FSFETCHDATA64 = 65537, /* AFS Fetch file data */
FSSTOREDATA64 = 65538, /* AFS Store file data */
diff --git a/fs/afs/callback.c b/fs/afs/callback.c
index bacf518c6fa..b8243945818 100644
--- a/fs/afs/callback.c
+++ b/fs/afs/callback.c
@@ -125,6 +125,9 @@ static void afs_break_callback(struct afs_server *server,
spin_unlock(&server->cb_lock);
queue_work(afs_callback_update_worker, &vnode->cb_broken_work);
+ if (list_empty(&vnode->granted_locks) &&
+ !list_empty(&vnode->pending_locks))
+ afs_lock_may_be_available(vnode);
spin_unlock(&vnode->lock);
}
}
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index 546c59522eb..33fe39ad4e0 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -44,6 +44,7 @@ const struct file_operations afs_dir_file_operations = {
.open = afs_dir_open,
.release = afs_release,
.readdir = afs_readdir,
+ .lock = afs_lock,
};
const struct inode_operations afs_dir_inode_operations = {
diff --git a/fs/afs/file.c b/fs/afs/file.c
index aede7eb66dd..525f7c56e06 100644
--- a/fs/afs/file.c
+++ b/fs/afs/file.c
@@ -34,6 +34,8 @@ const struct file_operations afs_file_operations = {
.mmap = generic_file_readonly_mmap,
.splice_read = generic_file_splice_read,
.fsync = afs_fsync,
+ .lock = afs_lock,
+ .flock = afs_flock,
};
const struct inode_operations afs_file_inode_operations = {
diff --git a/fs/afs/flock.c b/fs/afs/flock.c
new file mode 100644
index 00000000000..8f07f8d1bfa
--- /dev/null
+++ b/fs/afs/flock.c
@@ -0,0 +1,558 @@
+/* AFS file locking support
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * 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.
+ */
+
+#include <linux/smp_lock.h>
+#include "internal.h"
+
+#define AFS_LOCK_GRANTED 0
+#define AFS_LOCK_PENDING 1
+
+static void afs_fl_copy_lock(struct file_lock *new, struct file_lock *fl);
+static void afs_fl_release_private(struct file_lock *fl);
+
+static struct workqueue_struct *afs_lock_manager;
+
+static struct file_lock_operations afs_lock_ops = {
+ .fl_copy_lock = afs_fl_copy_lock,
+ .fl_release_private = afs_fl_release_private,
+};
+
+/*
+ * initialise the lock manager thread if it isn't already running
+ */
+static int afs_init_lock_manager(void)
+{
+ if (!afs_lock_manager) {
+ afs_lock_manager = create_singlethread_workqueue("kafs_lockd");
+ if (!afs_lock_manager)
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+/*
+ * destroy the lock manager thread if it's running
+ */
+void __exit afs_kill_lock_manager(void)
+{
+ if (afs_lock_manager)
+ destroy_workqueue(afs_lock_manager);
+}
+
+/*
+ * if the callback is broken on this vnode, then the lock may now be available
+ */
+void afs_lock_may_be_available(struct afs_vnode *vnode)
+{
+ _enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode);
+
+ queue_delayed_work(afs_lock_manager, &vnode->lock_work, 0);
+}
+
+/*
+ * the lock will time out in 5 minutes unless we extend it, so schedule
+ * extension in a bit less than that time
+ */
+static void afs_schedule_lock_extension(struct afs_vnode *vnode)
+{
+ queue_delayed_work(afs_lock_manager, &vnode->lock_work,
+ AFS_LOCKWAIT * HZ / 2);
+}
+
+/*
+ * do work for a lock, including:
+ * - probing for a lock we're waiting on but didn't get immediately
+ * - extending a lock that's close to timing out
+ */
+void afs_lock_work(struct work_struct *work)
+{
+ struct afs_vnode *vnode =
+ container_of(work, struct afs_vnode, lock_work.work);
+ struct file_lock *fl;
+ afs_lock_type_t type;
+ struct key *key;
+ int ret;
+
+ _enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode);
+
+ spin_lock(&vnode->lock);
+
+ if (test_bit(AFS_VNODE_UNLOCKING, &vnode->flags)) {
+ _debug("unlock");
+ spin_unlock(&vnode->lock);
+
+ /* attempt to release the server lock; if it fails, we just
+ * wait 5 minutes and it'll time out anyway */
+ ret = afs_vnode_release_lock(vnode, vnode->unlock_key);
+ if (ret < 0)
+ printk(KERN_WARNING "AFS:"
+ " Failed to release lock on {%x:%x} error %d\n",
+ vnode->fid.vid, vnode->fid.vnode, ret);
+
+ spin_lock(&vnode->lock);
+ key_put(vnode->unlock_key);
+ vnode->unlock_key = NULL;
+ clear_bit(AFS_VNODE_UNLOCKING, &vnode->flags);
+ }
+
+ /* if we've got a lock, then it must be time to extend that lock as AFS
+ * locks time out after 5 minutes */
+ if (!list_empty(&vnode->granted_locks)) {
+ _debug("extend");
+
+ if (test_and_set_bit(AFS_VNODE_LOCKING, &vnode->flags))
+ BUG();
+ fl = list_entry(vnode->granted_locks.next,
+ struct file_lock, fl_u.afs.link);
+ key = key_get(fl->fl_file->private_data);
+ spin_unlock(&vnode->lock);
+
+ ret = afs_vnode_extend_lock(vnode, key);
+ clear_bit(AFS_VNODE_LOCKING, &vnode->flags);
+ key_put(key);
+ switch (ret) {
+ case 0:
+ afs_schedule_lock_extension(vnode);
+ break;
+ default:
+ /* ummm... we failed to extend the lock - retry
+ * extension shortly */
+ printk(KERN_WARNING "AFS:"
+ " Failed to extend lock on {%x:%x} error %d\n",
+ vnode->fid.vid, vnode->fid.vnode, ret);
+ queue_delayed_work(afs_lock_manager, &vnode->lock_work,
+ HZ * 10);
+ break;
+ }
+ _leave(" [extend]");
+ return;
+ }
+
+ /* if we don't have a granted lock, then we must've been called back by
+ * the server, and so if might be possible to get a lock we're
+ * currently waiting for */
+ if (!list_empty(&vnode->pending_locks)) {
+ _debug("get");
+
+ if (test_and_set_bit(AFS_VNODE_LOCKING, &vnode->flags))
+ BUG();
+ fl = list_entry(vnode->pending_locks.next,
+ struct file_lock, fl_u.afs.link);
+ key = key_get(fl->fl_file->private_data);
+ type = (fl->fl_type == F_RDLCK) ?
+ AFS_LOCK_READ : AFS_LOCK_WRITE;
+ spin_unlock(&vnode->lock);
+
+ ret = afs_vnode_set_lock(vnode, key, type);
+ clear_bit(AFS_VNODE_LOCKING, &vnode->flags);
+ switch (ret) {
+ case -EWOULDBLOCK:
+ _debug("blocked");
+ break;
+ case 0:
+ _debug("acquired");
+ if (type == AFS_LOCK_READ)
+ set_bit(AFS_VNODE_READLOCKED, &vnode->flags);
+ else
+ set_bit(AFS_VNODE_WRITELOCKED, &vnode->flags);
+ ret = AFS_LOCK_GRANTED;
+ default:
+ spin_lock(&vnode->lock);
+ /* the pending lock may have been withdrawn due to a
+ * signal */
+ if (list_entry(vnode->pending_locks.next,
+ struct file_lock, fl_u.afs.link) == fl) {
+ fl->fl_u.afs.state = ret;
+ if (ret == AFS_LOCK_GRANTED)
+ list_move_tail(&fl->fl_u.afs.link,
+ &vnode->granted_locks);
+ else
+ list_del_init(&fl->fl_u.afs.link);
+ wake_up(&fl->fl_wait);
+ spin_unlock(&vnode->lock);
+ } else {
+ _debug("withdrawn");
+ clear_bit(AFS_VNODE_READLOCKED, &vnode->flags);
+ clear_bit(AFS_VNODE_WRITELOCKED, &vnode->flags);
+ spin_unlock(&vnode->lock);
+ afs_vnode_release_lock(vnode, key);
+ if (!list_empty(&vnode->pending_locks))
+ afs_lock_may_be_available(vnode);
+ }
+ break;
+ }
+ key_put(key);
+ _leave(" [pend]");
+ return;
+ }
+
+ /* looks like the lock request was withdrawn on a signal */
+ spin_unlock(&vnode->lock);
+ _leave(" [no locks]");
+}
+
+/*
+ * pass responsibility for the unlocking of a vnode on the server to the
+ * manager thread, lest a pending signal in the calling thread interrupt
+ * AF_RXRPC
+ * - the caller must hold the vnode lock
+ */
+static void afs_defer_unlock(struct afs_vnode *vnode, struct key *key)
+{
+ cancel_delayed_work(&vnode->lock_work);
+ if (!test_and_clear_bit(AFS_VNODE_READLOCKED, &vnode->flags) &&
+ !test_and_clear_bit(AFS_VNODE_WRITELOCKED, &vnode->flags))
+ BUG();
+ if (test_and_set_bit(AFS_VNODE_UNLOCKING, &vnode->flags))
+ BUG();
+ vnode->unlock_key = key_get(key);
+ afs_lock_may_be_available(vnode);
+}
+
+/*
+ * request a lock on a file on the server
+ */
+static int afs_do_setlk(struct file *file, struct file_lock *fl)
+{
+ struct afs_vnode *vnode = AFS_FS_I(file->f_mapping->host);
+ afs_lock_type_t type;
+ struct key *key = file->private_data;
+ int ret;
+
+ _enter("{%x:%u},%u", vnode->fid.vid, vnode->fid.vnode, fl->fl_type);
+
+ /* only whole-file locks are supported */
+ if (fl->fl_start != 0 || fl->fl_end != OFFSET_MAX)
+ return -EINVAL;
+
+ ret = afs_init_lock_manager();
+ if (ret < 0)
+ return ret;
+
+ fl->fl_ops = &afs_lock_ops;
+ INIT_LIST_HEAD(&fl->fl_u.afs.link);
+ fl->fl_u.afs.state = AFS_LOCK_PENDING;
+
+ type = (fl->fl_type == F_RDLCK) ? AFS_LOCK_READ : AFS_LOCK_WRITE;
+
+ lock_kernel();
+
+ /* make sure we've got a callback on this file and that our view of the
+ * data version is up to date */
+ ret = afs_vnode_fetch_status(vnode, NULL, key);
+ if (ret < 0)
+ goto error;
+
+ if (vnode->status.lock_count != 0 && !(fl->fl_flags & FL_SLEEP)) {
+ ret = -EAGAIN;
+ goto error;
+ }
+
+ spin_lock(&vnode->lock);
+
+ if (list_empty(&vnode->pending_locks)) {
+ /* if there's no-one else with a lock on this vnode, then we
+ * need to ask the server for a lock */
+ if (list_empty(&vnode->granted_locks)) {
+ _debug("not locked");
+ ASSERTCMP(vnode->flags &
+ ((1 << AFS_VNODE_LOCKING) |
+ (1 << AFS_VNODE_READLOCKED) |
+ (1 << AFS_VNODE_WRITELOCKED)), ==, 0);
+ list_add_tail(&fl->fl_u.afs.link, &vnode->pending_locks);
+ set_bit(AFS_VNODE_LOCKING, &vnode->flags);
+ spin_unlock(&vnode->lock);
+
+ ret = afs_vnode_set_lock(vnode, key, type);
+ clear_bit(AFS_VNODE_LOCKING, &vnode->flags);
+ switch (ret) {
+ case 0:
+ goto acquired_server_lock;
+ case -EWOULDBLOCK:
+ spin_lock(&vnode->lock);
+ ASSERT(list_empty(&vnode->granted_locks));
+ ASSERTCMP(vnode->pending_locks.next, ==,
+ &fl->fl_u.afs.link);
+ goto wait;
+ default:
+ spin_lock(&vnode->lock);
+ list_del_init(&fl->fl_u.afs.link);
+ spin_unlock(&vnode->lock);
+ goto error;
+ }
+ }
+
+ /* if we've already got a readlock on the server and no waiting
+ * writelocks, then we might be able to instantly grant another
+ * readlock */
+ if (type == AFS_LOCK_READ &&
+ vnode->flags & (1 << AFS_VNODE_READLOCKED)) {
+ _debug("instant readlock");
+ ASSERTCMP(vnode->flags &
+ ((1 << AFS_VNODE_LOCKING) |
+ (1 << AFS_VNODE_WRITELOCKED)), ==, 0);
+ ASSERT(!list_empty(&vnode->granted_locks));
+ goto sharing_existing_lock;
+ }
+ }
+
+ /* otherwise, we need to wait for a local lock to become available */
+ _debug("wait local");
+ list_add_tail(&fl->fl_u.afs.link, &vnode->pending_locks);
+wait:
+ if (!(fl->fl_flags & FL_SLEEP)) {
+ _debug("noblock");
+ ret = -EAGAIN;
+ goto abort_attempt;
+ }
+ spin_unlock(&vnode->lock);
+
+ /* now we need to sleep and wait for the lock manager thread to get the
+ * lock from the server */
+ _debug("sleep");
+ ret = wait_event_interruptible(fl->fl_wait,
+ fl->fl_u.afs.state <= AFS_LOCK_GRANTED);
+ if (fl->fl_u.afs.state <= AFS_LOCK_GRANTED) {
+ ret = fl->fl_u.afs.state;
+ if (ret < 0)
+ goto error;
+ spin_lock(&vnode->lock);
+ goto given_lock;
+ }
+
+ /* we were interrupted, but someone may still be in the throes of
+ * giving us the lock */
+ _debug("intr");
+ ASSERTCMP(ret, ==, -ERESTARTSYS);
+
+ spin_lock(&vnode->lock);
+ if (fl->fl_u.afs.state <= AFS_LOCK_GRANTED) {
+ ret = fl->fl_u.afs.state;
+ if (ret < 0) {
+ spin_unlock(&vnode->lock);
+ goto error;
+ }
+ goto given_lock;
+ }
+
+abort_attempt:
+ /* we aren't going to get the lock, either because we're unwilling to
+ * wait, or because some signal happened */
+ _debug("abort");
+ if (list_empty(&vnode->granted_locks) &&
+ vnode->pending_locks.next == &fl->fl_u.afs.link) {
+ if (vnode->pending_locks.prev != &fl->fl_u.afs.link) {
+ /* kick the next pending lock into having a go */
+ list_del_init(&fl->fl_u.afs.link);
+ afs_lock_may_be_available(vnode);
+ }
+ } else {
+ list_del_init(&fl->fl_u.afs.link);
+ }
+ spin_unlock(&vnode->lock);
+ goto error;
+
+acquired_server_lock:
+ /* we've acquired a server lock, but it needs to be renewed after 5
+ * mins */
+ spin_lock(&vnode->lock);
+ afs_schedule_lock_extension(vnode);
+ if (type == AFS_LOCK_READ)
+ set_bit(AFS_VNODE_READLOCKED, &vnode->flags);
+ else
+ set_bit(AFS_VNODE_WRITELOCKED, &vnode->flags);
+sharing_existing_lock:
+ /* the lock has been granted as far as we're concerned... */
+ fl->fl_u.afs.state = AFS_LOCK_GRANTED;
+ list_move_tail(&fl->fl_u.afs.link, &vnode->granted_locks);
+given_lock:
+ /* ... but we do still need to get the VFS's blessing */
+ ASSERT(!(vnode->flags & (1 << AFS_VNODE_LOCKING)));
+ ASSERT((vnode->flags & ((1 << AFS_VNODE_READLOCKED) |
+ (1 << AFS_VNODE_WRITELOCKED))) != 0);
+ ret = posix_lock_file(file, fl, NULL);
+ if (ret < 0)
+ goto vfs_rejected_lock;
+ spin_unlock(&vnode->lock);
+
+ /* again, make sure we've got a callback on this file and, again, make
+ * sure that our view of the data version is up to date (we ignore
+ * errors incurred here and deal with the consequences elsewhere) */
+ afs_vnode_fetch_status(vnode, NULL, key);
+
+error:
+ unlock_kernel();
+ _leave(" = %d", ret);
+ return ret;
+
+vfs_rejected_lock:
+ /* the VFS rejected the lock we just obtained, so we have to discard
+ * what we just got */
+ _debug("vfs refused %d", ret);
+ list_del_init(&fl->fl_u.afs.link);
+ if (list_empty(&vnode->granted_locks))
+ afs_defer_unlock(vnode, key);
+ spin_unlock(&vnode->lock);
+ goto abort_attempt;
+}
+
+/*
+ * unlock on a file on the server
+ */
+static int afs_do_unlk(struct file *file, struct file_lock *fl)
+{
+ struct afs_vnode *vnode = AFS_FS_I(file->f_mapping->host);
+ struct key *key = file->private_data;
+ int ret;
+
+ _enter("{%x:%u},%u", vnode->fid.vid, vnode->fid.vnode, fl->fl_type);
+
+ /* only whole-file unlocks are supported */
+ if (fl->fl_start != 0 || fl->fl_end != OFFSET_MAX)
+ return -EINVAL;
+
+ fl->fl_ops = &afs_lock_ops;
+ INIT_LIST_HEAD(&fl->fl_u.afs.link);
+ fl->fl_u.afs.state = AFS_LOCK_PENDING;
+
+ spin_lock(&vnode->lock);
+ ret = posix_lock_file(file, fl, NULL);
+ if (ret < 0) {
+ spin_unlock(&vnode->lock);
+ _leave(" = %d [vfs]", ret);
+ return ret;
+ }
+
+ /* discard the server lock only if all granted locks are gone */
+ if (list_empty(&vnode->granted_locks))
+ afs_defer_unlock(vnode, key);
+ spin_unlock(&vnode->lock);
+ _leave(" = 0");
+ return 0;
+}
+
+/*
+ * return information about a lock we currently hold, if indeed we hold one
+ */
+static int afs_do_getlk(struct file *file, struct file_lock *fl)
+{
+ struct afs_vnode *vnode = AFS_FS_I(file->f_mapping->host);
+ struct key *key = file->private_data;
+ int ret, lock_count;
+
+ _enter("");
+
+ fl->fl_type = F_UNLCK;
+
+ mutex_lock(&vnode->vfs_inode.i_mutex);
+
+ /* check local lock records first */
+ ret = 0;
+ if (posix_test_lock(file, fl) == 0) {
+ /* no local locks; consult the server */
+ ret = afs_vnode_fetch_status(vnode, NULL, key);
+ if (ret < 0)
+ goto error;
+ lock_count = vnode->status.lock_count;
+ if (lock_count) {
+ if (lock_count > 0)
+ fl->fl_type = F_RDLCK;
+ else
+ fl->fl_type = F_WRLCK;
+ fl->fl_start = 0;
+ fl->fl_end = OFFSET_MAX;
+ }
+ }
+
+error:
+ mutex_unlock(&vnode->vfs_inode.i_mutex);
+ _leave(" = %d [%hd]", ret, fl->fl_type);
+ return ret;
+}
+
+/*
+ * manage POSIX locks on a file
+ */
+int afs_lock(struct file *file, int cmd, struct file_lock *fl)
+{
+ struct afs_vnode *vnode = AFS_FS_I(file->f_dentry->d_inode);
+
+ _enter("{%x:%u},%d,{t=%x,fl=%x,r=%Ld:%Ld}",
+ vnode->fid.vid, vnode->fid.vnode, cmd,
+ fl->fl_type, fl->fl_flags,
+ (long long) fl->fl_start, (long long) fl->fl_end);
+
+ /* AFS doesn't support mandatory locks */
+ if ((vnode->vfs_inode.i_mode & (S_ISGID | S_IXGRP)) == S_ISGID &&
+ fl->fl_type != F_UNLCK)
+ return -ENOLCK;
+
+ if (IS_GETLK(cmd))
+ return afs_do_getlk(file, fl);
+ if (fl->fl_type == F_UNLCK)
+ return afs_do_unlk(file, fl);
+ return afs_do_setlk(file, fl);
+}
+
+/*
+ * manage FLOCK locks on a file
+ */
+int afs_flock(struct file *file, int cmd, struct file_lock *fl)
+{
+ struct afs_vnode *vnode = AFS_FS_I(file->f_dentry->d_inode);
+
+ _enter("{%x:%u},%d,{t=%x,fl=%x}",
+ vnode->fid.vid, vnode->fid.vnode, cmd,
+ fl->fl_type, fl->fl_flags);
+
+ /*
+ * No BSD flocks over NFS allowed.
+ * Note: we could try to fake a POSIX lock request here by
+ * using ((u32) filp | 0x80000000) or some such as the pid.
+ * Not sure whether that would be unique, though, or whether
+ * that would break in other places.
+ */
+ if (!(fl->fl_flags & FL_FLOCK))
+ return -ENOLCK;
+
+ /* we're simulating flock() locks using posix locks on the server */
+ fl->fl_owner = (fl_owner_t) file;
+ fl->fl_start = 0;
+ fl->fl_end = OFFSET_MAX;
+
+ if (fl->fl_type == F_UNLCK)
+ return afs_do_unlk(file, fl);
+ return afs_do_setlk(file, fl);
+}
+
+/*
+ * the POSIX lock management core VFS code copies the lock record and adds the
+ * copy into its own list, so we need to add that copy to the vnode's lock
+ * queue in the same place as the original (which will be deleted shortly
+ * after)
+ */
+static void afs_fl_copy_lock(struct file_lock *new, struct file_lock *fl)
+{
+ _enter("");
+
+ list_add(&new->fl_u.afs.link, &fl->fl_u.afs.link);
+}
+
+/*
+ * need to remove this lock from the vnode queue when it's removed from the
+ * VFS's list
+ */
+static void afs_fl_release_private(struct file_lock *fl)
+{
+ _enter("");
+
+ list_del_init(&fl->fl_u.afs.link);
+}
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index 5dff1308b6f..023b95b0d9d 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -67,7 +67,7 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
EXTRACT(status->group);
bp++; /* sync counter */
data_version |= (u64) ntohl(*bp++) << 32;
- bp++; /* lock count */
+ EXTRACT(status->lock_count);
size |= (u64) ntohl(*bp++) << 32;
bp++; /* spare 4 */
*_bp = bp;
@@ -1748,3 +1748,156 @@ int afs_fs_get_volume_status(struct afs_server *server,
return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
}
+
+/*
+ * deliver reply data to an FS.SetLock, FS.ExtendLock or FS.ReleaseLock
+ */
+static int afs_deliver_fs_xxxx_lock(struct afs_call *call,
+ struct sk_buff *skb, bool last)
+{
+ const __be32 *bp;
+
+ _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
+
+ afs_transfer_reply(call, skb);
+ if (!last)
+ return 0;
+
+ if (call->reply_size != call->reply_max)
+ return -EBADMSG;
+
+ /* unmarshall the reply once we've received all of it */
+ bp = call->buffer;
+ /* xdr_decode_AFSVolSync(&bp, call->replyX); */
+
+ _leave(" = 0 [done]");
+ return 0;
+}
+
+/*
+ * FS.SetLock operation type
+ */
+static const struct afs_call_type afs_RXFSSetLock = {
+ .name = "FS.SetLock",
+ .deliver = afs_deliver_fs_xxxx_lock,
+ .abort_to_error = afs_abort_to_error,
+ .destructor = afs_flat_call_destructor,
+};
+
+/*
+ * FS.ExtendLock operation type
+ */
+static const struct afs_call_type afs_RXFSExtendLock = {
+ .name = "FS.ExtendLock",
+ .deliver = afs_deliver_fs_xxxx_lock,
+ .abort_to_error = afs_abort_to_error,
+ .destructor = afs_flat_call_destructor,
+};
+
+/*
+ * FS.ReleaseLock operation type
+ */
+static const struct afs_call_type afs_RXFSReleaseLock = {
+ .name = "FS.ReleaseLock",
+ .deliver = afs_deliver_fs_xxxx_lock,
+ .abort_to_error = afs_abort_to_error,
+ .destructor = afs_flat_call_destructor,
+};
+
+/*
+ * get a lock on a file
+ */
+int afs_fs_set_lock(struct afs_server *server,
+ struct key *key,
+ struct afs_vnode *vnode,
+ afs_lock_type_t type,
+ const struct afs_wait_mode *wait_mode)
+{
+ struct afs_call *call;
+ __be32 *bp;
+
+ _enter("");
+
+ call = afs_alloc_flat_call(&afs_RXFSSetLock, 5 * 4, 6 * 4);
+ if (!call)
+ return -ENOMEM;
+
+ call->key = key;
+ call->reply = vnode;
+ call->service_id = FS_SERVICE;
+ call->port = htons(AFS_FS_PORT);
+
+ /* marshall the parameters */
+ bp = call->request;
+ *bp++ = htonl(FSSETLOCK);
+ *bp++ = htonl(vnode->fid.vid);
+ *bp++ = htonl(vnode->fid.vnode);
+ *bp++ = htonl(vnode->fid.unique);
+ *bp++ = htonl(type);
+
+ return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
+
+/*
+ * extend a lock on a file
+ */
+int afs_fs_extend_lock(struct afs_server *server,
+ struct key *key,
+ struct afs_vnode *vnode,
+ const struct afs_wait_mode *wait_mode)
+{
+ struct afs_call *call;
+ __be32 *bp;
+
+ _enter("");
+
+ call = afs_alloc_flat_call(&afs_RXFSExtendLock, 4 * 4, 6 * 4);
+ if (!call)
+ return -ENOMEM;
+
+ call->key = key;
+ call->reply = vnode;
+ call->service_id = FS_SERVICE;
+ call->port = htons(AFS_FS_PORT);
+
+ /* marshall the parameters */
+ bp = call->request;
+ *bp++ = htonl(FSEXTENDLOCK);
+ *bp++ = htonl(vnode->fid.vid);
+ *bp++ = htonl(vnode->fid.vnode);
+ *bp++ = htonl(vnode->fid.unique);
+
+ return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
+
+/*
+ * release a lock on a file
+ */
+int afs_fs_release_lock(struct afs_server *server,
+ struct key *key,
+ struct afs_vnode *vnode,
+ const struct afs_wait_mode *wait_mode)
+{
+ struct afs_call *call;
+ __be32 *bp;
+
+ _enter("");
+
+ call = afs_alloc_flat_call(&afs_RXFSReleaseLock, 4 * 4, 6 * 4);
+ if (!call)
+ return -ENOMEM;
+
+ call->key = key;
+ call->reply = vnode;
+ call->service_id = FS_SERVICE;
+ call->port = htons(AFS_FS_PORT);
+
+ /* marshall the parameters */
+ bp = call->request;
+ *bp++ = htonl(FSRELEASELOCK);
+ *bp++ = htonl(vnode->fid.vid);
+ *bp++ = htonl(vnode->fid.vnode);
+ *bp++ = htonl(vnode->fid.unique);
+
+ return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 2c55dd94a1d..6306438f331 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -351,10 +351,18 @@ struct afs_vnode {
#define AFS_VNODE_ZAP_DATA 3 /* set if vnode's data should be invalidated */
#define AFS_VNODE_DELETED 4 /* set if vnode deleted on server */
#define AFS_VNODE_MOUNTPOINT 5 /* set if vnode is a mountpoint symlink */
+#define AFS_VNODE_LOCKING 6 /* set if waiting for lock on vnode */
+#define AFS_VNODE_READLOCKED 7 /* set if vnode is read-locked on the server */
+#define AFS_VNODE_WRITELOCKED 8 /* set if vnode is write-locked on the server */
+#define AFS_VNODE_UNLOCKING 9 /* set if vnode is being unlocked on the server */
long acl_order; /* ACL check count (callback break count) */
struct list_head writebacks; /* alterations in pagecache that need writing */
+ struct list_head pending_locks; /* locks waiting to be granted */
+ struct list_head granted_locks; /* locks granted on this file */
+ struct delayed_work lock_work; /* work to be done in locking */
+ struct key *unlock_key; /* key to be used in unlocking */
/* outstanding callback notification on this file */
struct rb_node server_rb; /* link in server->fs_vnodes */
@@ -474,6 +482,15 @@ extern int afs_open(struct inode *, struct file *);
extern int afs_release(struct inode *, struct file *);
/*
+ * flock.c
+ */
+extern void __exit afs_kill_lock_manager(void);
+extern void afs_lock_work(struct work_struct *);
+extern void afs_lock_may_be_available(struct afs_vnode *);
+extern int afs_lock(struct file *, int, struct file_lock *);
+extern int afs_flock(struct file *, int, struct file_lock *);
+
+/*
* fsclient.c
*/
extern int afs_fs_fetch_file_status(struct afs_server *, struct key *,
@@ -513,6 +530,15 @@ extern int afs_fs_get_volume_status(struct afs_server *, struct key *,
struct afs_vnode *,
struct afs_volume_status *,
const struct afs_wait_mode *);
+extern int afs_fs_set_lock(struct afs_server *, struct key *,
+ struct afs_vnode *, afs_lock_type_t,
+ const struct afs_wait_mode *);
+extern int afs_fs_extend_lock(struct afs_server *, struct key *,
+ struct afs_vnode *,
+ const struct afs_wait_mode *);
+extern int afs_fs_release_lock(struct afs_server *, struct key *,
+ struct afs_vnode *,
+ const struct afs_wait_mode *);
/*
* inode.c
@@ -681,6 +707,10 @@ extern int afs_vnode_store_data(struct afs_writeback *, pgoff_t, pgoff_t,
extern int afs_vnode_setattr(struct afs_vnode *, struct key *, struct iattr *);
extern int afs_vnode_get_volume_status(struct afs_vnode *, struct key *,
struct afs_volume_status *);
+extern int afs_vnode_set_lock(struct afs_vnode *, struct key *,
+ afs_lock_type_t);
+extern int afs_vnode_extend_lock(struct afs_vnode *, struct key *);
+extern int afs_vnode_release_lock(struct afs_vnode *, struct key *);
/*
* volume.c
diff --git a/fs/afs/main.c b/fs/afs/main.c
index cd21195bbb2..0f60f6b3576 100644
--- a/fs/afs/main.c
+++ b/fs/afs/main.c
@@ -168,6 +168,7 @@ static void __exit afs_exit(void)
printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 unregistering.\n");
afs_fs_exit();
+ afs_kill_lock_manager();
afs_close_socket();
afs_purge_servers();
afs_callback_update_kill();
diff --git a/fs/afs/misc.c b/fs/afs/misc.c
index d1a889c4074..2d33a5f7d21 100644
--- a/fs/afs/misc.c
+++ b/fs/afs/misc.c
@@ -35,6 +35,7 @@ int afs_abort_to_error(u32 abort_code)
case VOVERQUOTA: return -EDQUOT;
case VBUSY: return -EBUSY;
case VMOVED: return -ENXIO;
+ case 0x2f6df0a: return -EWOULDBLOCK;
case 0x2f6df0c: return -EACCES;
case 0x2f6df0f: return -EBUSY;
case 0x2f6df10: return -EEXIST;
diff --git a/fs/afs/proc.c b/fs/afs/proc.c
index 13df512aea9..6edb56683b9 100644
--- a/fs/afs/proc.c
+++ b/fs/afs/proc.c
@@ -201,23 +201,9 @@ static int afs_proc_cells_open(struct inode *inode, struct file *file)
*/
static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos)
{
- struct list_head *_p;
- loff_t pos = *_pos;
-
/* lock the list against modification */
down_read(&afs_proc_cells_sem);
-
- /* allow for the header line */
- if (!pos)
- return (void *) 1;
- pos--;
-
- /* find the n'th element in the list */
- list_for_each(_p, &afs_proc_cells)
- if (!pos--)
- break;
-
- return _p != &afs_proc_cells ? _p : NULL;
+ return seq_list_start_head(&afs_proc_cells, *_pos);
}
/*
@@ -225,14 +211,7 @@ static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos)
*/
static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos)
{
- struct list_head *_p;
-
- (*pos)++;
-
- _p = v;
- _p = v == (void *) 1 ? afs_proc_cells.next : _p->next;
-
- return _p != &afs_proc_cells ? _p : NULL;
+ return seq_list_next(v, &afs_proc_cells, pos);
}
/*
@@ -250,7 +229,7 @@ static int afs_proc_cells_show(struct seq_file *m, void *v)
{
struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link);
- if (v == (void *) 1) {
+ if (v == &afs_proc_cells) {
/* display header on line 1 */
seq_puts(m, "USE NAME\n");
return 0;
@@ -503,26 +482,13 @@ static int afs_proc_cell_volumes_release(struct inode *inode, struct file *file)
*/
static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos)
{
- struct list_head *_p;
struct afs_cell *cell = m->private;
- loff_t pos = *_pos;
_enter("cell=%p pos=%Ld", cell, *_pos);
/* lock the list against modification */
down_read(&cell->vl_sem);
-
- /* allow for the header line */
- if (!pos)
- return (void *) 1;
- pos--;
-
- /* find the n'th element in the list */
- list_for_each(_p, &cell->vl_list)
- if (!pos--)
- break;
-
- return _p != &cell->vl_list ? _p : NULL;
+ return seq_list_start_head(&cell->vl_list, *_pos);
}
/*
@@ -531,17 +497,10 @@ static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos)
static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v,
loff_t *_pos)
{
- struct list_head *_p;
struct afs_cell *cell = p->private;
_enter("cell=%p pos=%Ld", cell, *_pos);
-
- (*_pos)++;
-
- _p = v;
- _p = (v == (void *) 1) ? cell->vl_list.next : _p->next;
-
- return (_p != &cell->vl_list) ? _p : NULL;
+ return seq_list_next(v, &cell->vl_list, _pos);
}
/*
@@ -569,11 +528,12 @@ const char afs_vlocation_states[][4] = {
*/
static int afs_proc_cell_volumes_show(struct seq_file *m, void *v)
{
+ struct afs_cell *cell = m->private;
struct afs_vlocation *vlocation =
list_entry(v, struct afs_vlocation, link);
/* display header on line 1 */
- if (v == (void *) 1) {
+ if (v == &cell->vl_list) {
seq_puts(m, "USE STT VLID[0] VLID[1] VLID[2] NAME\n");
return 0;
}
@@ -734,26 +694,13 @@ static int afs_proc_cell_servers_release(struct inode *inode,
static void *afs_proc_cell_servers_start(struct seq_file *m, loff_t *_pos)
__acquires(m->private->servers_lock)
{
- struct list_head *_p;
struct afs_cell *cell = m->private;
- loff_t pos = *_pos;
_enter("cell=%p pos=%Ld", cell, *_pos);
/* lock the list against modification */
read_lock(&cell->servers_lock);
-
- /* allow for the header line */
- if (!pos)
- return (void *) 1;
- pos--;
-
- /* find the n'th element in the list */
- list_for_each(_p, &cell->servers)
- if (!pos--)
- break;
-
- return _p != &cell->servers ? _p : NULL;
+ return seq_list_start_head(&cell->servers, *_pos);
}
/*
@@ -762,17 +709,10 @@ static void *afs_proc_cell_servers_start(struct seq_file *m, loff_t *_pos)
static void *afs_proc_cell_servers_next(struct seq_file *p, void *v,
loff_t *_pos)
{
- struct list_head *_p;
struct afs_cell *cell = p->private;
_enter("cell=%p pos=%Ld", cell, *_pos);
-
- (*_pos)++;
-
- _p = v;
- _p = v == (void *) 1 ? cell->servers.next : _p->next;
-
- return _p != &cell->servers ? _p : NULL;
+ return seq_list_next(v, &cell->servers, _pos);
}
/*
@@ -791,11 +731,12 @@ static void afs_proc_cell_servers_stop(struct seq_file *p, void *v)
*/
static int afs_proc_cell_servers_show(struct seq_file *m, void *v)
{
+ struct afs_cell *cell = m->private;
struct afs_server *server = list_entry(v, struct afs_server, link);
char ipaddr[20];
/* display header on line 1 */
- if (v == (void *) 1) {
+ if (v == &cell->servers) {
seq_puts(m, "USE ADDR STATE\n");
return 0;
}
diff --git a/fs/afs/super.c b/fs/afs/super.c
index 2e8496ba120..993cdf1cce3 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -460,6 +460,9 @@ static void afs_i_init_once(void *_vnode, struct kmem_cache *cachep,
spin_lock_init(&vnode->writeback_lock);
spin_lock_init(&vnode->lock);
INIT_LIST_HEAD(&vnode->writebacks);
+ INIT_LIST_HEAD(&vnode->pending_locks);
+ INIT_LIST_HEAD(&vnode->granted_locks);
+ INIT_DELAYED_WORK(&vnode->lock_work, afs_lock_work);
INIT_WORK(&vnode->cb_broken_work, afs_broken_callback_work);
}
diff --git a/fs/afs/vnode.c b/fs/afs/vnode.c
index 232c55dc245..2f05c4fc2a7 100644
--- a/fs/afs/vnode.c
+++ b/fs/afs/vnode.c
@@ -561,7 +561,7 @@ no_server:
/*
* create a hard link
*/
-extern int afs_vnode_link(struct afs_vnode *dvnode, struct afs_vnode *vnode,
+int afs_vnode_link(struct afs_vnode *dvnode, struct afs_vnode *vnode,
struct key *key, const char *name)
{
struct afs_server *server;
@@ -887,11 +887,6 @@ int afs_vnode_get_volume_status(struct afs_vnode *vnode, struct key *key,
vnode->fid.unique,
key_serial(key));
- /* this op will fetch the status */
- spin_lock(&vnode->lock);
- vnode->update_cnt++;
- spin_unlock(&vnode->lock);
-
do {
/* pick a server to query */
server = afs_volume_pick_fileserver(vnode);
@@ -905,20 +900,127 @@ int afs_vnode_get_volume_status(struct afs_vnode *vnode, struct key *key,
} while (!afs_volume_release_fileserver(vnode, server, ret));
/* adjust the flags */
- if (ret == 0) {
- afs_vnode_finalise_status_update(vnode, server);
+ if (ret == 0)
+ afs_put_server(server);
+
+ _leave(" = %d", ret);
+ return ret;
+
+no_server:
+ return PTR_ERR(server);
+}
+
+/*
+ * get a lock on a file
+ */
+int afs_vnode_set_lock(struct afs_vnode *vnode, struct key *key,
+ afs_lock_type_t type)
+{
+ struct afs_server *server;
+ int ret;
+
+ _enter("%s{%x:%u.%u},%x,%u",
+ vnode->volume->vlocation->vldb.name,
+ vnode->fid.vid,
+ vnode->fid.vnode,
+ vnode->fid.unique,
+ key_serial(key), type);
+
+ do {
+ /* pick a server to query */
+ server = afs_volume_pick_fileserver(vnode);
+ if (IS_ERR(server))
+ goto no_server;
+
+ _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
+
+ ret = afs_fs_set_lock(server, key, vnode, type, &afs_sync_call);
+
+ } while (!afs_volume_release_fileserver(vnode, server, ret));
+
+ /* adjust the flags */
+ if (ret == 0)
+ afs_put_server(server);
+
+ _leave(" = %d", ret);
+ return ret;
+
+no_server:
+ return PTR_ERR(server);
+}
+
+/*
+ * extend a lock on a file
+ */
+int afs_vnode_extend_lock(struct afs_vnode *vnode, struct key *key)
+{
+ struct afs_server *server;
+ int ret;
+
+ _enter("%s{%x:%u.%u},%x",
+ vnode->volume->vlocation->vldb.name,
+ vnode->fid.vid,
+ vnode->fid.vnode,
+ vnode->fid.unique,
+ key_serial(key));
+
+ do {
+ /* pick a server to query */
+ server = afs_volume_pick_fileserver(vnode);
+ if (IS_ERR(server))
+ goto no_server;
+
+ _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
+
+ ret = afs_fs_extend_lock(server, key, vnode, &afs_sync_call);
+
+ } while (!afs_volume_release_fileserver(vnode, server, ret));
+
+ /* adjust the flags */
+ if (ret == 0)
+ afs_put_server(server);
+
+ _leave(" = %d", ret);
+ return ret;
+
+no_server:
+ return PTR_ERR(server);
+}
+
+/*
+ * release a lock on a file
+ */
+int afs_vnode_release_lock(struct afs_vnode *vnode, struct key *key)
+{
+ struct afs_server *server;
+ int ret;
+
+ _enter("%s{%x:%u.%u},%x",
+ vnode->volume->vlocation->vldb.name,
+ vnode->fid.vid,
+ vnode->fid.vnode,
+ vnode->fid.unique,
+ key_serial(key));
+
+ do {
+ /* pick a server to query */
+ server = afs_volume_pick_fileserver(vnode);
+ if (IS_ERR(server))
+ goto no_server;
+
+ _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
+
+ ret = afs_fs_release_lock(server, key, vnode, &afs_sync_call);
+
+ } while (!afs_volume_release_fileserver(vnode, server, ret));
+
+ /* adjust the flags */
+ if (ret == 0)
afs_put_server(server);
- } else {
- afs_vnode_status_update_failed(vnode, ret);
- }
_leave(" = %d", ret);
return ret;
no_server:
- spin_lock(&vnode->lock);
- vnode->update_cnt--;
- ASSERTCMP(vnode->update_cnt, >=, 0);
- spin_unlock(&vnode->lock);
return PTR_ERR(server);
}
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
index 40fe3a3222e..a260198306c 100644
--- a/fs/anon_inodes.c
+++ b/fs/anon_inodes.c
@@ -53,7 +53,7 @@ static struct dentry_operations anon_inodefs_dentry_operations = {
};
/**
- * anon_inode_getfd - creates a new file instance by hooking it up to and
+ * anon_inode_getfd - creates a new file instance by hooking it up to an
* anonymous inode, and a dentry that describe the "class"
* of the file
*
@@ -66,7 +66,7 @@ static struct dentry_operations anon_inodefs_dentry_operations = {
*
* Creates a new file by hooking it on a single inode. This is useful for files
* that do not need to have a full-fledged inode in order to operate correctly.
- * All the files created with anon_inode_getfd() will share a single inode, by
+ * All the files created with anon_inode_getfd() will share a single inode,
* hence saving memory and avoiding code duplication for the file/inode/dentry
* setup.
*/
@@ -141,9 +141,9 @@ err_put_filp:
}
/*
- * A single inode exist for all anon_inode files. Contrary to pipes,
- * anon_inode inodes has no per-instance data associated, so we can avoid
- * the allocation of multiple of them.
+ * A single inode exists for all anon_inode files. Contrary to pipes,
+ * anon_inode inodes have no associated per-instance data, so we need
+ * only allocate one of them.
*/
static struct inode *anon_inode_mkinode(void)
{
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 08e4414b837..a27e42bf340 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -45,7 +45,7 @@
static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs);
static int load_elf_library(struct file *);
-static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int);
+static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int, unsigned long);
/*
* If we don't support core dumping, then supply a NULL so we
@@ -80,7 +80,7 @@ static struct linux_binfmt elf_format = {
.hasvdso = 1
};
-#define BAD_ADDR(x) ((unsigned long)(x) >= TASK_SIZE)
+#define BAD_ADDR(x) IS_ERR_VALUE(x)
static int set_brk(unsigned long start, unsigned long end)
{
@@ -285,33 +285,70 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
#ifndef elf_map
static unsigned long elf_map(struct file *filep, unsigned long addr,
- struct elf_phdr *eppnt, int prot, int type)
+ struct elf_phdr *eppnt, int prot, int type,
+ unsigned long total_size)
{
unsigned long map_addr;
- unsigned long pageoffset = ELF_PAGEOFFSET(eppnt->p_vaddr);
+ unsigned long size = eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr);
+ unsigned long off = eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr);
+ addr = ELF_PAGESTART(addr);
+ size = ELF_PAGEALIGN(size);
- down_write(&current->mm->mmap_sem);
/* mmap() will return -EINVAL if given a zero size, but a
* segment with zero filesize is perfectly valid */
- if (eppnt->p_filesz + pageoffset)
- map_addr = do_mmap(filep, ELF_PAGESTART(addr),
- eppnt->p_filesz + pageoffset, prot, type,
- eppnt->p_offset - pageoffset);
- else
- map_addr = ELF_PAGESTART(addr);
+ if (!size)
+ return addr;
+
+ down_write(&current->mm->mmap_sem);
+ /*
+ * total_size is the size of the ELF (interpreter) image.
+ * The _first_ mmap needs to know the full size, otherwise
+ * randomization might put this image into an overlapping
+ * position with the ELF binary image. (since size < total_size)
+ * So we first map the 'big' image - and unmap the remainder at
+ * the end. (which unmap is needed for ELF images with holes.)
+ */
+ if (total_size) {
+ total_size = ELF_PAGEALIGN(total_size);
+ map_addr = do_mmap(filep, addr, total_size, prot, type, off);
+ if (!BAD_ADDR(map_addr))
+ do_munmap(current->mm, map_addr+size, total_size-size);
+ } else
+ map_addr = do_mmap(filep, addr, size, prot, type, off);
+
up_write(&current->mm->mmap_sem);
return(map_addr);
}
#endif /* !elf_map */
+static unsigned long total_mapping_size(struct elf_phdr *cmds, int nr)
+{
+ int i, first_idx = -1, last_idx = -1;
+
+ for (i = 0; i < nr; i++) {
+ if (cmds[i].p_type == PT_LOAD) {
+ last_idx = i;
+ if (first_idx == -1)
+ first_idx = i;
+ }
+ }
+ if (first_idx == -1)
+ return 0;
+
+ return cmds[last_idx].p_vaddr + cmds[last_idx].p_memsz -
+ ELF_PAGESTART(cmds[first_idx].p_vaddr);
+}
+
+
/* This is much more generalized than the library routine read function,
so we keep this separate. Technically the library read function
is only provided so that we can read a.out libraries that have
an ELF header */
static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
- struct file *interpreter, unsigned long *interp_load_addr)
+ struct file *interpreter, unsigned long *interp_map_addr,
+ unsigned long no_base)
{
struct elf_phdr *elf_phdata;
struct elf_phdr *eppnt;
@@ -319,6 +356,7 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
int load_addr_set = 0;
unsigned long last_bss = 0, elf_bss = 0;
unsigned long error = ~0UL;
+ unsigned long total_size;
int retval, i, size;
/* First of all, some simple consistency checks */
@@ -357,6 +395,12 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
goto out_close;
}
+ total_size = total_mapping_size(elf_phdata, interp_elf_ex->e_phnum);
+ if (!total_size) {
+ error = -EINVAL;
+ goto out_close;
+ }
+
eppnt = elf_phdata;
for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) {
if (eppnt->p_type == PT_LOAD) {
@@ -374,9 +418,14 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
vaddr = eppnt->p_vaddr;
if (interp_elf_ex->e_type == ET_EXEC || load_addr_set)
elf_type |= MAP_FIXED;
+ else if (no_base && interp_elf_ex->e_type == ET_DYN)
+ load_addr = -vaddr;
map_addr = elf_map(interpreter, load_addr + vaddr,
- eppnt, elf_prot, elf_type);
+ eppnt, elf_prot, elf_type, total_size);
+ total_size = 0;
+ if (!*interp_map_addr)
+ *interp_map_addr = map_addr;
error = map_addr;
if (BAD_ADDR(map_addr))
goto out_close;
@@ -442,8 +491,7 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
goto out_close;
}
- *interp_load_addr = load_addr;
- error = ((unsigned long)interp_elf_ex->e_entry) + load_addr;
+ error = load_addr;
out_close:
kfree(elf_phdata);
@@ -540,7 +588,8 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
int elf_exec_fileno;
int retval, i;
unsigned int size;
- unsigned long elf_entry, interp_load_addr = 0;
+ unsigned long elf_entry;
+ unsigned long interp_load_addr = 0;
unsigned long start_code, end_code, start_data, end_data;
unsigned long reloc_func_desc = 0;
char passed_fileno[6];
@@ -808,9 +857,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
current->mm->start_stack = bprm->p;
/* Now we do a little grungy work by mmaping the ELF image into
- the correct location in memory. At this point, we assume that
- the image should be loaded at fixed address, not at a variable
- address. */
+ the correct location in memory. */
for(i = 0, elf_ppnt = elf_phdata;
i < loc->elf_ex.e_phnum; i++, elf_ppnt++) {
int elf_prot = 0, elf_flags;
@@ -864,11 +911,15 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
* default mmap base, as well as whatever program they
* might try to exec. This is because the brk will
* follow the loader, and is not movable. */
+#ifdef CONFIG_X86
+ load_bias = 0;
+#else
load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
+#endif
}
error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,
- elf_prot, elf_flags);
+ elf_prot, elf_flags,0);
if (BAD_ADDR(error)) {
send_sig(SIGKILL, current, 0);
retval = IS_ERR((void *)error) ?
@@ -944,13 +995,25 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
}
if (elf_interpreter) {
- if (interpreter_type == INTERPRETER_AOUT)
+ if (interpreter_type == INTERPRETER_AOUT) {
elf_entry = load_aout_interp(&loc->interp_ex,
interpreter);
- else
+ } else {
+ unsigned long uninitialized_var(interp_map_addr);
+
elf_entry = load_elf_interp(&loc->interp_elf_ex,
interpreter,
- &interp_load_addr);
+ &interp_map_addr,
+ load_bias);
+ if (!BAD_ADDR(elf_entry)) {
+ /*
+ * load_elf_interp() returns relocation
+ * adjustment
+ */
+ interp_load_addr = elf_entry;
+ elf_entry += loc->interp_elf_ex.e_entry;
+ }
+ }
if (BAD_ADDR(elf_entry)) {
force_sig(SIGSEGV, current);
retval = IS_ERR((void *)elf_entry) ?
diff --git a/fs/block_dev.c b/fs/block_dev.c
index b3e9bfa748c..3635315e3b9 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -588,12 +588,10 @@ EXPORT_SYMBOL(bdget);
long nr_blockdev_pages(void)
{
- struct list_head *p;
+ struct block_device *bdev;
long ret = 0;
spin_lock(&bdev_lock);
- list_for_each(p, &all_bdevs) {
- struct block_device *bdev;
- bdev = list_entry(p, struct block_device, bd_list);
+ list_for_each_entry(bdev, &all_bdevs, bd_list) {
ret += bdev->bd_inode->i_mapping->nrpages;
}
spin_unlock(&bdev_lock);
@@ -874,7 +872,7 @@ static struct bd_holder *find_bd_holder(struct block_device *bdev,
*/
static int add_bd_holder(struct block_device *bdev, struct bd_holder *bo)
{
- int ret;
+ int err;
if (!bo)
return -EINVAL;
@@ -882,15 +880,18 @@ static int add_bd_holder(struct block_device *bdev, struct bd_holder *bo)
if (!bd_holder_grab_dirs(bdev, bo))
return -EBUSY;
- ret = add_symlink(bo->sdir, bo->sdev);
- if (ret == 0) {
- ret = add_symlink(bo->hdir, bo->hdev);
- if (ret)
- del_symlink(bo->sdir, bo->sdev);
+ err = add_symlink(bo->sdir, bo->sdev);
+ if (err)
+ return err;
+
+ err = add_symlink(bo->hdir, bo->hdev);
+ if (err) {
+ del_symlink(bo->sdir, bo->sdev);
+ return err;
}
- if (ret == 0)
- list_add_tail(&bo->list, &bdev->bd_holder_list);
- return ret;
+
+ list_add_tail(&bo->list, &bdev->bd_holder_list);
+ return 0;
}
/**
@@ -948,7 +949,7 @@ static struct bd_holder *del_bd_holder(struct block_device *bdev,
static int bd_claim_by_kobject(struct block_device *bdev, void *holder,
struct kobject *kobj)
{
- int res;
+ int err;
struct bd_holder *bo, *found;
if (!kobj)
@@ -959,21 +960,24 @@ static int bd_claim_by_kobject(struct block_device *bdev, void *holder,
return -ENOMEM;
mutex_lock(&bdev->bd_mutex);
- res = bd_claim(bdev, holder);
- if (res == 0) {
- found = find_bd_holder(bdev, bo);
- if (found == NULL) {
- res = add_bd_holder(bdev, bo);
- if (res)
- bd_release(bdev);
- }
- }
- if (res || found)
- free_bd_holder(bo);
- mutex_unlock(&bdev->bd_mutex);
+ err = bd_claim(bdev, holder);
+ if (err)
+ goto fail;
- return res;
+ found = find_bd_holder(bdev, bo);
+ if (found)
+ goto fail;
+
+ err = add_bd_holder(bdev, bo);
+ if (err)
+ bd_release(bdev);
+ else
+ bo = NULL;
+fail:
+ mutex_unlock(&bdev->bd_mutex);
+ free_bd_holder(bo);
+ return err;
}
/**
@@ -987,15 +991,12 @@ static int bd_claim_by_kobject(struct block_device *bdev, void *holder,
static void bd_release_from_kobject(struct block_device *bdev,
struct kobject *kobj)
{
- struct bd_holder *bo;
-
if (!kobj)
return;
mutex_lock(&bdev->bd_mutex);
bd_release(bdev);
- if ((bo = del_bd_holder(bdev, kobj)))
- free_bd_holder(bo);
+ free_bd_holder(del_bd_holder(bdev, kobj));
mutex_unlock(&bdev->bd_mutex);
}
diff --git a/fs/buffer.c b/fs/buffer.c
index aa68206bd51..424165b569f 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1026,11 +1026,6 @@ failed:
/*
* Create buffers for the specified block device block's page. If
* that page was dirty, the buffers are set dirty also.
- *
- * Except that's a bug. Attaching dirty buffers to a dirty
- * blockdev's page can result in filesystem corruption, because
- * some of those buffers may be aliases of filesystem data.
- * grow_dev_page() will go BUG() if this happens.
*/
static int
grow_buffers(struct block_device *bdev, sector_t block, int size)
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 6b44cdc96fa..e440a7b95d0 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -63,6 +63,7 @@
#include <linux/wireless.h>
#include <linux/atalk.h>
#include <linux/blktrace_api.h>
+#include <linux/loop.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci.h>
@@ -3489,6 +3490,9 @@ HANDLE_IOCTL(LPSETTIMEOUT, lp_timeout_trans)
IGNORE_IOCTL(VFAT_IOCTL_READDIR_BOTH32)
IGNORE_IOCTL(VFAT_IOCTL_READDIR_SHORT32)
+
+/* loop */
+IGNORE_IOCTL(LOOP_CLR_FD)
};
#define IOCTL_HASHSIZE 256
diff --git a/fs/drop_caches.c b/fs/drop_caches.c
index 03ea7696fe3..59375efcf39 100644
--- a/fs/drop_caches.c
+++ b/fs/drop_caches.c
@@ -20,7 +20,7 @@ static void drop_pagecache_sb(struct super_block *sb)
list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
if (inode->i_state & (I_FREEING|I_WILL_FREE))
continue;
- invalidate_mapping_pages(inode->i_mapping, 0, -1);
+ __invalidate_mapping_pages(inode->i_mapping, 0, -1, true);
}
spin_unlock(&inode_lock);
}
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index 04afeecaaef..ab7961260c4 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -24,9 +24,9 @@
#include "acl.h"
/*
- * Called when an inode is released. Note that this is different
- * from ext2_open_file: open gets called at every open, but release
- * gets called only when /all/ the files are closed.
+ * Called when filp is released. This happens when all file descriptors
+ * for a single struct file are closed. Note that different open() calls
+ * for the same file yield different struct file structures.
*/
static int ext2_release_file (struct inode * inode, struct file * filp)
{
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 5de5061eb33..b2efd9083b9 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -1099,15 +1099,18 @@ static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf)
struct super_block *sb = dentry->d_sb;
struct ext2_sb_info *sbi = EXT2_SB(sb);
struct ext2_super_block *es = sbi->s_es;
- unsigned long overhead;
- int i;
u64 fsid;
if (test_opt (sb, MINIX_DF))
- overhead = 0;
- else {
+ sbi->s_overhead_last = 0;
+ else if (sbi->s_blocks_last != le32_to_cpu(es->s_blocks_count)) {
+ unsigned long i, overhead = 0;
+ smp_rmb();
+
/*
- * Compute the overhead (FS structures)
+ * Compute the overhead (FS structures). This is constant
+ * for a given filesystem unless the number of block groups
+ * changes so we cache the previous value until it does.
*/
/*
@@ -1131,17 +1134,22 @@ static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf)
*/
overhead += (sbi->s_groups_count *
(2 + sbi->s_itb_per_group));
+ sbi->s_overhead_last = overhead;
+ smp_wmb();
+ sbi->s_blocks_last = le32_to_cpu(es->s_blocks_count);
}
buf->f_type = EXT2_SUPER_MAGIC;
buf->f_bsize = sb->s_blocksize;
- buf->f_blocks = le32_to_cpu(es->s_blocks_count) - overhead;
+ buf->f_blocks = le32_to_cpu(es->s_blocks_count) - sbi->s_overhead_last;
buf->f_bfree = ext2_count_free_blocks(sb);
+ es->s_free_blocks_count = cpu_to_le32(buf->f_bfree);
buf->f_bavail = buf->f_bfree - le32_to_cpu(es->s_r_blocks_count);
if (buf->f_bfree < le32_to_cpu(es->s_r_blocks_count))
buf->f_bavail = 0;
buf->f_files = le32_to_cpu(es->s_inodes_count);
buf->f_ffree = ext2_count_free_inodes(sb);
+ es->s_free_inodes_count = cpu_to_le32(buf->f_ffree);
buf->f_namelen = EXT2_NAME_LEN;
fsid = le64_to_cpup((void *)es->s_uuid) ^
le64_to_cpup((void *)es->s_uuid + sizeof(u64));
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 2a85ddee474..de4e3161e47 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -3195,7 +3195,7 @@ int ext3_change_inode_journal_flag(struct inode *inode, int val)
*/
journal = EXT3_JOURNAL(inode);
- if (is_journal_aborted(journal) || IS_RDONLY(inode))
+ if (is_journal_aborted(journal))
return -EROFS;
journal_lock_updates(journal);
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index 9bb046df827..1586807b817 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -1019,6 +1019,11 @@ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, str
if (!inode)
return ERR_PTR(-EACCES);
+
+ if (is_bad_inode(inode)) {
+ iput(inode);
+ return ERR_PTR(-ENOENT);
+ }
}
return d_splice_alias(inode, dentry);
}
@@ -1054,6 +1059,11 @@ struct dentry *ext3_get_parent(struct dentry *child)
if (!inode)
return ERR_PTR(-EACCES);
+ if (is_bad_inode(inode)) {
+ iput(inode);
+ return ERR_PTR(-ENOENT);
+ }
+
parent = d_alloc_anon(inode);
if (!parent) {
iput(inode);
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index 6e3062913a9..51d1c456cda 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -35,6 +35,7 @@
#include <linux/namei.h>
#include <linux/quotaops.h>
#include <linux/seq_file.h>
+#include <linux/log2.h>
#include <asm/uaccess.h>
@@ -459,6 +460,14 @@ static struct inode *ext3_alloc_inode(struct super_block *sb)
static void ext3_destroy_inode(struct inode *inode)
{
+ if (!list_empty(&(EXT3_I(inode)->i_orphan))) {
+ printk("EXT3 Inode %p: orphan list check failed!\n",
+ EXT3_I(inode));
+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 16, 4,
+ EXT3_I(inode), sizeof(struct ext3_inode_info),
+ false);
+ dump_stack();
+ }
kmem_cache_free(ext3_inode_cachep, EXT3_I(inode));
}
@@ -1566,7 +1575,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
sbi->s_inode_size = le16_to_cpu(es->s_inode_size);
sbi->s_first_ino = le32_to_cpu(es->s_first_ino);
if ((sbi->s_inode_size < EXT3_GOOD_OLD_INODE_SIZE) ||
- (sbi->s_inode_size & (sbi->s_inode_size - 1)) ||
+ (!is_power_of_2(sbi->s_inode_size)) ||
(sbi->s_inode_size > blocksize)) {
printk (KERN_ERR
"EXT3-fs: unsupported inode size: %d\n",
@@ -2075,6 +2084,7 @@ static int ext3_create_journal(struct super_block * sb,
unsigned int journal_inum)
{
journal_t *journal;
+ int err;
if (sb->s_flags & MS_RDONLY) {
printk(KERN_ERR "EXT3-fs: readonly filesystem when trying to "
@@ -2082,13 +2092,15 @@ static int ext3_create_journal(struct super_block * sb,
return -EROFS;
}
- if (!(journal = ext3_get_journal(sb, journal_inum)))
+ journal = ext3_get_journal(sb, journal_inum);
+ if (!journal)
return -EINVAL;
printk(KERN_INFO "EXT3-fs: creating new journal on inode %u\n",
journal_inum);
- if (journal_create(journal)) {
+ err = journal_create(journal);
+ if (err) {
printk(KERN_ERR "EXT3-fs: error creating journal.\n");
journal_destroy(journal);
return -EIO;
@@ -2139,12 +2151,14 @@ static void ext3_mark_recovery_complete(struct super_block * sb,
journal_lock_updates(journal);
journal_flush(journal);
+ lock_super(sb);
if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER) &&
sb->s_flags & MS_RDONLY) {
EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);
sb->s_dirt = 0;
ext3_commit_super(sb, es, 1);
}
+ unlock_super(sb);
journal_unlock_updates(journal);
}
@@ -2333,7 +2347,13 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
(sbi->s_mount_state & EXT3_VALID_FS))
es->s_state = cpu_to_le16(sbi->s_mount_state);
+ /*
+ * We have to unlock super so that we can wait for
+ * transactions.
+ */
+ unlock_super(sb);
ext3_mark_recovery_complete(sb, es);
+ lock_super(sb);
} else {
__le32 ret;
if ((ret = EXT3_HAS_RO_COMPAT_FEATURE(sb,
@@ -2406,19 +2426,19 @@ static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf)
struct super_block *sb = dentry->d_sb;
struct ext3_sb_info *sbi = EXT3_SB(sb);
struct ext3_super_block *es = sbi->s_es;
- ext3_fsblk_t overhead;
- int i;
u64 fsid;
- if (test_opt (sb, MINIX_DF))
- overhead = 0;
- else {
- unsigned long ngroups;
- ngroups = EXT3_SB(sb)->s_groups_count;
+ if (test_opt(sb, MINIX_DF)) {
+ sbi->s_overhead_last = 0;
+ } else if (sbi->s_blocks_last != le32_to_cpu(es->s_blocks_count)) {
+ unsigned long ngroups = sbi->s_groups_count, i;
+ ext3_fsblk_t overhead = 0;
smp_rmb();
/*
- * Compute the overhead (FS structures)
+ * Compute the overhead (FS structures). This is constant
+ * for a given filesystem unless the number of block groups
+ * changes so we cache the previous value until it does.
*/
/*
@@ -2442,18 +2462,23 @@ static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf)
* Every block group has an inode bitmap, a block
* bitmap, and an inode table.
*/
- overhead += (ngroups * (2 + EXT3_SB(sb)->s_itb_per_group));
+ overhead += ngroups * (2 + sbi->s_itb_per_group);
+ sbi->s_overhead_last = overhead;
+ smp_wmb();
+ sbi->s_blocks_last = le32_to_cpu(es->s_blocks_count);
}
buf->f_type = EXT3_SUPER_MAGIC;
buf->f_bsize = sb->s_blocksize;
- buf->f_blocks = le32_to_cpu(es->s_blocks_count) - overhead;
+ buf->f_blocks = le32_to_cpu(es->s_blocks_count) - sbi->s_overhead_last;
buf->f_bfree = percpu_counter_sum(&sbi->s_freeblocks_counter);
+ es->s_free_blocks_count = cpu_to_le32(buf->f_bfree);
buf->f_bavail = buf->f_bfree - le32_to_cpu(es->s_r_blocks_count);
if (buf->f_bfree < le32_to_cpu(es->s_r_blocks_count))
buf->f_bavail = 0;
buf->f_files = le32_to_cpu(es->s_inodes_count);
buf->f_ffree = percpu_counter_sum(&sbi->s_freeinodes_counter);
+ es->s_free_inodes_count = cpu_to_le32(buf->f_ffree);
buf->f_namelen = EXT3_NAME_LEN;
fsid = le64_to_cpup((void *)es->s_uuid) ^
le64_to_cpup((void *)es->s_uuid + sizeof(u64));
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index 3b64bb16c72..9de54ae48de 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -1585,7 +1585,7 @@ allocated:
ret_block = grp_alloc_blk + ext4_group_first_block_no(sb, group_no);
if (in_range(ext4_block_bitmap(sb, gdp), ret_block, num) ||
- in_range(ext4_block_bitmap(sb, gdp), ret_block, num) ||
+ in_range(ext4_inode_bitmap(sb, gdp), ret_block, num) ||
in_range(ret_block, ext4_inode_table(sb, gdp),
EXT4_SB(sb)->s_itb_per_group) ||
in_range(ret_block + num - 1, ext4_inode_table(sb, gdp),
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 2811e5720ad..2de339dd755 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -1017,6 +1017,11 @@ static struct dentry *ext4_lookup(struct inode * dir, struct dentry *dentry, str
if (!inode)
return ERR_PTR(-EACCES);
+
+ if (is_bad_inode(inode)) {
+ iput(inode);
+ return ERR_PTR(-ENOENT);
+ }
}
return d_splice_alias(inode, dentry);
}
@@ -1052,6 +1057,11 @@ struct dentry *ext4_get_parent(struct dentry *child)
if (!inode)
return ERR_PTR(-EACCES);
+ if (is_bad_inode(inode)) {
+ iput(inode);
+ return ERR_PTR(-ENOENT);
+ }
+
parent = d_alloc_anon(inode);
if (!parent) {
iput(inode);
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 175b68c6096..d0d8c76c7ed 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -510,6 +510,14 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
static void ext4_destroy_inode(struct inode *inode)
{
+ if (!list_empty(&(EXT4_I(inode)->i_orphan))) {
+ printk("EXT4 Inode %p: orphan list check failed!\n",
+ EXT4_I(inode));
+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 16, 4,
+ EXT4_I(inode), sizeof(struct ext4_inode_info),
+ true);
+ dump_stack();
+ }
kmem_cache_free(ext4_inode_cachep, EXT4_I(inode));
}
@@ -2150,6 +2158,7 @@ static int ext4_create_journal(struct super_block * sb,
unsigned int journal_inum)
{
journal_t *journal;
+ int err;
if (sb->s_flags & MS_RDONLY) {
printk(KERN_ERR "EXT4-fs: readonly filesystem when trying to "
@@ -2157,13 +2166,15 @@ static int ext4_create_journal(struct super_block * sb,
return -EROFS;
}
- if (!(journal = ext4_get_journal(sb, journal_inum)))
+ journal = ext4_get_journal(sb, journal_inum);
+ if (!journal)
return -EINVAL;
printk(KERN_INFO "EXT4-fs: creating new journal on inode %u\n",
journal_inum);
- if (jbd2_journal_create(journal)) {
+ err = jbd2_journal_create(journal);
+ if (err) {
printk(KERN_ERR "EXT4-fs: error creating journal.\n");
jbd2_journal_destroy(journal);
return -EIO;
@@ -2214,12 +2225,14 @@ static void ext4_mark_recovery_complete(struct super_block * sb,
jbd2_journal_lock_updates(journal);
jbd2_journal_flush(journal);
+ lock_super(sb);
if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER) &&
sb->s_flags & MS_RDONLY) {
EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
sb->s_dirt = 0;
ext4_commit_super(sb, es, 1);
}
+ unlock_super(sb);
jbd2_journal_unlock_updates(journal);
}
@@ -2408,7 +2421,13 @@ static int ext4_remount (struct super_block * sb, int * flags, char * data)
(sbi->s_mount_state & EXT4_VALID_FS))
es->s_state = cpu_to_le16(sbi->s_mount_state);
+ /*
+ * We have to unlock super so that we can wait for
+ * transactions.
+ */
+ unlock_super(sb);
ext4_mark_recovery_complete(sb, es);
+ lock_super(sb);
} else {
__le32 ret;
if ((ret = EXT4_HAS_RO_COMPAT_FEATURE(sb,
@@ -2481,19 +2500,19 @@ static int ext4_statfs (struct dentry * dentry, struct kstatfs * buf)
struct super_block *sb = dentry->d_sb;
struct ext4_sb_info *sbi = EXT4_SB(sb);
struct ext4_super_block *es = sbi->s_es;
- ext4_fsblk_t overhead;
- int i;
u64 fsid;
- if (test_opt (sb, MINIX_DF))
- overhead = 0;
- else {
- unsigned long ngroups;
- ngroups = EXT4_SB(sb)->s_groups_count;
+ if (test_opt(sb, MINIX_DF)) {
+ sbi->s_overhead_last = 0;
+ } else if (sbi->s_blocks_last != le32_to_cpu(es->s_blocks_count)) {
+ unsigned long ngroups = sbi->s_groups_count, i;
+ ext4_fsblk_t overhead = 0;
smp_rmb();
/*
- * Compute the overhead (FS structures)
+ * Compute the overhead (FS structures). This is constant
+ * for a given filesystem unless the number of block groups
+ * changes so we cache the previous value until it does.
*/
/*
@@ -2517,18 +2536,23 @@ static int ext4_statfs (struct dentry * dentry, struct kstatfs * buf)
* Every block group has an inode bitmap, a block
* bitmap, and an inode table.
*/
- overhead += (ngroups * (2 + EXT4_SB(sb)->s_itb_per_group));
+ overhead += ngroups * (2 + sbi->s_itb_per_group);
+ sbi->s_overhead_last = overhead;
+ smp_wmb();
+ sbi->s_blocks_last = le32_to_cpu(es->s_blocks_count);
}
buf->f_type = EXT4_SUPER_MAGIC;
buf->f_bsize = sb->s_blocksize;
- buf->f_blocks = ext4_blocks_count(es) - overhead;
+ buf->f_blocks = ext4_blocks_count(es) - sbi->s_overhead_last;
buf->f_bfree = percpu_counter_sum(&sbi->s_freeblocks_counter);
+ es->s_free_blocks_count = cpu_to_le32(buf->f_bfree);
buf->f_bavail = buf->f_bfree - ext4_r_blocks_count(es);
if (buf->f_bfree < ext4_r_blocks_count(es))
buf->f_bavail = 0;
buf->f_files = le32_to_cpu(es->s_inodes_count);
buf->f_ffree = percpu_counter_sum(&sbi->s_freeinodes_counter);
+ es->s_free_inodes_count = cpu_to_le32(buf->f_ffree);
buf->f_namelen = EXT4_NAME_LEN;
fsid = le64_to_cpup((void *)es->s_uuid) ^
le64_to_cpup((void *)es->s_uuid + sizeof(u64));
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index ccf161dffb6..72cbcd61bd9 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -313,7 +313,7 @@ int fat_search_long(struct inode *inode, const unsigned char *name,
wchar_t bufuname[14];
unsigned char xlate_len, nr_slots;
wchar_t *unicode = NULL;
- unsigned char work[8], bufname[260]; /* 256 + 4 */
+ unsigned char work[MSDOS_NAME], bufname[260]; /* 256 + 4 */
int uni_xlate = sbi->options.unicode_xlate;
int utf8 = sbi->options.utf8;
int anycase = (sbi->options.name_check != 's');
@@ -351,7 +351,8 @@ parse_record:
if (work[0] == 0x05)
work[0] = 0xE5;
for (i = 0, j = 0, last_u = 0; i < 8;) {
- if (!work[i]) break;
+ if (!work[i])
+ break;
chl = fat_shortname2uni(nls_disk, &work[i], 8 - i,
&bufuname[j++], opt_shortname,
de->lcase & CASE_LOWER_BASE);
@@ -365,13 +366,15 @@ parse_record:
}
j = last_u;
fat_short2uni(nls_disk, ".", 1, &bufuname[j++]);
- for (i = 0; i < 3;) {
- if (!de->ext[i]) break;
- chl = fat_shortname2uni(nls_disk, &de->ext[i], 3 - i,
+ for (i = 8; i < MSDOS_NAME;) {
+ if (!work[i])
+ break;
+ chl = fat_shortname2uni(nls_disk, &work[i],
+ MSDOS_NAME - i,
&bufuname[j++], opt_shortname,
de->lcase & CASE_LOWER_EXT);
if (chl <= 1) {
- if (de->ext[i] != ' ')
+ if (work[i] != ' ')
last_u = j;
} else {
last_u = j;
@@ -445,7 +448,7 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
int fill_len;
wchar_t bufuname[14];
wchar_t *unicode = NULL;
- unsigned char c, work[8], bufname[56], *ptname = bufname;
+ unsigned char c, work[MSDOS_NAME], bufname[56], *ptname = bufname;
unsigned long lpos, dummy, *furrfu = &lpos;
int uni_xlate = sbi->options.unicode_xlate;
int isvfat = sbi->options.isvfat;
@@ -527,7 +530,8 @@ parse_record:
if (work[0] == 0x05)
work[0] = 0xE5;
for (i = 0, j = 0, last = 0, last_u = 0; i < 8;) {
- if (!(c = work[i])) break;
+ if (!(c = work[i]))
+ break;
chl = fat_shortname2uni(nls_disk, &work[i], 8 - i,
&bufuname[j++], opt_shortname,
de->lcase & CASE_LOWER_BASE);
@@ -549,9 +553,10 @@ parse_record:
j = last_u;
fat_short2uni(nls_disk, ".", 1, &bufuname[j++]);
ptname[i++] = '.';
- for (i2 = 0; i2 < 3;) {
- if (!(c = de->ext[i2])) break;
- chl = fat_shortname2uni(nls_disk, &de->ext[i2], 3 - i2,
+ for (i2 = 8; i2 < MSDOS_NAME;) {
+ if (!(c = work[i2]))
+ break;
+ chl = fat_shortname2uni(nls_disk, &work[i2], MSDOS_NAME - i2,
&bufuname[j++], opt_shortname,
de->lcase & CASE_LOWER_EXT);
if (chl <= 1) {
@@ -563,8 +568,8 @@ parse_record:
}
} else {
last_u = j;
- for (chi = 0; chi < chl && i2 < 3; chi++) {
- ptname[i++] = de->ext[i2++];
+ for (chi = 0; chi < chl && i2 < MSDOS_NAME; chi++) {
+ ptname[i++] = work[i2++];
last = i;
}
}
diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c
index ab171ea8e86..2c1b73fb82a 100644
--- a/fs/fat/fatent.c
+++ b/fs/fat/fatent.c
@@ -17,6 +17,8 @@ struct fatent_operations {
int (*ent_next)(struct fat_entry *);
};
+static DEFINE_SPINLOCK(fat12_entry_lock);
+
static void fat12_ent_blocknr(struct super_block *sb, int entry,
int *offset, sector_t *blocknr)
{
@@ -116,10 +118,13 @@ static int fat12_ent_get(struct fat_entry *fatent)
u8 **ent12_p = fatent->u.ent12_p;
int next;
+ spin_lock(&fat12_entry_lock);
if (fatent->entry & 1)
next = (*ent12_p[0] >> 4) | (*ent12_p[1] << 4);
else
next = (*ent12_p[1] << 8) | *ent12_p[0];
+ spin_unlock(&fat12_entry_lock);
+
next &= 0x0fff;
if (next >= BAD_FAT12)
next = FAT_ENT_EOF;
@@ -151,6 +156,7 @@ static void fat12_ent_put(struct fat_entry *fatent, int new)
if (new == FAT_ENT_EOF)
new = EOF_FAT12;
+ spin_lock(&fat12_entry_lock);
if (fatent->entry & 1) {
*ent12_p[0] = (new << 4) | (*ent12_p[0] & 0x0f);
*ent12_p[1] = new >> 4;
@@ -158,6 +164,7 @@ static void fat12_ent_put(struct fat_entry *fatent, int new)
*ent12_p[0] = new & 0xff;
*ent12_p[1] = (*ent12_p[1] & 0xf0) | (new >> 8);
}
+ spin_unlock(&fat12_entry_lock);
mark_buffer_dirty(fatent->bhs[0]);
if (fatent->nr_bhs == 2)
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 479722d8966..cfaf5877d98 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -354,8 +354,7 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
} else { /* not a directory */
inode->i_generation |= 1;
inode->i_mode = MSDOS_MKMODE(de->attr,
- ((sbi->options.showexec &&
- !is_exec(de->ext))
+ ((sbi->options.showexec && !is_exec(de->name + 8))
? S_IRUGO|S_IWUGO : S_IRWXUGO)
& ~sbi->options.fs_fmask) | S_IFREG;
MSDOS_I(inode)->i_start = le16_to_cpu(de->start);
diff --git a/fs/freevxfs/vxfs_dir.h b/fs/freevxfs/vxfs_dir.h
index 8a4dfef1dda..3c96d6e6397 100644
--- a/fs/freevxfs/vxfs_dir.h
+++ b/fs/freevxfs/vxfs_dir.h
@@ -80,7 +80,7 @@ struct vxfs_direct {
* a d_name with size len.
*/
#define VXFS_DIRPAD 4
-#define VXFS_NAMEMIN ((int)((struct vxfs_direct *)0)->d_name)
+#define VXFS_NAMEMIN offsetof(struct vxfs_direct, d_name)
#define VXFS_DIRROUND(len) ((VXFS_DIRPAD + (len) - 1) & ~(VXFS_DIRPAD -1))
#define VXFS_DIRLEN(len) (VXFS_DIRROUND(VXFS_NAMEMIN + (len)))
diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c
index c1f44009853..1ab3e9d7388 100644
--- a/fs/gfs2/eaops.c
+++ b/fs/gfs2/eaops.c
@@ -11,6 +11,7 @@
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/buffer_head.h>
+#include <linux/capability.h>
#include <linux/xattr.h>
#include <linux/gfs2_ondisk.h>
#include <linux/lm_interface.h>
diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c
index 90ebab753d3..050d29c0a5b 100644
--- a/fs/hfsplus/btree.c
+++ b/fs/hfsplus/btree.c
@@ -62,8 +62,10 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
if ((HFSPLUS_SB(sb).flags & HFSPLUS_SB_HFSX) &&
(head->key_type == HFSPLUS_KEY_BINARY))
tree->keycmp = hfsplus_cat_bin_cmp_key;
- else
+ else {
tree->keycmp = hfsplus_cat_case_cmp_key;
+ HFSPLUS_SB(sb).flags |= HFSPLUS_SB_CASEFOLD;
+ }
} else {
printk(KERN_ERR "hfs: unknown B*Tree requested\n");
goto fail_page;
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
index 80b5682a227..1955ee61251 100644
--- a/fs/hfsplus/dir.c
+++ b/fs/hfsplus/dir.c
@@ -36,6 +36,8 @@ static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry,
u16 type;
sb = dir->i_sb;
+
+ dentry->d_op = &hfsplus_dentry_operations;
dentry->d_fsdata = NULL;
hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd);
hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, &dentry->d_name);
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h
index 3915635b447..d9f5eda6d03 100644
--- a/fs/hfsplus/hfsplus_fs.h
+++ b/fs/hfsplus/hfsplus_fs.h
@@ -150,6 +150,7 @@ struct hfsplus_sb_info {
#define HFSPLUS_SB_NODECOMPOSE 0x0002
#define HFSPLUS_SB_FORCE 0x0004
#define HFSPLUS_SB_HFSX 0x0008
+#define HFSPLUS_SB_CASEFOLD 0x0010
struct hfsplus_inode_info {
@@ -321,6 +322,7 @@ void hfsplus_file_truncate(struct inode *);
/* inode.c */
extern const struct address_space_operations hfsplus_aops;
extern const struct address_space_operations hfsplus_btree_aops;
+extern struct dentry_operations hfsplus_dentry_operations;
void hfsplus_inode_read_fork(struct inode *, struct hfsplus_fork_raw *);
void hfsplus_inode_write_fork(struct inode *, struct hfsplus_fork_raw *);
@@ -353,6 +355,8 @@ int hfsplus_strcasecmp(const struct hfsplus_unistr *, const struct hfsplus_unist
int hfsplus_strcmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *);
int hfsplus_uni2asc(struct super_block *, const struct hfsplus_unistr *, char *, int *);
int hfsplus_asc2uni(struct super_block *, struct hfsplus_unistr *, const char *, int);
+int hfsplus_hash_dentry(struct dentry *dentry, struct qstr *str);
+int hfsplus_compare_dentry(struct dentry *dentry, struct qstr *s1, struct qstr *s2);
/* wrapper.c */
int hfsplus_read_wrapper(struct super_block *);
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index 409ce5429c9..6f7c662174d 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -131,6 +131,11 @@ const struct address_space_operations hfsplus_aops = {
.writepages = hfsplus_writepages,
};
+struct dentry_operations hfsplus_dentry_operations = {
+ .d_hash = hfsplus_hash_dentry,
+ .d_compare = hfsplus_compare_dentry,
+};
+
static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *nd)
{
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index ebd1b380cbb..6d87a2a9534 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -283,11 +283,10 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
struct nls_table *nls = NULL;
int err = -EINVAL;
- sbi = kmalloc(sizeof(struct hfsplus_sb_info), GFP_KERNEL);
+ sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
if (!sbi)
return -ENOMEM;
- memset(sbi, 0, sizeof(HFSPLUS_SB(sb)));
sb->s_fs_info = sbi;
INIT_HLIST_HEAD(&sbi->rsrc_inodes);
hfsplus_fill_defaults(sbi);
@@ -381,6 +380,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
iput(root);
goto cleanup;
}
+ sb->s_root->d_op = &hfsplus_dentry_operations;
str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1;
str.name = HFSP_HIDDENDIR_NAME;
diff --git a/fs/hfsplus/unicode.c b/fs/hfsplus/unicode.c
index 689c8bd721f..9e10f9444b6 100644
--- a/fs/hfsplus/unicode.c
+++ b/fs/hfsplus/unicode.c
@@ -239,61 +239,201 @@ out:
return res;
}
-int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr, const char *astr, int len)
+/*
+ * Convert one or more ASCII characters into a single unicode character.
+ * Returns the number of ASCII characters corresponding to the unicode char.
+ */
+static inline int asc2unichar(struct super_block *sb, const char *astr, int len,
+ wchar_t *uc)
{
- struct nls_table *nls = HFSPLUS_SB(sb).nls;
- int size, off, decompose;
+ int size = HFSPLUS_SB(sb).nls->char2uni(astr, len, uc);
+ if (size <= 0) {
+ *uc = '?';
+ size = 1;
+ }
+ switch (*uc) {
+ case 0x2400:
+ *uc = 0;
+ break;
+ case ':':
+ *uc = '/';
+ break;
+ }
+ return size;
+}
+
+/* Decomposes a single unicode character. */
+static inline u16 *decompose_unichar(wchar_t uc, int *size)
+{
+ int off;
+
+ off = hfsplus_decompose_table[(uc >> 12) & 0xf];
+ if (off == 0 || off == 0xffff)
+ return NULL;
+
+ off = hfsplus_decompose_table[off + ((uc >> 8) & 0xf)];
+ if (!off)
+ return NULL;
+
+ off = hfsplus_decompose_table[off + ((uc >> 4) & 0xf)];
+ if (!off)
+ return NULL;
+
+ off = hfsplus_decompose_table[off + (uc & 0xf)];
+ *size = off & 3;
+ if (*size == 0)
+ return NULL;
+ return hfsplus_decompose_table + (off / 4);
+}
+
+int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr,
+ const char *astr, int len)
+{
+ int size, dsize, decompose;
+ u16 *dstr, outlen = 0;
wchar_t c;
- u16 outlen = 0;
decompose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE);
-
while (outlen < HFSPLUS_MAX_STRLEN && len > 0) {
- size = nls->char2uni(astr, len, &c);
- if (size <= 0) {
- c = '?';
- size = 1;
- }
- astr += size;
- len -= size;
- switch (c) {
- case 0x2400:
- c = 0;
- break;
- case ':':
- c = '/';
- break;
- }
- if (c >= 0xc0 && decompose) {
- off = hfsplus_decompose_table[(c >> 12) & 0xf];
- if (!off)
- goto done;
- if (off == 0xffff) {
- goto done;
- }
- off = hfsplus_decompose_table[off + ((c >> 8) & 0xf)];
- if (!off)
- goto done;
- off = hfsplus_decompose_table[off + ((c >> 4) & 0xf)];
- if (!off)
- goto done;
- off = hfsplus_decompose_table[off + (c & 0xf)];
- size = off & 3;
- if (!size)
- goto done;
- off /= 4;
- if (outlen + size > HFSPLUS_MAX_STRLEN)
+ size = asc2unichar(sb, astr, len, &c);
+
+ if (decompose && (dstr = decompose_unichar(c, &dsize))) {
+ if (outlen + dsize > HFSPLUS_MAX_STRLEN)
break;
do {
- ustr->unicode[outlen++] = cpu_to_be16(hfsplus_decompose_table[off++]);
- } while (--size > 0);
- continue;
- }
- done:
- ustr->unicode[outlen++] = cpu_to_be16(c);
+ ustr->unicode[outlen++] = cpu_to_be16(*dstr++);
+ } while (--dsize > 0);
+ } else
+ ustr->unicode[outlen++] = cpu_to_be16(c);
+
+ astr += size;
+ len -= size;
}
ustr->length = cpu_to_be16(outlen);
if (len > 0)
return -ENAMETOOLONG;
return 0;
}
+
+/*
+ * Hash a string to an integer as appropriate for the HFS+ filesystem.
+ * Composed unicode characters are decomposed and case-folding is performed
+ * if the appropriate bits are (un)set on the superblock.
+ */
+int hfsplus_hash_dentry(struct dentry *dentry, struct qstr *str)
+{
+ struct super_block *sb = dentry->d_sb;
+ const char *astr;
+ const u16 *dstr;
+ int casefold, decompose, size, dsize, len;
+ unsigned long hash;
+ wchar_t c;
+ u16 c2;
+
+ casefold = (HFSPLUS_SB(sb).flags & HFSPLUS_SB_CASEFOLD);
+ decompose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE);
+ hash = init_name_hash();
+ astr = str->name;
+ len = str->len;
+ while (len > 0) {
+ size = asc2unichar(sb, astr, len, &c);
+ astr += size;
+ len -= size;
+
+ if (decompose && (dstr = decompose_unichar(c, &dsize))) {
+ do {
+ c2 = *dstr++;
+ if (!casefold || (c2 = case_fold(c2)))
+ hash = partial_name_hash(c2, hash);
+ } while (--dsize > 0);
+ } else {
+ c2 = c;
+ if (!casefold || (c2 = case_fold(c2)))
+ hash = partial_name_hash(c2, hash);
+ }
+ }
+ str->hash = end_name_hash(hash);
+
+ return 0;
+}
+
+/*
+ * Compare strings with HFS+ filename ordering.
+ * Composed unicode characters are decomposed and case-folding is performed
+ * if the appropriate bits are (un)set on the superblock.
+ */
+int hfsplus_compare_dentry(struct dentry *dentry, struct qstr *s1, struct qstr *s2)
+{
+ struct super_block *sb = dentry->d_sb;
+ int casefold, decompose, size;
+ int dsize1, dsize2, len1, len2;
+ const u16 *dstr1, *dstr2;
+ const char *astr1, *astr2;
+ u16 c1, c2;
+ wchar_t c;
+
+ casefold = (HFSPLUS_SB(sb).flags & HFSPLUS_SB_CASEFOLD);
+ decompose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE);
+ astr1 = s1->name;
+ len1 = s1->len;
+ astr2 = s2->name;
+ len2 = s2->len;
+ dsize1 = dsize2 = 0;
+ dstr1 = dstr2 = NULL;
+
+ while (len1 > 0 && len2 > 0) {
+ if (!dsize1) {
+ size = asc2unichar(sb, astr1, len1, &c);
+ astr1 += size;
+ len1 -= size;
+
+ if (!decompose || !(dstr1 = decompose_unichar(c, &dsize1))) {
+ c1 = c;
+ dstr1 = &c1;
+ dsize1 = 1;
+ }
+ }
+
+ if (!dsize2) {
+ size = asc2unichar(sb, astr2, len2, &c);
+ astr2 += size;
+ len2 -= size;
+
+ if (!decompose || !(dstr2 = decompose_unichar(c, &dsize2))) {
+ c2 = c;
+ dstr2 = &c2;
+ dsize2 = 1;
+ }
+ }
+
+ c1 = *dstr1;
+ c2 = *dstr2;
+ if (casefold) {
+ if (!(c1 = case_fold(c1))) {
+ dstr1++;
+ dsize1--;
+ continue;
+ }
+ if (!(c2 = case_fold(c2))) {
+ dstr2++;
+ dsize2--;
+ continue;
+ }
+ }
+ if (c1 < c2)
+ return -1;
+ else if (c1 > c2)
+ return 1;
+
+ dstr1++;
+ dsize1--;
+ dstr2++;
+ dsize2--;
+ }
+
+ if (len1 < len2)
+ return -1;
+ if (len1 > len2)
+ return 1;
+ return 0;
+}
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index e6b46b3ac2f..d145cb79c30 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -13,15 +13,18 @@
#include <linux/fs.h>
#include <linux/mount.h>
#include <linux/file.h>
+#include <linux/kernel.h>
#include <linux/writeback.h>
#include <linux/pagemap.h>
#include <linux/highmem.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/capability.h>
+#include <linux/ctype.h>
#include <linux/backing-dev.h>
#include <linux/hugetlb.h>
#include <linux/pagevec.h>
+#include <linux/parser.h>
#include <linux/mman.h>
#include <linux/quotaops.h>
#include <linux/slab.h>
@@ -47,6 +50,21 @@ static struct backing_dev_info hugetlbfs_backing_dev_info = {
int sysctl_hugetlb_shm_group;
+enum {
+ Opt_size, Opt_nr_inodes,
+ Opt_mode, Opt_uid, Opt_gid,
+ Opt_err,
+};
+
+static match_table_t tokens = {
+ {Opt_size, "size=%s"},
+ {Opt_nr_inodes, "nr_inodes=%s"},
+ {Opt_mode, "mode=%o"},
+ {Opt_uid, "uid=%u"},
+ {Opt_gid, "gid=%u"},
+ {Opt_err, NULL},
+};
+
static void huge_pagevec_release(struct pagevec *pvec)
{
int i;
@@ -594,46 +612,73 @@ static const struct super_operations hugetlbfs_ops = {
static int
hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig)
{
- char *opt, *value, *rest;
+ char *p, *rest;
+ substring_t args[MAX_OPT_ARGS];
+ int option;
if (!options)
return 0;
- while ((opt = strsep(&options, ",")) != NULL) {
- if (!*opt)
+
+ while ((p = strsep(&options, ",")) != NULL) {
+ int token;
+ if (!*p)
continue;
- value = strchr(opt, '=');
- if (!value || !*value)
- return -EINVAL;
- else
- *value++ = '\0';
-
- if (!strcmp(opt, "uid"))
- pconfig->uid = simple_strtoul(value, &value, 0);
- else if (!strcmp(opt, "gid"))
- pconfig->gid = simple_strtoul(value, &value, 0);
- else if (!strcmp(opt, "mode"))
- pconfig->mode = simple_strtoul(value,&value,0) & 0777U;
- else if (!strcmp(opt, "size")) {
- unsigned long long size = memparse(value, &rest);
+ token = match_token(p, tokens, args);
+ switch (token) {
+ case Opt_uid:
+ if (match_int(&args[0], &option))
+ goto bad_val;
+ pconfig->uid = option;
+ break;
+
+ case Opt_gid:
+ if (match_int(&args[0], &option))
+ goto bad_val;
+ pconfig->gid = option;
+ break;
+
+ case Opt_mode:
+ if (match_octal(&args[0], &option))
+ goto bad_val;
+ pconfig->mode = option & 0777U;
+ break;
+
+ case Opt_size: {
+ unsigned long long size;
+ /* memparse() will accept a K/M/G without a digit */
+ if (!isdigit(*args[0].from))
+ goto bad_val;
+ size = memparse(args[0].from, &rest);
if (*rest == '%') {
size <<= HPAGE_SHIFT;
size *= max_huge_pages;
do_div(size, 100);
- rest++;
}
pconfig->nr_blocks = (size >> HPAGE_SHIFT);
- value = rest;
- } else if (!strcmp(opt,"nr_inodes")) {
- pconfig->nr_inodes = memparse(value, &rest);
- value = rest;
- } else
- return -EINVAL;
+ break;
+ }
+
+ case Opt_nr_inodes:
+ /* memparse() will accept a K/M/G without a digit */
+ if (!isdigit(*args[0].from))
+ goto bad_val;
+ pconfig->nr_inodes = memparse(args[0].from, &rest);
+ break;
- if (*value)
+ default:
+ printk(KERN_ERR "hugetlbfs: Bad mount option: \"%s\"\n",
+ p);
return -EINVAL;
+ break;
+ }
}
return 0;
+
+bad_val:
+ printk(KERN_ERR "hugetlbfs: Bad value '%s' for mount option '%s'\n",
+ args[0].from, p);
+ return 1;
}
static int
@@ -651,7 +696,6 @@ hugetlbfs_fill_super(struct super_block *sb, void *data, int silent)
config.gid = current->fsgid;
config.mode = 0755;
ret = hugetlbfs_parse_options(data, &config);
-
if (ret)
return ret;
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 8c90cbc903f..c2a773e8620 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -12,7 +12,6 @@
#include <linux/fs.h>
#include <linux/security.h>
#include <linux/module.h>
-#include <linux/kallsyms.h>
#include <asm/uaccess.h>
#include <asm/ioctls.h>
@@ -21,7 +20,6 @@ static long do_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
int error = -ENOTTY;
- void *f;
if (!filp->f_op)
goto out;
@@ -31,16 +29,10 @@ static long do_ioctl(struct file *filp, unsigned int cmd,
if (error == -ENOIOCTLCMD)
error = -EINVAL;
goto out;
- } else if ((f = filp->f_op->ioctl)) {
+ } else if (filp->f_op->ioctl) {
lock_kernel();
- if (!filp->f_op->ioctl) {
- printk("%s: ioctl %p disappeared\n", __FUNCTION__, f);
- print_symbol("symbol: %s\n", (unsigned long)f);
- dump_stack();
- } else {
- error = filp->f_op->ioctl(filp->f_path.dentry->d_inode,
- filp, cmd, arg);
- }
+ error = filp->f_op->ioctl(filp->f_path.dentry->d_inode,
+ filp, cmd, arg);
unlock_kernel();
}
@@ -182,11 +174,3 @@ asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
out:
return error;
}
-
-/*
- * Platforms implementing 32 bit compatibility ioctl handlers in
- * modules need this exported
- */
-#ifdef CONFIG_COMPAT
-EXPORT_SYMBOL(sys_ioctl);
-#endif
diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c
index 0e94c31cad9..1ba407c64df 100644
--- a/fs/isofs/dir.c
+++ b/fs/isofs/dir.c
@@ -7,34 +7,18 @@
*
* Steve Beynon : Missing last directory entries fixed
* (stephen@askone.demon.co.uk) : 21st June 1996
- *
+ *
* isofs directory handling functions
*/
#include <linux/smp_lock.h>
#include "isofs.h"
-static int isofs_readdir(struct file *, void *, filldir_t);
-
-const struct file_operations isofs_dir_operations =
-{
- .read = generic_read_dir,
- .readdir = isofs_readdir,
-};
-
-/*
- * directories can handle most operations...
- */
-const struct inode_operations isofs_dir_inode_operations =
-{
- .lookup = isofs_lookup,
-};
-
int isofs_name_translate(struct iso_directory_record *de, char *new, struct inode *inode)
{
char * old = de->name;
int len = de->name_len[0];
int i;
-
+
for (i = 0; i < len; i++) {
unsigned char c = old[i];
if (!c)
@@ -62,22 +46,27 @@ int isofs_name_translate(struct iso_directory_record *de, char *new, struct inod
}
/* Acorn extensions written by Matthew Wilcox <willy@bofh.ai> 1998 */
-int get_acorn_filename(struct iso_directory_record * de,
- char * retname, struct inode * inode)
+int get_acorn_filename(struct iso_directory_record *de,
+ char *retname, struct inode *inode)
{
int std;
- unsigned char * chr;
+ unsigned char *chr;
int retnamlen = isofs_name_translate(de, retname, inode);
- if (retnamlen == 0) return 0;
+
+ if (retnamlen == 0)
+ return 0;
std = sizeof(struct iso_directory_record) + de->name_len[0];
- if (std & 1) std++;
- if ((*((unsigned char *) de) - std) != 32) return retnamlen;
+ if (std & 1)
+ std++;
+ if ((*((unsigned char *) de) - std) != 32)
+ return retnamlen;
chr = ((unsigned char *) de) + std;
- if (strncmp(chr, "ARCHIMEDES", 10)) return retnamlen;
- if ((*retname == '_') && ((chr[19] & 1) == 1)) *retname = '!';
+ if (strncmp(chr, "ARCHIMEDES", 10))
+ return retnamlen;
+ if ((*retname == '_') && ((chr[19] & 1) == 1))
+ *retname = '!';
if (((de->flags[0] & 2) == 0) && (chr[13] == 0xff)
- && ((chr[12] & 0xf0) == 0xf0))
- {
+ && ((chr[12] & 0xf0) == 0xf0)) {
retname[retnamlen] = ',';
sprintf(retname+retnamlen+1, "%3.3x",
((chr[12] & 0xf) << 8) | chr[11]);
@@ -91,7 +80,7 @@ int get_acorn_filename(struct iso_directory_record * de,
*/
static int do_isofs_readdir(struct inode *inode, struct file *filp,
void *dirent, filldir_t filldir,
- char * tmpname, struct iso_directory_record * tmpde)
+ char *tmpname, struct iso_directory_record *tmpde)
{
unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
@@ -121,9 +110,11 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
de_len = *(unsigned char *) de;
- /* If the length byte is zero, we should move on to the next
- CDROM sector. If we are at the end of the directory, we
- kick out of the while loop. */
+ /*
+ * If the length byte is zero, we should move on to the next
+ * CDROM sector. If we are at the end of the directory, we
+ * kick out of the while loop.
+ */
if (de_len == 0) {
brelse(bh);
@@ -157,11 +148,10 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
if (first_de) {
isofs_normalize_block_and_offset(de,
- &block_saved,
- &offset_saved);
+ &block_saved,
+ &offset_saved);
inode_number = isofs_get_ino(block_saved,
- offset_saved,
- bufbits);
+ offset_saved, bufbits);
}
if (de->flags[-sbi->s_high_sierra] & 0x80) {
@@ -199,7 +189,7 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
*/
if ((sbi->s_hide == 'y' &&
(de->flags[-sbi->s_high_sierra] & 1)) ||
- (sbi->s_showassoc =='n' &&
+ (sbi->s_showassoc =='n' &&
(de->flags[-sbi->s_high_sierra] & 4))) {
filp->f_pos += de_len;
continue;
@@ -240,7 +230,8 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
continue;
}
- if (bh) brelse(bh);
+ if (bh)
+ brelse(bh);
return 0;
}
@@ -253,8 +244,8 @@ static int isofs_readdir(struct file *filp,
void *dirent, filldir_t filldir)
{
int result;
- char * tmpname;
- struct iso_directory_record * tmpde;
+ char *tmpname;
+ struct iso_directory_record *tmpde;
struct inode *inode = filp->f_path.dentry->d_inode;
tmpname = (char *)__get_free_page(GFP_KERNEL);
@@ -270,3 +261,19 @@ static int isofs_readdir(struct file *filp,
unlock_kernel();
return result;
}
+
+const struct file_operations isofs_dir_operations =
+{
+ .read = generic_read_dir,
+ .readdir = isofs_readdir,
+};
+
+/*
+ * directories can handle most operations...
+ */
+const struct inode_operations isofs_dir_inode_operations =
+{
+ .lookup = isofs_lookup,
+};
+
+
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 5c3eecf7542..4f5418be059 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -73,20 +73,20 @@ static void isofs_destroy_inode(struct inode *inode)
kmem_cache_free(isofs_inode_cachep, ISOFS_I(inode));
}
-static void init_once(void *foo, struct kmem_cache * cachep, unsigned long flags)
+static void init_once(void *foo, struct kmem_cache *cachep, unsigned long flags)
{
struct iso_inode_info *ei = foo;
inode_init_once(&ei->vfs_inode);
}
-
+
static int init_inodecache(void)
{
isofs_inode_cachep = kmem_cache_create("isofs_inode_cache",
- sizeof(struct iso_inode_info),
- 0, (SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD),
- init_once, NULL);
+ sizeof(struct iso_inode_info),
+ 0, (SLAB_RECLAIM_ACCOUNT|
+ SLAB_MEM_SPREAD),
+ init_once, NULL);
if (isofs_inode_cachep == NULL)
return -ENOMEM;
return 0;
@@ -150,9 +150,9 @@ struct iso9660_options{
uid_t uid;
char *iocharset;
unsigned char utf8;
- /* LVE */
- s32 session;
- s32 sbsector;
+ /* LVE */
+ s32 session;
+ s32 sbsector;
};
/*
@@ -197,7 +197,7 @@ isofs_hashi_common(struct dentry *dentry, struct qstr *qstr, int ms)
hash = init_name_hash();
while (len--) {
c = tolower(*name++);
- hash = partial_name_hash(tolower(c), hash);
+ hash = partial_name_hash(c, hash);
}
qstr->hash = end_name_hash(hash);
@@ -360,10 +360,12 @@ static int parse_options(char *options, struct iso9660_options *popt)
popt->check = 'u'; /* unset */
popt->nocompress = 0;
popt->blocksize = 1024;
- popt->mode = S_IRUGO | S_IXUGO; /* r-x for all. The disc could
- be shared with DOS machines so
- virtually anything could be
- a valid executable. */
+ popt->mode = S_IRUGO | S_IXUGO; /*
+ * r-x for all. The disc could
+ * be shared with DOS machines so
+ * virtually anything could be
+ * a valid executable.
+ */
popt->gid = 0;
popt->uid = 0;
popt->iocharset = NULL;
@@ -503,30 +505,30 @@ static unsigned int isofs_get_last_session(struct super_block *sb, s32 session)
Te.cdte_format=CDROM_LBA;
i = ioctl_by_bdev(bdev, CDROMREADTOCENTRY, (unsigned long) &Te);
if (!i) {
- printk(KERN_DEBUG "Session %d start %d type %d\n",
- session, Te.cdte_addr.lba,
- Te.cdte_ctrl&CDROM_DATA_TRACK);
+ printk(KERN_DEBUG "ISOFS: Session %d start %d type %d\n",
+ session, Te.cdte_addr.lba,
+ Te.cdte_ctrl&CDROM_DATA_TRACK);
if ((Te.cdte_ctrl&CDROM_DATA_TRACK) == 4)
return Te.cdte_addr.lba;
}
-
- printk(KERN_ERR "Invalid session number or type of track\n");
+
+ printk(KERN_ERR "ISOFS: Invalid session number or type of track\n");
}
i = ioctl_by_bdev(bdev, CDROMMULTISESSION, (unsigned long) &ms_info);
if (session > 0)
- printk(KERN_ERR "Invalid session number\n");
+ printk(KERN_ERR "ISOFS: Invalid session number\n");
#if 0
- printk("isofs.inode: CDROMMULTISESSION: rc=%d\n",i);
+ printk(KERN_DEBUG "isofs.inode: CDROMMULTISESSION: rc=%d\n",i);
if (i==0) {
- printk("isofs.inode: XA disk: %s\n",ms_info.xa_flag?"yes":"no");
- printk("isofs.inode: vol_desc_start = %d\n", ms_info.addr.lba);
+ printk(KERN_DEBUG "isofs.inode: XA disk: %s\n",ms_info.xa_flag?"yes":"no");
+ printk(KERN_DEBUG "isofs.inode: vol_desc_start = %d\n", ms_info.addr.lba);
}
#endif
if (i==0)
#if WE_OBEY_THE_WRITTEN_STANDARDS
- if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */
+ if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */
#endif
- vol_desc_start=ms_info.addr.lba;
+ vol_desc_start=ms_info.addr.lba;
return vol_desc_start;
}
@@ -538,20 +540,20 @@ static unsigned int isofs_get_last_session(struct super_block *sb, s32 session)
*/
static int isofs_fill_super(struct super_block *s, void *data, int silent)
{
- struct buffer_head * bh = NULL, *pri_bh = NULL;
- struct hs_primary_descriptor * h_pri = NULL;
- struct iso_primary_descriptor * pri = NULL;
+ struct buffer_head *bh = NULL, *pri_bh = NULL;
+ struct hs_primary_descriptor *h_pri = NULL;
+ struct iso_primary_descriptor *pri = NULL;
struct iso_supplementary_descriptor *sec = NULL;
- struct iso_directory_record * rootp;
- int joliet_level = 0;
- int iso_blknum, block;
- int orig_zonesize;
- int table;
- unsigned int vol_desc_start;
- unsigned long first_data_zone;
- struct inode * inode;
- struct iso9660_options opt;
- struct isofs_sb_info * sbi;
+ struct iso_directory_record *rootp;
+ struct inode *inode;
+ struct iso9660_options opt;
+ struct isofs_sb_info *sbi;
+ unsigned long first_data_zone;
+ int joliet_level = 0;
+ int iso_blknum, block;
+ int orig_zonesize;
+ int table;
+ unsigned int vol_desc_start;
sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
if (!sbi)
@@ -577,72 +579,73 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
vol_desc_start = (opt.sbsector != -1) ?
opt.sbsector : isofs_get_last_session(s,opt.session);
- for (iso_blknum = vol_desc_start+16;
- iso_blknum < vol_desc_start+100; iso_blknum++)
- {
- struct hs_volume_descriptor * hdp;
- struct iso_volume_descriptor * vdp;
-
- block = iso_blknum << (ISOFS_BLOCK_BITS - s->s_blocksize_bits);
- if (!(bh = sb_bread(s, block)))
- goto out_no_read;
-
- vdp = (struct iso_volume_descriptor *)bh->b_data;
- hdp = (struct hs_volume_descriptor *)bh->b_data;
-
- /* Due to the overlapping physical location of the descriptors,
- * ISO CDs can match hdp->id==HS_STANDARD_ID as well. To ensure
- * proper identification in this case, we first check for ISO.
- */
- if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) {
- if (isonum_711 (vdp->type) == ISO_VD_END)
- break;
- if (isonum_711 (vdp->type) == ISO_VD_PRIMARY) {
- if (pri == NULL) {
- pri = (struct iso_primary_descriptor *)vdp;
- /* Save the buffer in case we need it ... */
- pri_bh = bh;
- bh = NULL;
- }
- }
+ for (iso_blknum = vol_desc_start+16;
+ iso_blknum < vol_desc_start+100; iso_blknum++) {
+ struct hs_volume_descriptor *hdp;
+ struct iso_volume_descriptor *vdp;
+
+ block = iso_blknum << (ISOFS_BLOCK_BITS - s->s_blocksize_bits);
+ if (!(bh = sb_bread(s, block)))
+ goto out_no_read;
+
+ vdp = (struct iso_volume_descriptor *)bh->b_data;
+ hdp = (struct hs_volume_descriptor *)bh->b_data;
+
+ /*
+ * Due to the overlapping physical location of the descriptors,
+ * ISO CDs can match hdp->id==HS_STANDARD_ID as well. To ensure
+ * proper identification in this case, we first check for ISO.
+ */
+ if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) {
+ if (isonum_711(vdp->type) == ISO_VD_END)
+ break;
+ if (isonum_711(vdp->type) == ISO_VD_PRIMARY) {
+ if (pri == NULL) {
+ pri = (struct iso_primary_descriptor *)vdp;
+ /* Save the buffer in case we need it ... */
+ pri_bh = bh;
+ bh = NULL;
+ }
+ }
#ifdef CONFIG_JOLIET
- else if (isonum_711 (vdp->type) == ISO_VD_SUPPLEMENTARY) {
- sec = (struct iso_supplementary_descriptor *)vdp;
- if (sec->escape[0] == 0x25 && sec->escape[1] == 0x2f) {
- if (opt.joliet == 'y') {
- if (sec->escape[2] == 0x40) {
- joliet_level = 1;
- } else if (sec->escape[2] == 0x43) {
- joliet_level = 2;
- } else if (sec->escape[2] == 0x45) {
- joliet_level = 3;
- }
- printk(KERN_DEBUG"ISO 9660 Extensions: Microsoft Joliet Level %d\n",
- joliet_level);
+ else if (isonum_711(vdp->type) == ISO_VD_SUPPLEMENTARY) {
+ sec = (struct iso_supplementary_descriptor *)vdp;
+ if (sec->escape[0] == 0x25 && sec->escape[1] == 0x2f) {
+ if (opt.joliet == 'y') {
+ if (sec->escape[2] == 0x40)
+ joliet_level = 1;
+ else if (sec->escape[2] == 0x43)
+ joliet_level = 2;
+ else if (sec->escape[2] == 0x45)
+ joliet_level = 3;
+
+ printk(KERN_DEBUG "ISO 9660 Extensions: "
+ "Microsoft Joliet Level %d\n",
+ joliet_level);
+ }
+ goto root_found;
+ } else {
+ /* Unknown supplementary volume descriptor */
+ sec = NULL;
+ }
}
- goto root_found;
- } else {
- /* Unknown supplementary volume descriptor */
- sec = NULL;
- }
- }
#endif
- } else {
- if (strncmp (hdp->id, HS_STANDARD_ID, sizeof hdp->id) == 0) {
- if (isonum_711 (hdp->type) != ISO_VD_PRIMARY)
- goto out_freebh;
-
- sbi->s_high_sierra = 1;
- opt.rock = 'n';
- h_pri = (struct hs_primary_descriptor *)vdp;
- goto root_found;
+ } else {
+ if (strncmp (hdp->id, HS_STANDARD_ID, sizeof hdp->id) == 0) {
+ if (isonum_711(hdp->type) != ISO_VD_PRIMARY)
+ goto out_freebh;
+
+ sbi->s_high_sierra = 1;
+ opt.rock = 'n';
+ h_pri = (struct hs_primary_descriptor *)vdp;
+ goto root_found;
+ }
}
- }
- /* Just skip any volume descriptors we don't recognize */
+ /* Just skip any volume descriptors we don't recognize */
- brelse(bh);
- bh = NULL;
+ brelse(bh);
+ bh = NULL;
}
/*
* If we fall through, either no volume descriptor was found,
@@ -657,24 +660,24 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
root_found:
if (joliet_level && (pri == NULL || opt.rock == 'n')) {
- /* This is the case of Joliet with the norock mount flag.
- * A disc with both Joliet and Rock Ridge is handled later
- */
- pri = (struct iso_primary_descriptor *) sec;
+ /* This is the case of Joliet with the norock mount flag.
+ * A disc with both Joliet and Rock Ridge is handled later
+ */
+ pri = (struct iso_primary_descriptor *) sec;
}
if(sbi->s_high_sierra){
- rootp = (struct iso_directory_record *) h_pri->root_directory_record;
- sbi->s_nzones = isonum_733 (h_pri->volume_space_size);
- sbi->s_log_zone_size = isonum_723 (h_pri->logical_block_size);
- sbi->s_max_size = isonum_733(h_pri->volume_space_size);
+ rootp = (struct iso_directory_record *) h_pri->root_directory_record;
+ sbi->s_nzones = isonum_733(h_pri->volume_space_size);
+ sbi->s_log_zone_size = isonum_723(h_pri->logical_block_size);
+ sbi->s_max_size = isonum_733(h_pri->volume_space_size);
} else {
- if (!pri)
- goto out_freebh;
- rootp = (struct iso_directory_record *) pri->root_directory_record;
- sbi->s_nzones = isonum_733 (pri->volume_space_size);
- sbi->s_log_zone_size = isonum_723 (pri->logical_block_size);
- sbi->s_max_size = isonum_733(pri->volume_space_size);
+ if (!pri)
+ goto out_freebh;
+ rootp = (struct iso_directory_record *) pri->root_directory_record;
+ sbi->s_nzones = isonum_733(pri->volume_space_size);
+ sbi->s_log_zone_size = isonum_723(pri->logical_block_size);
+ sbi->s_max_size = isonum_733(pri->volume_space_size);
}
sbi->s_ninodes = 0; /* No way to figure this out easily */
@@ -687,42 +690,43 @@ root_found:
* blocks that were 512 bytes (which should only very rarely
* happen.)
*/
- if(orig_zonesize < opt.blocksize)
+ if (orig_zonesize < opt.blocksize)
goto out_bad_size;
/* RDE: convert log zone size to bit shift */
- switch (sbi->s_log_zone_size)
- { case 512: sbi->s_log_zone_size = 9; break;
- case 1024: sbi->s_log_zone_size = 10; break;
- case 2048: sbi->s_log_zone_size = 11; break;
+ switch (sbi->s_log_zone_size) {
+ case 512: sbi->s_log_zone_size = 9; break;
+ case 1024: sbi->s_log_zone_size = 10; break;
+ case 2048: sbi->s_log_zone_size = 11; break;
- default:
+ default:
goto out_bad_zone_size;
- }
+ }
s->s_magic = ISOFS_SUPER_MAGIC;
s->s_maxbytes = 0xffffffff; /* We can handle files up to 4 GB */
- /* The CDROM is read-only, has no nodes (devices) on it, and since
- all of the files appear to be owned by root, we really do not want
- to allow suid. (suid or devices will not show up unless we have
- Rock Ridge extensions) */
+ /*
+ * The CDROM is read-only, has no nodes (devices) on it, and since
+ * all of the files appear to be owned by root, we really do not want
+ * to allow suid. (suid or devices will not show up unless we have
+ * Rock Ridge extensions)
+ */
s->s_flags |= MS_RDONLY /* | MS_NODEV | MS_NOSUID */;
/* Set this for reference. Its not currently used except on write
which we don't have .. */
-
- first_data_zone = isonum_733 (rootp->extent) +
- isonum_711 (rootp->ext_attr_length);
+
+ first_data_zone = isonum_733(rootp->extent) +
+ isonum_711(rootp->ext_attr_length);
sbi->s_firstdatazone = first_data_zone;
#ifndef BEQUIET
- printk(KERN_DEBUG "Max size:%ld Log zone size:%ld\n",
- sbi->s_max_size,
- 1UL << sbi->s_log_zone_size);
- printk(KERN_DEBUG "First datazone:%ld\n", sbi->s_firstdatazone);
+ printk(KERN_DEBUG "ISOFS: Max size:%ld Log zone size:%ld\n",
+ sbi->s_max_size, 1UL << sbi->s_log_zone_size);
+ printk(KERN_DEBUG "ISOFS: First datazone:%ld\n", sbi->s_firstdatazone);
if(sbi->s_high_sierra)
- printk(KERN_DEBUG "Disc in High Sierra format.\n");
+ printk(KERN_DEBUG "ISOFS: Disc in High Sierra format.\n");
#endif
/*
@@ -737,8 +741,8 @@ root_found:
pri = (struct iso_primary_descriptor *) sec;
rootp = (struct iso_directory_record *)
pri->root_directory_record;
- first_data_zone = isonum_733 (rootp->extent) +
- isonum_711 (rootp->ext_attr_length);
+ first_data_zone = isonum_733(rootp->extent) +
+ isonum_711(rootp->ext_attr_length);
}
/*
@@ -771,7 +775,7 @@ root_found:
#ifdef CONFIG_JOLIET
if (joliet_level && opt.utf8 == 0) {
- char * p = opt.iocharset ? opt.iocharset : CONFIG_NLS_DEFAULT;
+ char *p = opt.iocharset ? opt.iocharset : CONFIG_NLS_DEFAULT;
sbi->s_nls_iocharset = load_nls(p);
if (! sbi->s_nls_iocharset) {
/* Fail only if explicit charset specified */
@@ -821,7 +825,7 @@ root_found:
sbi->s_rock = 0;
if (sbi->s_firstdatazone != first_data_zone) {
sbi->s_firstdatazone = first_data_zone;
- printk(KERN_DEBUG
+ printk(KERN_DEBUG
"ISOFS: changing to secondary root\n");
iput(inode);
inode = isofs_iget(s, sbi->s_firstdatazone, 0);
@@ -830,8 +834,10 @@ root_found:
if (opt.check == 'u') {
/* Only Joliet is case insensitive by default */
- if (joliet_level) opt.check = 'r';
- else opt.check = 's';
+ if (joliet_level)
+ opt.check = 'r';
+ else
+ opt.check = 's';
}
sbi->s_joliet_level = joliet_level;
@@ -846,8 +852,10 @@ root_found:
goto out_no_root;
table = 0;
- if (joliet_level) table += 2;
- if (opt.check == 'r') table++;
+ if (joliet_level)
+ table += 2;
+ if (opt.check == 'r')
+ table++;
s->s_root->d_op = &isofs_dentry_ops[table];
kfree(opt.iocharset);
@@ -858,10 +866,10 @@ root_found:
* Display error messages and free resources.
*/
out_bad_root:
- printk(KERN_WARNING "isofs_fill_super: root inode not initialized\n");
+ printk(KERN_WARNING "%s: root inode not initialized\n", __func__);
goto out_iput;
out_no_root:
- printk(KERN_WARNING "isofs_fill_super: get root inode failed\n");
+ printk(KERN_WARNING "%s: get root inode failed\n", __func__);
out_iput:
iput(inode);
#ifdef CONFIG_JOLIET
@@ -870,21 +878,20 @@ out_iput:
#endif
goto out_freesbi;
out_no_read:
- printk(KERN_WARNING "isofs_fill_super: "
- "bread failed, dev=%s, iso_blknum=%d, block=%d\n",
- s->s_id, iso_blknum, block);
+ printk(KERN_WARNING "%s: bread failed, dev=%s, iso_blknum=%d, block=%d\n",
+ __func__, s->s_id, iso_blknum, block);
goto out_freesbi;
out_bad_zone_size:
- printk(KERN_WARNING "Bad logical zone size %ld\n",
+ printk(KERN_WARNING "ISOFS: Bad logical zone size %ld\n",
sbi->s_log_zone_size);
goto out_freebh;
out_bad_size:
- printk(KERN_WARNING "Logical zone size(%d) < hardware blocksize(%u)\n",
+ printk(KERN_WARNING "ISOFS: Logical zone size(%d) < hardware blocksize(%u)\n",
orig_zonesize, opt.blocksize);
goto out_freebh;
out_unknown_format:
if (!silent)
- printk(KERN_WARNING "Unable to identify CD-ROM format.\n");
+ printk(KERN_WARNING "ISOFS: Unable to identify CD-ROM format.\n");
out_freebh:
brelse(bh);
@@ -902,7 +909,7 @@ static int isofs_statfs (struct dentry *dentry, struct kstatfs *buf)
buf->f_type = ISOFS_SUPER_MAGIC;
buf->f_bsize = sb->s_blocksize;
buf->f_blocks = (ISOFS_SB(sb)->s_nzones
- << (ISOFS_SB(sb)->s_log_zone_size - sb->s_blocksize_bits));
+ << (ISOFS_SB(sb)->s_log_zone_size - sb->s_blocksize_bits));
buf->f_bfree = 0;
buf->f_bavail = 0;
buf->f_files = ISOFS_SB(sb)->s_ninodes;
@@ -931,20 +938,20 @@ int isofs_get_blocks(struct inode *inode, sector_t iblock_s,
rv = 0;
if (iblock < 0 || iblock != iblock_s) {
- printk("isofs_get_blocks: block number too large\n");
+ printk(KERN_DEBUG "%s: block number too large\n", __func__);
goto abort;
}
b_off = iblock;
-
- offset = 0;
- firstext = ei->i_first_extent;
+
+ offset = 0;
+ firstext = ei->i_first_extent;
sect_size = ei->i_section_size >> ISOFS_BUFFER_BITS(inode);
- nextblk = ei->i_next_section_block;
- nextoff = ei->i_next_section_offset;
- section = 0;
+ nextblk = ei->i_next_section_block;
+ nextoff = ei->i_next_section_offset;
+ section = 0;
- while ( nblocks ) {
+ while (nblocks) {
/* If we are *way* beyond the end of the file, print a message.
* Access beyond the end of the file up to the next page boundary
* is normal, however because of the way the page cache works.
@@ -953,11 +960,11 @@ int isofs_get_blocks(struct inode *inode, sector_t iblock_s,
* I/O errors.
*/
if (b_off > ((inode->i_size + PAGE_CACHE_SIZE - 1) >> ISOFS_BUFFER_BITS(inode))) {
- printk("isofs_get_blocks: block >= EOF (%ld, %ld)\n",
- iblock, (unsigned long) inode->i_size);
+ printk(KERN_DEBUG "%s: block >= EOF (%ld, %ld)\n",
+ __func__, iblock, (unsigned long) inode->i_size);
goto abort;
}
-
+
/* On the last section, nextblk == 0, section size is likely to
* exceed sect_size by a partial block, and access beyond the
* end of the file will reach beyond the section size, too.
@@ -976,20 +983,21 @@ int isofs_get_blocks(struct inode *inode, sector_t iblock_s,
iput(ninode);
if (++section > 100) {
- printk("isofs_get_blocks: More than 100 file sections ?!?, aborting...\n");
- printk("isofs_get_blocks: block=%ld firstext=%u sect_size=%u "
- "nextblk=%lu nextoff=%lu\n",
- iblock, firstext, (unsigned) sect_size,
- nextblk, nextoff);
+ printk(KERN_DEBUG "%s: More than 100 file sections ?!?"
+ " aborting...\n", __func__);
+ printk(KERN_DEBUG "%s: block=%ld firstext=%u sect_size=%u "
+ "nextblk=%lu nextoff=%lu\n", __func__,
+ iblock, firstext, (unsigned) sect_size,
+ nextblk, nextoff);
goto abort;
}
}
-
- if ( *bh ) {
+
+ if (*bh) {
map_bh(*bh, inode->i_sb, firstext + b_off - offset);
} else {
*bh = sb_getblk(inode->i_sb, firstext+b_off-offset);
- if ( !*bh )
+ if (!*bh)
goto abort;
}
bh++; /* Next buffer head */
@@ -1010,7 +1018,7 @@ static int isofs_get_block(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create)
{
if (create) {
- printk("isofs_get_block: Kernel tries to allocate a block\n");
+ printk(KERN_DEBUG "%s: Kernel tries to allocate a block\n", __func__);
return -EROFS;
}
@@ -1070,11 +1078,11 @@ static int isofs_read_level3_size(struct inode *inode)
{
unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
int high_sierra = ISOFS_SB(inode->i_sb)->s_high_sierra;
- struct buffer_head * bh = NULL;
+ struct buffer_head *bh = NULL;
unsigned long block, offset, block_saved, offset_saved;
int i = 0;
int more_entries = 0;
- struct iso_directory_record * tmpde = NULL;
+ struct iso_directory_record *tmpde = NULL;
struct iso_inode_info *ei = ISOFS_I(inode);
inode->i_size = 0;
@@ -1089,7 +1097,7 @@ static int isofs_read_level3_size(struct inode *inode)
offset = ei->i_iget5_offset;
do {
- struct iso_directory_record * de;
+ struct iso_directory_record *de;
unsigned int de_len;
if (!bh) {
@@ -1163,10 +1171,9 @@ out_noread:
return -EIO;
out_toomany:
- printk(KERN_INFO "isofs_read_level3_size: "
- "More than 100 file sections ?!?, aborting...\n"
- "isofs_read_level3_size: inode=%lu\n",
- inode->i_ino);
+ printk(KERN_INFO "%s: More than 100 file sections ?!?, aborting...\n"
+ "isofs_read_level3_size: inode=%lu\n",
+ __func__, inode->i_ino);
goto out;
}
@@ -1177,9 +1184,9 @@ static void isofs_read_inode(struct inode *inode)
unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
unsigned long block;
int high_sierra = sbi->s_high_sierra;
- struct buffer_head * bh = NULL;
- struct iso_directory_record * de;
- struct iso_directory_record * tmpde = NULL;
+ struct buffer_head *bh = NULL;
+ struct iso_directory_record *de;
+ struct iso_directory_record *tmpde = NULL;
unsigned int de_len;
unsigned long offset;
struct iso_inode_info *ei = ISOFS_I(inode);
@@ -1199,7 +1206,7 @@ static void isofs_read_inode(struct inode *inode)
tmpde = kmalloc(de_len, GFP_KERNEL);
if (tmpde == NULL) {
- printk(KERN_INFO "isofs_read_inode: out of memory\n");
+ printk(KERN_INFO "%s: out of memory\n", __func__);
goto fail;
}
memcpy(tmpde, bh->b_data + offset, frag1);
@@ -1212,24 +1219,26 @@ static void isofs_read_inode(struct inode *inode)
}
inode->i_ino = isofs_get_ino(ei->i_iget5_block,
- ei->i_iget5_offset,
- ISOFS_BUFFER_BITS(inode));
+ ei->i_iget5_offset,
+ ISOFS_BUFFER_BITS(inode));
/* Assume it is a normal-format file unless told otherwise */
ei->i_file_format = isofs_file_normal;
if (de->flags[-high_sierra] & 2) {
inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR;
- inode->i_nlink = 1; /* Set to 1. We know there are 2, but
- the find utility tries to optimize
- if it is 2, and it screws up. It is
- easier to give 1 which tells find to
- do it the hard way. */
+ inode->i_nlink = 1; /*
+ * Set to 1. We know there are 2, but
+ * the find utility tries to optimize
+ * if it is 2, and it screws up. It is
+ * easier to give 1 which tells find to
+ * do it the hard way.
+ */
} else {
- /* Everybody gets to read the file. */
+ /* Everybody gets to read the file. */
inode->i_mode = sbi->s_mode;
inode->i_nlink = 1;
- inode->i_mode |= S_IFREG;
+ inode->i_mode |= S_IFREG;
}
inode->i_uid = sbi->s_uid;
inode->i_gid = sbi->s_gid;
@@ -1239,13 +1248,14 @@ static void isofs_read_inode(struct inode *inode)
ei->i_format_parm[1] = 0;
ei->i_format_parm[2] = 0;
- ei->i_section_size = isonum_733 (de->size);
+ ei->i_section_size = isonum_733(de->size);
if (de->flags[-high_sierra] & 0x80) {
- if(isofs_read_level3_size(inode)) goto fail;
+ if(isofs_read_level3_size(inode))
+ goto fail;
} else {
ei->i_next_section_block = 0;
ei->i_next_section_offset = 0;
- inode->i_size = isonum_733 (de->size);
+ inode->i_size = isonum_733(de->size);
}
/*
@@ -1258,23 +1268,24 @@ static void isofs_read_inode(struct inode *inode)
inode->i_size &= 0x00ffffff;
if (de->interleave[0]) {
- printk("Interleaved files not (yet) supported.\n");
+ printk(KERN_DEBUG "ISOFS: Interleaved files not (yet) supported.\n");
inode->i_size = 0;
}
/* I have no idea what file_unit_size is used for, so
we will flag it for now */
if (de->file_unit_size[0] != 0) {
- printk("File unit size != 0 for ISO file (%ld).\n",
- inode->i_ino);
+ printk(KERN_DEBUG "ISOFS: File unit size != 0 for ISO file (%ld).\n",
+ inode->i_ino);
}
/* I have no idea what other flag bits are used for, so
we will flag it for now */
#ifdef DEBUG
if((de->flags[-high_sierra] & ~2)!= 0){
- printk("Unusual flag settings for ISO file (%ld %x).\n",
- inode->i_ino, de->flags[-high_sierra]);
+ printk(KERN_DEBUG "ISOFS: Unusual flag settings for ISO file "
+ "(%ld %x).\n",
+ inode->i_ino, de->flags[-high_sierra]);
}
#endif
@@ -1285,11 +1296,11 @@ static void isofs_read_inode(struct inode *inode)
inode->i_atime.tv_nsec =
inode->i_ctime.tv_nsec = 0;
- ei->i_first_extent = (isonum_733 (de->extent) +
- isonum_711 (de->ext_attr_length));
+ ei->i_first_extent = (isonum_733(de->extent) +
+ isonum_711(de->ext_attr_length));
/* Set the number of blocks for stat() - should be done before RR */
- inode->i_blocks = (inode->i_size + 511) >> 9;
+ inode->i_blocks = (inode->i_size + 511) >> 9;
/*
* Now test for possible Rock Ridge extensions which will override
@@ -1306,7 +1317,7 @@ static void isofs_read_inode(struct inode *inode)
/* Install the inode operations vector */
if (S_ISREG(inode->i_mode)) {
inode->i_fop = &generic_ro_fops;
- switch ( ei->i_file_format ) {
+ switch (ei->i_file_format) {
#ifdef CONFIG_ZISOFS
case isofs_file_compressed:
inode->i_data.a_ops = &zisofs_aops;
@@ -1350,7 +1361,7 @@ static int isofs_iget5_test(struct inode *ino, void *data)
struct isofs_iget5_callback_data *d =
(struct isofs_iget5_callback_data*)data;
return (i->i_iget5_block == d->block)
- && (i->i_iget5_offset == d->offset);
+ && (i->i_iget5_offset == d->offset);
}
static int isofs_iget5_set(struct inode *ino, void *data)
@@ -1384,7 +1395,7 @@ struct inode *isofs_iget(struct super_block *sb,
hashval = (block << sb->s_blocksize_bits) | offset;
inode = iget5_locked(sb, hashval, &isofs_iget5_test,
- &isofs_iget5_set, &data);
+ &isofs_iget5_set, &data);
if (inode && (inode->i_state & I_NEW)) {
sb->s_op->read_inode(inode);
@@ -1398,7 +1409,7 @@ static int isofs_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
return get_sb_bdev(fs_type, flags, dev_name, data, isofs_fill_super,
- mnt);
+ mnt);
}
static struct file_system_type iso9660_fs_type = {
diff --git a/fs/isofs/joliet.c b/fs/isofs/joliet.c
index fb8fe7a9ddc..92c14b850e9 100644
--- a/fs/isofs/joliet.c
+++ b/fs/isofs/joliet.c
@@ -80,22 +80,20 @@ get_joliet_filename(struct iso_directory_record * de, unsigned char *outname, st
if (utf8) {
len = wcsntombs_be(outname, de->name,
- de->name_len[0] >> 1, PAGE_SIZE);
+ de->name_len[0] >> 1, PAGE_SIZE);
} else {
len = uni16_to_x8(outname, (__be16 *) de->name,
- de->name_len[0] >> 1, nls);
+ de->name_len[0] >> 1, nls);
}
- if ((len > 2) && (outname[len-2] == ';') && (outname[len-1] == '1')) {
+ if ((len > 2) && (outname[len-2] == ';') && (outname[len-1] == '1'))
len -= 2;
- }
/*
* Windows doesn't like periods at the end of a name,
* so neither do we
*/
- while (len >= 2 && (outname[len-1] == '.')) {
+ while (len >= 2 && (outname[len-1] == '.'))
len--;
- }
return len;
}
diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c
index c04b3a14a3e..c8c7e5138a0 100644
--- a/fs/isofs/namei.c
+++ b/fs/isofs/namei.c
@@ -15,7 +15,7 @@
* some sanity tests.
*/
static int
-isofs_cmp(struct dentry * dentry, const char * compare, int dlen)
+isofs_cmp(struct dentry *dentry, const char *compare, int dlen)
{
struct qstr qstr;
@@ -48,24 +48,24 @@ isofs_cmp(struct dentry * dentry, const char * compare, int dlen)
*/
static unsigned long
isofs_find_entry(struct inode *dir, struct dentry *dentry,
- unsigned long *block_rv, unsigned long* offset_rv,
- char * tmpname, struct iso_directory_record * tmpde)
+ unsigned long *block_rv, unsigned long *offset_rv,
+ char *tmpname, struct iso_directory_record *tmpde)
{
unsigned long bufsize = ISOFS_BUFFER_SIZE(dir);
unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
unsigned long block, f_pos, offset, block_saved, offset_saved;
- struct buffer_head * bh = NULL;
+ struct buffer_head *bh = NULL;
struct isofs_sb_info *sbi = ISOFS_SB(dir->i_sb);
if (!ISOFS_I(dir)->i_first_extent)
return 0;
-
+
f_pos = 0;
offset = 0;
block = 0;
while (f_pos < dir->i_size) {
- struct iso_directory_record * de;
+ struct iso_directory_record *de;
int de_len, match, i, dlen;
char *dpnt;
@@ -114,7 +114,7 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry,
if (sbi->s_rock &&
((i = get_rock_ridge_filename(de, tmpname, dir)))) {
- dlen = i; /* possibly -1 */
+ dlen = i; /* possibly -1 */
dpnt = tmpname;
#ifdef CONFIG_JOLIET
} else if (sbi->s_joliet_level) {
@@ -145,8 +145,8 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry,
isofs_normalize_block_and_offset(de,
&block_saved,
&offset_saved);
- *block_rv = block_saved;
- *offset_rv = offset_saved;
+ *block_rv = block_saved;
+ *offset_rv = offset_saved;
brelse(bh);
return 1;
}
@@ -155,7 +155,7 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry,
return 0;
}
-struct dentry *isofs_lookup(struct inode * dir, struct dentry * dentry, struct nameidata *nd)
+struct dentry *isofs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
{
int found;
unsigned long block, offset;
@@ -170,9 +170,9 @@ struct dentry *isofs_lookup(struct inode * dir, struct dentry * dentry, struct n
lock_kernel();
found = isofs_find_entry(dir, dentry,
- &block, &offset,
- page_address(page),
- 1024 + page_address(page));
+ &block, &offset,
+ page_address(page),
+ 1024 + page_address(page));
__free_page(page);
inode = NULL;
diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c
index 1facfaff97c..a003d50edcd 100644
--- a/fs/jbd/commit.c
+++ b/fs/jbd/commit.c
@@ -887,7 +887,8 @@ restart_loop:
journal->j_committing_transaction = NULL;
spin_unlock(&journal->j_state_lock);
- if (commit_transaction->t_checkpoint_list == NULL) {
+ if (commit_transaction->t_checkpoint_list == NULL &&
+ commit_transaction->t_checkpoint_io_list == NULL) {
__journal_drop_transaction(journal, commit_transaction);
} else {
if (journal->j_checkpoint_transactions == NULL) {
diff --git a/fs/jbd/revoke.c b/fs/jbd/revoke.c
index 824e3b7d4ec..8db2fa25170 100644
--- a/fs/jbd/revoke.c
+++ b/fs/jbd/revoke.c
@@ -68,6 +68,7 @@
#include <linux/list.h>
#include <linux/init.h>
#endif
+#include <linux/log2.h>
static struct kmem_cache *revoke_record_cache;
static struct kmem_cache *revoke_table_cache;
@@ -211,7 +212,7 @@ int journal_init_revoke(journal_t *journal, int hash_size)
journal->j_revoke = journal->j_revoke_table[0];
/* Check that the hash_size is a power of two */
- J_ASSERT ((hash_size & (hash_size-1)) == 0);
+ J_ASSERT(is_power_of_2(hash_size));
journal->j_revoke->hash_size = hash_size;
@@ -238,7 +239,7 @@ int journal_init_revoke(journal_t *journal, int hash_size)
journal->j_revoke = journal->j_revoke_table[1];
/* Check that the hash_size is a power of two */
- J_ASSERT ((hash_size & (hash_size-1)) == 0);
+ J_ASSERT(is_power_of_2(hash_size));
journal->j_revoke->hash_size = hash_size;
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
index 2856e1100a5..c0f59d1b13d 100644
--- a/fs/jbd2/commit.c
+++ b/fs/jbd2/commit.c
@@ -896,7 +896,8 @@ restart_loop:
journal->j_committing_transaction = NULL;
spin_unlock(&journal->j_state_lock);
- if (commit_transaction->t_checkpoint_list == NULL) {
+ if (commit_transaction->t_checkpoint_list == NULL &&
+ commit_transaction->t_checkpoint_io_list == NULL) {
__jbd2_journal_drop_transaction(journal, commit_transaction);
} else {
if (journal->j_checkpoint_transactions == NULL) {
diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c
index 9246e763da7..28cac049a56 100644
--- a/fs/jbd2/revoke.c
+++ b/fs/jbd2/revoke.c
@@ -68,6 +68,7 @@
#include <linux/list.h>
#include <linux/init.h>
#endif
+#include <linux/log2.h>
static struct kmem_cache *jbd2_revoke_record_cache;
static struct kmem_cache *jbd2_revoke_table_cache;
@@ -212,7 +213,7 @@ int jbd2_journal_init_revoke(journal_t *journal, int hash_size)
journal->j_revoke = journal->j_revoke_table[0];
/* Check that the hash_size is a power of two */
- J_ASSERT ((hash_size & (hash_size-1)) == 0);
+ J_ASSERT(is_power_of_2(hash_size));
journal->j_revoke->hash_size = hash_size;
@@ -239,7 +240,7 @@ int jbd2_journal_init_revoke(journal_t *journal, int hash_size)
journal->j_revoke = journal->j_revoke_table[1];
/* Check that the hash_size is a power of two */
- J_ASSERT ((hash_size & (hash_size-1)) == 0);
+ J_ASSERT(is_power_of_2(hash_size));
journal->j_revoke->hash_size = hash_size;
diff --git a/fs/namespace.c b/fs/namespace.c
index b696e3a0d18..4198003d7e1 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -28,6 +28,7 @@
#include <asm/uaccess.h>
#include <asm/unistd.h>
#include "pnode.h"
+#include "internal.h"
/* spinlock for vfsmount related operations, inplace of dcache_lock */
__cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock);
@@ -320,22 +321,16 @@ EXPORT_SYMBOL(mnt_unpin);
static void *m_start(struct seq_file *m, loff_t *pos)
{
struct mnt_namespace *n = m->private;
- struct list_head *p;
- loff_t l = *pos;
down_read(&namespace_sem);
- list_for_each(p, &n->list)
- if (!l--)
- return list_entry(p, struct vfsmount, mnt_list);
- return NULL;
+ return seq_list_start(&n->list, *pos);
}
static void *m_next(struct seq_file *m, void *v, loff_t *pos)
{
struct mnt_namespace *n = m->private;
- struct list_head *p = ((struct vfsmount *)v)->mnt_list.next;
- (*pos)++;
- return p == &n->list ? NULL : list_entry(p, struct vfsmount, mnt_list);
+
+ return seq_list_next(v, &n->list, pos);
}
static void m_stop(struct seq_file *m, void *v)
@@ -350,7 +345,7 @@ static inline void mangle(struct seq_file *m, const char *s)
static int show_vfsmnt(struct seq_file *m, void *v)
{
- struct vfsmount *mnt = v;
+ struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list);
int err = 0;
static struct proc_fs_info {
int flag;
@@ -405,7 +400,7 @@ struct seq_operations mounts_op = {
static int show_vfsstat(struct seq_file *m, void *v)
{
- struct vfsmount *mnt = v;
+ struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list);
int err = 0;
/* device */
@@ -1457,7 +1452,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL);
if (!new_ns)
- return NULL;
+ return ERR_PTR(-ENOMEM);
atomic_set(&new_ns->count, 1);
INIT_LIST_HEAD(&new_ns->list);
@@ -1471,7 +1466,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
if (!new_ns->root) {
up_write(&namespace_sem);
kfree(new_ns);
- return NULL;
+ return ERR_PTR(-ENOMEM);;
}
spin_lock(&vfsmount_lock);
list_add_tail(&new_ns->list, &new_ns->root->mnt_list);
@@ -1515,7 +1510,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
return new_ns;
}
-struct mnt_namespace *copy_mnt_ns(int flags, struct mnt_namespace *ns,
+struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns,
struct fs_struct *new_fs)
{
struct mnt_namespace *new_ns;
diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c
index d3152f8d95c..2b145de45b3 100644
--- a/fs/ncpfs/file.c
+++ b/fs/ncpfs/file.c
@@ -203,7 +203,6 @@ ncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t *
if (pos + count > MAX_NON_LFS && !(file->f_flags&O_LARGEFILE)) {
if (pos >= MAX_NON_LFS) {
- send_sig(SIGXFSZ, current, 0);
return -EFBIG;
}
if (count > MAX_NON_LFS - (u32)pos) {
@@ -212,7 +211,6 @@ ncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t *
}
if (pos >= inode->i_sb->s_maxbytes) {
if (count || pos > inode->i_sb->s_maxbytes) {
- send_sig(SIGXFSZ, current, 0);
return -EFBIG;
}
}
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index ccb455053ee..a49f9feff77 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -1206,23 +1206,9 @@ static int nfs_server_list_open(struct inode *inode, struct file *file)
*/
static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos)
{
- struct list_head *_p;
- loff_t pos = *_pos;
-
/* lock the list against modification */
spin_lock(&nfs_client_lock);
-
- /* allow for the header line */
- if (!pos)
- return SEQ_START_TOKEN;
- pos--;
-
- /* find the n'th element in the list */
- list_for_each(_p, &nfs_client_list)
- if (!pos--)
- break;
-
- return _p != &nfs_client_list ? _p : NULL;
+ return seq_list_start_head(&nfs_client_list, *_pos);
}
/*
@@ -1230,14 +1216,7 @@ static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos)
*/
static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos)
{
- struct list_head *_p;
-
- (*pos)++;
-
- _p = v;
- _p = (v == SEQ_START_TOKEN) ? nfs_client_list.next : _p->next;
-
- return _p != &nfs_client_list ? _p : NULL;
+ return seq_list_next(v, &nfs_client_list, pos);
}
/*
@@ -1256,7 +1235,7 @@ static int nfs_server_list_show(struct seq_file *m, void *v)
struct nfs_client *clp;
/* display header on line 1 */
- if (v == SEQ_START_TOKEN) {
+ if (v == &nfs_client_list) {
seq_puts(m, "NV SERVER PORT USE HOSTNAME\n");
return 0;
}
@@ -1297,23 +1276,9 @@ static int nfs_volume_list_open(struct inode *inode, struct file *file)
*/
static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos)
{
- struct list_head *_p;
- loff_t pos = *_pos;
-
/* lock the list against modification */
spin_lock(&nfs_client_lock);
-
- /* allow for the header line */
- if (!pos)
- return SEQ_START_TOKEN;
- pos--;
-
- /* find the n'th element in the list */
- list_for_each(_p, &nfs_volume_list)
- if (!pos--)
- break;
-
- return _p != &nfs_volume_list ? _p : NULL;
+ return seq_list_start_head(&nfs_volume_list, *_pos);
}
/*
@@ -1321,14 +1286,7 @@ static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos)
*/
static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos)
{
- struct list_head *_p;
-
- (*pos)++;
-
- _p = v;
- _p = (v == SEQ_START_TOKEN) ? nfs_volume_list.next : _p->next;
-
- return _p != &nfs_volume_list ? _p : NULL;
+ return seq_list_next(v, &nfs_volume_list, pos);
}
/*
@@ -1349,7 +1307,7 @@ static int nfs_volume_list_show(struct seq_file *m, void *v)
char dev[8], fsid[17];
/* display header on line 1 */
- if (v == SEQ_START_TOKEN) {
+ if (v == &nfs_volume_list) {
seq_puts(m, "NV SERVER PORT DEV FSID\n");
return 0;
}
diff --git a/fs/nls/Makefile b/fs/nls/Makefile
index a7ade138d68..f499dd7c390 100644
--- a/fs/nls/Makefile
+++ b/fs/nls/Makefile
@@ -36,11 +36,9 @@ obj-$(CONFIG_NLS_ISO8859_6) += nls_iso8859-6.o
obj-$(CONFIG_NLS_ISO8859_7) += nls_iso8859-7.o
obj-$(CONFIG_NLS_ISO8859_8) += nls_cp1255.o
obj-$(CONFIG_NLS_ISO8859_9) += nls_iso8859-9.o
-obj-$(CONFIG_NLS_ISO8859_10) += nls_iso8859-10.o
obj-$(CONFIG_NLS_ISO8859_13) += nls_iso8859-13.o
obj-$(CONFIG_NLS_ISO8859_14) += nls_iso8859-14.o
obj-$(CONFIG_NLS_ISO8859_15) += nls_iso8859-15.o
obj-$(CONFIG_NLS_KOI8_R) += nls_koi8-r.o
obj-$(CONFIG_NLS_KOI8_U) += nls_koi8-u.o nls_koi8-ru.o
-obj-$(CONFIG_NLS_ABC) += nls_abc.o
obj-$(CONFIG_NLS_UTF8) += nls_utf8.o
diff --git a/fs/open.c b/fs/open.c
index 0d515d16197..be6a457f422 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -855,7 +855,7 @@ EXPORT_SYMBOL(dentry_open);
/*
* Find an empty file descriptor entry, and mark it busy.
*/
-int get_unused_fd(void)
+int get_unused_fd_flags(int flags)
{
struct files_struct * files = current->files;
int fd, error;
@@ -891,7 +891,10 @@ repeat:
}
FD_SET(fd, fdt->open_fds);
- FD_CLR(fd, fdt->close_on_exec);
+ if (flags & O_CLOEXEC)
+ FD_SET(fd, fdt->close_on_exec);
+ else
+ FD_CLR(fd, fdt->close_on_exec);
files->next_fd = fd + 1;
#if 1
/* Sanity check */
@@ -907,6 +910,11 @@ out:
return error;
}
+int get_unused_fd(void)
+{
+ return get_unused_fd_flags(0);
+}
+
EXPORT_SYMBOL(get_unused_fd);
static void __put_unused_fd(struct files_struct *files, unsigned int fd)
@@ -959,7 +967,7 @@ long do_sys_open(int dfd, const char __user *filename, int flags, int mode)
int fd = PTR_ERR(tmp);
if (!IS_ERR(tmp)) {
- fd = get_unused_fd();
+ fd = get_unused_fd_flags(flags);
if (fd >= 0) {
struct file *f = do_filp_open(dfd, tmp, flags, mode);
if (IS_ERR(f)) {
diff --git a/fs/partitions/acorn.c b/fs/partitions/acorn.c
index e3491328596..3d3e1663147 100644
--- a/fs/partitions/acorn.c
+++ b/fs/partitions/acorn.c
@@ -25,6 +25,8 @@
#define PARTITION_RISCIX_SCSI 2
#define PARTITION_LINUX 9
+#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \
+ defined(CONFIG_ACORN_PARTITION_ADFS)
static struct adfs_discrecord *
adfs_partition(struct parsed_partitions *state, char *name, char *data,
unsigned long first_sector, int slot)
@@ -48,6 +50,7 @@ adfs_partition(struct parsed_partitions *state, char *name, char *data,
put_partition(state, slot, first_sector, nr_sects);
return dr;
}
+#endif
#ifdef CONFIG_ACORN_PARTITION_RISCIX
@@ -65,6 +68,8 @@ struct riscix_record {
struct riscix_part part[8];
};
+#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \
+ defined(CONFIG_ACORN_PARTITION_ADFS)
static int
riscix_partition(struct parsed_partitions *state, struct block_device *bdev,
unsigned long first_sect, int slot, unsigned long nr_sects)
@@ -105,6 +110,7 @@ riscix_partition(struct parsed_partitions *state, struct block_device *bdev,
return slot;
}
#endif
+#endif
#define LINUX_NATIVE_MAGIC 0xdeafa1de
#define LINUX_SWAP_MAGIC 0xdeafab1e
@@ -115,6 +121,8 @@ struct linux_part {
__le32 nr_sects;
};
+#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \
+ defined(CONFIG_ACORN_PARTITION_ADFS)
static int
linux_partition(struct parsed_partitions *state, struct block_device *bdev,
unsigned long first_sect, int slot, unsigned long nr_sects)
@@ -146,6 +154,7 @@ linux_partition(struct parsed_partitions *state, struct block_device *bdev,
put_dev_sector(sect);
return slot;
}
+#endif
#ifdef CONFIG_ACORN_PARTITION_CUMANA
int
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 98e78e2f18d..9cbab7e9355 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -289,6 +289,15 @@ static inline char *task_cap(struct task_struct *p, char *buffer)
cap_t(p->cap_effective));
}
+static inline char *task_context_switch_counts(struct task_struct *p,
+ char *buffer)
+{
+ return buffer + sprintf(buffer, "voluntary_ctxt_switches:\t%lu\n"
+ "nonvoluntary_ctxt_switches:\t%lu\n",
+ p->nvcsw,
+ p->nivcsw);
+}
+
int proc_pid_status(struct task_struct *task, char * buffer)
{
char * orig = buffer;
@@ -307,6 +316,7 @@ int proc_pid_status(struct task_struct *task, char * buffer)
#if defined(CONFIG_S390)
buffer = task_show_regs(task, buffer);
#endif
+ buffer = task_context_switch_counts(task, buffer);
return buffer - orig;
}
@@ -440,8 +450,9 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole)
/* Temporary variable needed for gcc-2.96 */
/* convert timespec -> nsec*/
- start_time = (unsigned long long)task->start_time.tv_sec * NSEC_PER_SEC
- + task->start_time.tv_nsec;
+ start_time =
+ (unsigned long long)task->real_start_time.tv_sec * NSEC_PER_SEC
+ + task->real_start_time.tv_nsec;
/* convert nsec -> ticks */
start_time = nsec_to_clock_t(start_time);
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 46ea5d56e1b..ae3627337a9 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -67,7 +67,6 @@
#include <linux/mount.h>
#include <linux/security.h>
#include <linux/ptrace.h>
-#include <linux/seccomp.h>
#include <linux/cpuset.h>
#include <linux/audit.h>
#include <linux/poll.h>
@@ -204,12 +203,17 @@ static int proc_pid_environ(struct task_struct *task, char * buffer)
int res = 0;
struct mm_struct *mm = get_task_mm(task);
if (mm) {
- unsigned int len = mm->env_end - mm->env_start;
+ unsigned int len;
+
+ res = -ESRCH;
+ if (!ptrace_may_attach(task))
+ goto out;
+
+ len = mm->env_end - mm->env_start;
if (len > PAGE_SIZE)
len = PAGE_SIZE;
res = access_process_vm(task, mm->env_start, buffer, len, 0);
- if (!ptrace_may_attach(task))
- res = -ESRCH;
+out:
mmput(mm);
}
return res;
@@ -812,71 +816,6 @@ static const struct file_operations proc_loginuid_operations = {
};
#endif
-#ifdef CONFIG_SECCOMP
-static ssize_t seccomp_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct task_struct *tsk = get_proc_task(file->f_dentry->d_inode);
- char __buf[20];
- size_t len;
-
- if (!tsk)
- return -ESRCH;
- /* no need to print the trailing zero, so use only len */
- len = sprintf(__buf, "%u\n", tsk->seccomp.mode);
- put_task_struct(tsk);
-
- return simple_read_from_buffer(buf, count, ppos, __buf, len);
-}
-
-static ssize_t seccomp_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct task_struct *tsk = get_proc_task(file->f_dentry->d_inode);
- char __buf[20], *end;
- unsigned int seccomp_mode;
- ssize_t result;
-
- result = -ESRCH;
- if (!tsk)
- goto out_no_task;
-
- /* can set it only once to be even more secure */
- result = -EPERM;
- if (unlikely(tsk->seccomp.mode))
- goto out;
-
- result = -EFAULT;
- memset(__buf, 0, sizeof(__buf));
- count = min(count, sizeof(__buf) - 1);
- if (copy_from_user(__buf, buf, count))
- goto out;
-
- seccomp_mode = simple_strtoul(__buf, &end, 0);
- if (*end == '\n')
- end++;
- result = -EINVAL;
- if (seccomp_mode && seccomp_mode <= NR_SECCOMP_MODES) {
- tsk->seccomp.mode = seccomp_mode;
- set_tsk_thread_flag(tsk, TIF_SECCOMP);
- } else
- goto out;
- result = -EIO;
- if (unlikely(!(end - __buf)))
- goto out;
- result = end - __buf;
-out:
- put_task_struct(tsk);
-out_no_task:
- return result;
-}
-
-static const struct file_operations proc_seccomp_operations = {
- .read = seccomp_read,
- .write = seccomp_write,
-};
-#endif /* CONFIG_SECCOMP */
-
#ifdef CONFIG_FAULT_INJECTION
static ssize_t proc_fault_inject_read(struct file * file, char __user * buf,
size_t count, loff_t *ppos)
@@ -2037,9 +1976,6 @@ static const struct pid_entry tgid_base_stuff[] = {
REG("numa_maps", S_IRUGO, numa_maps),
#endif
REG("mem", S_IRUSR|S_IWUSR, mem),
-#ifdef CONFIG_SECCOMP
- REG("seccomp", S_IRUSR|S_IWUSR, seccomp),
-#endif
LNK("cwd", cwd),
LNK("root", root),
LNK("exe", exe),
@@ -2324,9 +2260,6 @@ static const struct pid_entry tid_base_stuff[] = {
REG("numa_maps", S_IRUGO, numa_maps),
#endif
REG("mem", S_IRUSR|S_IWUSR, mem),
-#ifdef CONFIG_SECCOMP
- REG("seccomp", S_IRUSR|S_IWUSR, seccomp),
-#endif
LNK("cwd", cwd),
LNK("root", root),
LNK("exe", exe),
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 8a40e15f5ec..b5e7155d30d 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -20,6 +20,7 @@
#include <linux/namei.h>
#include <linux/bitops.h>
#include <linux/spinlock.h>
+#include <linux/completion.h>
#include <asm/uaccess.h>
#include "internal.h"
@@ -529,12 +530,6 @@ static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp
return -EAGAIN;
dp->low_ino = i;
- spin_lock(&proc_subdir_lock);
- dp->next = dir->subdir;
- dp->parent = dir;
- dir->subdir = dp;
- spin_unlock(&proc_subdir_lock);
-
if (S_ISDIR(dp->mode)) {
if (dp->proc_iops == NULL) {
dp->proc_fops = &proc_dir_operations;
@@ -550,6 +545,13 @@ static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp
if (dp->proc_iops == NULL)
dp->proc_iops = &proc_file_inode_operations;
}
+
+ spin_lock(&proc_subdir_lock);
+ dp->next = dir->subdir;
+ dp->parent = dir;
+ dir->subdir = dp;
+ spin_unlock(&proc_subdir_lock);
+
return 0;
}
@@ -613,6 +615,9 @@ static struct proc_dir_entry *proc_create(struct proc_dir_entry **parent,
ent->namelen = len;
ent->mode = mode;
ent->nlink = nlink;
+ ent->pde_users = 0;
+ spin_lock_init(&ent->pde_unload_lock);
+ ent->pde_unload_completion = NULL;
out:
return ent;
}
@@ -649,9 +654,6 @@ struct proc_dir_entry *proc_mkdir_mode(const char *name, mode_t mode,
ent = proc_create(&parent, name, S_IFDIR | mode, 2);
if (ent) {
- ent->proc_fops = &proc_dir_operations;
- ent->proc_iops = &proc_dir_inode_operations;
-
if (proc_register(parent, ent) < 0) {
kfree(ent);
ent = NULL;
@@ -686,10 +688,6 @@ struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
ent = proc_create(&parent,name,mode,nlink);
if (ent) {
- if (S_ISDIR(mode)) {
- ent->proc_fops = &proc_dir_operations;
- ent->proc_iops = &proc_dir_inode_operations;
- }
if (proc_register(parent, ent) < 0) {
kfree(ent);
ent = NULL;
@@ -734,9 +732,35 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
de = *p;
*p = de->next;
de->next = NULL;
+
+ spin_lock(&de->pde_unload_lock);
+ /*
+ * Stop accepting new callers into module. If you're
+ * dynamically allocating ->proc_fops, save a pointer somewhere.
+ */
+ de->proc_fops = NULL;
+ /* Wait until all existing callers into module are done. */
+ if (de->pde_users > 0) {
+ DECLARE_COMPLETION_ONSTACK(c);
+
+ if (!de->pde_unload_completion)
+ de->pde_unload_completion = &c;
+
+ spin_unlock(&de->pde_unload_lock);
+ spin_unlock(&proc_subdir_lock);
+
+ wait_for_completion(de->pde_unload_completion);
+
+ spin_lock(&proc_subdir_lock);
+ goto continue_removing;
+ }
+ spin_unlock(&de->pde_unload_lock);
+
+continue_removing:
if (S_ISDIR(de->mode))
parent->nlink--;
- proc_kill_inodes(de);
+ if (!S_ISREG(de->mode))
+ proc_kill_inodes(de);
de->nlink = 0;
WARN_ON(de->subdir);
if (!atomic_read(&de->count))
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index d5ce65c68d7..dd28e86ab42 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -10,6 +10,7 @@
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/stat.h>
+#include <linux/completion.h>
#include <linux/file.h>
#include <linux/limits.h>
#include <linux/init.h>
@@ -140,6 +141,251 @@ static const struct super_operations proc_sops = {
.remount_fs = proc_remount,
};
+static void pde_users_dec(struct proc_dir_entry *pde)
+{
+ spin_lock(&pde->pde_unload_lock);
+ pde->pde_users--;
+ if (pde->pde_unload_completion && pde->pde_users == 0)
+ complete(pde->pde_unload_completion);
+ spin_unlock(&pde->pde_unload_lock);
+}
+
+static loff_t proc_reg_llseek(struct file *file, loff_t offset, int whence)
+{
+ struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
+ loff_t rv = -EINVAL;
+ loff_t (*llseek)(struct file *, loff_t, int);
+
+ spin_lock(&pde->pde_unload_lock);
+ /*
+ * remove_proc_entry() is going to delete PDE (as part of module
+ * cleanup sequence). No new callers into module allowed.
+ */
+ if (!pde->proc_fops) {
+ spin_unlock(&pde->pde_unload_lock);
+ return rv;
+ }
+ /*
+ * Bump refcount so that remove_proc_entry will wail for ->llseek to
+ * complete.
+ */
+ pde->pde_users++;
+ /*
+ * Save function pointer under lock, to protect against ->proc_fops
+ * NULL'ifying right after ->pde_unload_lock is dropped.
+ */
+ llseek = pde->proc_fops->llseek;
+ spin_unlock(&pde->pde_unload_lock);
+
+ if (!llseek)
+ llseek = default_llseek;
+ rv = llseek(file, offset, whence);
+
+ pde_users_dec(pde);
+ return rv;
+}
+
+static ssize_t proc_reg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+{
+ struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
+ ssize_t rv = -EIO;
+ ssize_t (*read)(struct file *, char __user *, size_t, loff_t *);
+
+ spin_lock(&pde->pde_unload_lock);
+ if (!pde->proc_fops) {
+ spin_unlock(&pde->pde_unload_lock);
+ return rv;
+ }
+ pde->pde_users++;
+ read = pde->proc_fops->read;
+ spin_unlock(&pde->pde_unload_lock);
+
+ if (read)
+ rv = read(file, buf, count, ppos);
+
+ pde_users_dec(pde);
+ return rv;
+}
+
+static ssize_t proc_reg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+{
+ struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
+ ssize_t rv = -EIO;
+ ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *);
+
+ spin_lock(&pde->pde_unload_lock);
+ if (!pde->proc_fops) {
+ spin_unlock(&pde->pde_unload_lock);
+ return rv;
+ }
+ pde->pde_users++;
+ write = pde->proc_fops->write;
+ spin_unlock(&pde->pde_unload_lock);
+
+ if (write)
+ rv = write(file, buf, count, ppos);
+
+ pde_users_dec(pde);
+ return rv;
+}
+
+static unsigned int proc_reg_poll(struct file *file, struct poll_table_struct *pts)
+{
+ struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
+ unsigned int rv = 0;
+ unsigned int (*poll)(struct file *, struct poll_table_struct *);
+
+ spin_lock(&pde->pde_unload_lock);
+ if (!pde->proc_fops) {
+ spin_unlock(&pde->pde_unload_lock);
+ return rv;
+ }
+ pde->pde_users++;
+ poll = pde->proc_fops->poll;
+ spin_unlock(&pde->pde_unload_lock);
+
+ if (poll)
+ rv = poll(file, pts);
+
+ pde_users_dec(pde);
+ return rv;
+}
+
+static long proc_reg_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
+ long rv = -ENOTTY;
+ long (*unlocked_ioctl)(struct file *, unsigned int, unsigned long);
+ int (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long);
+
+ spin_lock(&pde->pde_unload_lock);
+ if (!pde->proc_fops) {
+ spin_unlock(&pde->pde_unload_lock);
+ return rv;
+ }
+ pde->pde_users++;
+ unlocked_ioctl = pde->proc_fops->unlocked_ioctl;
+ ioctl = pde->proc_fops->ioctl;
+ spin_unlock(&pde->pde_unload_lock);
+
+ if (unlocked_ioctl) {
+ rv = unlocked_ioctl(file, cmd, arg);
+ if (rv == -ENOIOCTLCMD)
+ rv = -EINVAL;
+ } else if (ioctl) {
+ lock_kernel();
+ rv = ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
+ unlock_kernel();
+ }
+
+ pde_users_dec(pde);
+ return rv;
+}
+
+#ifdef CONFIG_COMPAT
+static long proc_reg_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
+ long rv = -ENOTTY;
+ long (*compat_ioctl)(struct file *, unsigned int, unsigned long);
+
+ spin_lock(&pde->pde_unload_lock);
+ if (!pde->proc_fops) {
+ spin_unlock(&pde->pde_unload_lock);
+ return rv;
+ }
+ pde->pde_users++;
+ compat_ioctl = pde->proc_fops->compat_ioctl;
+ spin_unlock(&pde->pde_unload_lock);
+
+ if (compat_ioctl)
+ rv = compat_ioctl(file, cmd, arg);
+
+ pde_users_dec(pde);
+ return rv;
+}
+#endif
+
+static int proc_reg_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
+ int rv = -EIO;
+ int (*mmap)(struct file *, struct vm_area_struct *);
+
+ spin_lock(&pde->pde_unload_lock);
+ if (!pde->proc_fops) {
+ spin_unlock(&pde->pde_unload_lock);
+ return rv;
+ }
+ pde->pde_users++;
+ mmap = pde->proc_fops->mmap;
+ spin_unlock(&pde->pde_unload_lock);
+
+ if (mmap)
+ rv = mmap(file, vma);
+
+ pde_users_dec(pde);
+ return rv;
+}
+
+static int proc_reg_open(struct inode *inode, struct file *file)
+{
+ struct proc_dir_entry *pde = PDE(inode);
+ int rv = 0;
+ int (*open)(struct inode *, struct file *);
+
+ spin_lock(&pde->pde_unload_lock);
+ if (!pde->proc_fops) {
+ spin_unlock(&pde->pde_unload_lock);
+ return rv;
+ }
+ pde->pde_users++;
+ open = pde->proc_fops->open;
+ spin_unlock(&pde->pde_unload_lock);
+
+ if (open)
+ rv = open(inode, file);
+
+ pde_users_dec(pde);
+ return rv;
+}
+
+static int proc_reg_release(struct inode *inode, struct file *file)
+{
+ struct proc_dir_entry *pde = PDE(inode);
+ int rv = 0;
+ int (*release)(struct inode *, struct file *);
+
+ spin_lock(&pde->pde_unload_lock);
+ if (!pde->proc_fops) {
+ spin_unlock(&pde->pde_unload_lock);
+ return rv;
+ }
+ pde->pde_users++;
+ release = pde->proc_fops->release;
+ spin_unlock(&pde->pde_unload_lock);
+
+ if (release)
+ rv = release(inode, file);
+
+ pde_users_dec(pde);
+ return rv;
+}
+
+static const struct file_operations proc_reg_file_ops = {
+ .llseek = proc_reg_llseek,
+ .read = proc_reg_read,
+ .write = proc_reg_write,
+ .poll = proc_reg_poll,
+ .unlocked_ioctl = proc_reg_unlocked_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = proc_reg_compat_ioctl,
+#endif
+ .mmap = proc_reg_mmap,
+ .open = proc_reg_open,
+ .release = proc_reg_release,
+};
+
struct inode *proc_get_inode(struct super_block *sb, unsigned int ino,
struct proc_dir_entry *de)
{
@@ -166,8 +412,12 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino,
inode->i_nlink = de->nlink;
if (de->proc_iops)
inode->i_op = de->proc_iops;
- if (de->proc_fops)
- inode->i_fop = de->proc_fops;
+ if (de->proc_fops) {
+ if (S_ISREG(inode->i_mode))
+ inode->i_fop = &proc_reg_file_ops;
+ else
+ inode->i_fop = de->proc_fops;
+ }
}
return inode;
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index 5fd49e47f83..d24b8d46059 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -105,6 +105,7 @@ static int uptime_read_proc(char *page, char **start, off_t off,
cputime_t idletime = cputime_add(init_task.utime, init_task.stime);
do_posix_clock_monotonic_gettime(&uptime);
+ monotonic_to_bootbased(&uptime);
cputime_to_timespec(idletime, &idle);
len = sprintf(page,"%lu.%02lu %lu.%02lu\n",
(unsigned long) uptime.tv_sec,
@@ -443,12 +444,12 @@ static int show_stat(struct seq_file *p, void *v)
unsigned long jif;
cputime64_t user, nice, system, idle, iowait, irq, softirq, steal;
u64 sum = 0;
+ struct timespec boottime;
user = nice = system = idle = iowait =
irq = softirq = steal = cputime64_zero;
- jif = - wall_to_monotonic.tv_sec;
- if (wall_to_monotonic.tv_nsec)
- --jif;
+ getboottime(&boottime);
+ jif = boottime.tv_sec;
for_each_possible_cpu(i) {
int j;
diff --git a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c
index b3a473b0a19..22846225acf 100644
--- a/fs/proc/proc_tty.c
+++ b/fs/proc/proc_tty.c
@@ -69,7 +69,7 @@ static void show_tty_range(struct seq_file *m, struct tty_driver *p,
static int show_tty_driver(struct seq_file *m, void *v)
{
- struct tty_driver *p = v;
+ struct tty_driver *p = list_entry(v, struct tty_driver, tty_drivers);
dev_t from = MKDEV(p->major, p->minor_start);
dev_t to = from + p->num;
@@ -106,22 +106,13 @@ static int show_tty_driver(struct seq_file *m, void *v)
/* iterator */
static void *t_start(struct seq_file *m, loff_t *pos)
{
- struct list_head *p;
- loff_t l = *pos;
-
mutex_lock(&tty_mutex);
- list_for_each(p, &tty_drivers)
- if (!l--)
- return list_entry(p, struct tty_driver, tty_drivers);
- return NULL;
+ return seq_list_start(&tty_drivers, *pos);
}
static void *t_next(struct seq_file *m, void *v, loff_t *pos)
{
- struct list_head *p = ((struct tty_driver *)v)->tty_drivers.next;
- (*pos)++;
- return p==&tty_drivers ? NULL :
- list_entry(p, struct tty_driver, tty_drivers);
+ return seq_list_next(v, &tty_drivers, pos);
}
static void t_stop(struct seq_file *m, void *v)
diff --git a/fs/quota.c b/fs/quota.c
index 9f237d6182c..e6577ac15a6 100644
--- a/fs/quota.c
+++ b/fs/quota.c
@@ -10,12 +10,14 @@
#include <linux/slab.h>
#include <asm/current.h>
#include <asm/uaccess.h>
+#include <linux/compat.h>
#include <linux/kernel.h>
#include <linux/security.h>
#include <linux/syscalls.h>
#include <linux/buffer_head.h>
#include <linux/capability.h>
#include <linux/quotaops.h>
+#include <linux/types.h>
/* Check validity of generic quotactl commands */
static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id)
@@ -384,3 +386,119 @@ asmlinkage long sys_quotactl(unsigned int cmd, const char __user *special, qid_t
return ret;
}
+
+#if defined(CONFIG_X86_64) || defined(CONFIG_IA64)
+/*
+ * This code works only for 32 bit quota tools over 64 bit OS (x86_64, ia64)
+ * and is necessary due to alignment problems.
+ */
+struct compat_if_dqblk {
+ compat_u64 dqb_bhardlimit;
+ compat_u64 dqb_bsoftlimit;
+ compat_u64 dqb_curspace;
+ compat_u64 dqb_ihardlimit;
+ compat_u64 dqb_isoftlimit;
+ compat_u64 dqb_curinodes;
+ compat_u64 dqb_btime;
+ compat_u64 dqb_itime;
+ compat_uint_t dqb_valid;
+};
+
+/* XFS structures */
+struct compat_fs_qfilestat {
+ compat_u64 dqb_bhardlimit;
+ compat_u64 qfs_nblks;
+ compat_uint_t qfs_nextents;
+};
+
+struct compat_fs_quota_stat {
+ __s8 qs_version;
+ __u16 qs_flags;
+ __s8 qs_pad;
+ struct compat_fs_qfilestat qs_uquota;
+ struct compat_fs_qfilestat qs_gquota;
+ compat_uint_t qs_incoredqs;
+ compat_int_t qs_btimelimit;
+ compat_int_t qs_itimelimit;
+ compat_int_t qs_rtbtimelimit;
+ __u16 qs_bwarnlimit;
+ __u16 qs_iwarnlimit;
+};
+
+asmlinkage long sys32_quotactl(unsigned int cmd, const char __user *special,
+ qid_t id, void __user *addr)
+{
+ unsigned int cmds;
+ struct if_dqblk __user *dqblk;
+ struct compat_if_dqblk __user *compat_dqblk;
+ struct fs_quota_stat __user *fsqstat;
+ struct compat_fs_quota_stat __user *compat_fsqstat;
+ compat_uint_t data;
+ u16 xdata;
+ long ret;
+
+ cmds = cmd >> SUBCMDSHIFT;
+
+ switch (cmds) {
+ case Q_GETQUOTA:
+ dqblk = compat_alloc_user_space(sizeof(struct if_dqblk));
+ compat_dqblk = addr;
+ ret = sys_quotactl(cmd, special, id, dqblk);
+ if (ret)
+ break;
+ if (copy_in_user(compat_dqblk, dqblk, sizeof(*compat_dqblk)) ||
+ get_user(data, &dqblk->dqb_valid) ||
+ put_user(data, &compat_dqblk->dqb_valid))
+ ret = -EFAULT;
+ break;
+ case Q_SETQUOTA:
+ dqblk = compat_alloc_user_space(sizeof(struct if_dqblk));
+ compat_dqblk = addr;
+ ret = -EFAULT;
+ if (copy_in_user(dqblk, compat_dqblk, sizeof(*compat_dqblk)) ||
+ get_user(data, &compat_dqblk->dqb_valid) ||
+ put_user(data, &dqblk->dqb_valid))
+ break;
+ ret = sys_quotactl(cmd, special, id, dqblk);
+ break;
+ case Q_XGETQSTAT:
+ fsqstat = compat_alloc_user_space(sizeof(struct fs_quota_stat));
+ compat_fsqstat = addr;
+ ret = sys_quotactl(cmd, special, id, fsqstat);
+ if (ret)
+ break;
+ ret = -EFAULT;
+ /* Copying qs_version, qs_flags, qs_pad */
+ if (copy_in_user(compat_fsqstat, fsqstat,
+ offsetof(struct compat_fs_quota_stat, qs_uquota)))
+ break;
+ /* Copying qs_uquota */
+ if (copy_in_user(&compat_fsqstat->qs_uquota,
+ &fsqstat->qs_uquota,
+ sizeof(compat_fsqstat->qs_uquota)) ||
+ get_user(data, &fsqstat->qs_uquota.qfs_nextents) ||
+ put_user(data, &compat_fsqstat->qs_uquota.qfs_nextents))
+ break;
+ /* Copying qs_gquota */
+ if (copy_in_user(&compat_fsqstat->qs_gquota,
+ &fsqstat->qs_gquota,
+ sizeof(compat_fsqstat->qs_gquota)) ||
+ get_user(data, &fsqstat->qs_gquota.qfs_nextents) ||
+ put_user(data, &compat_fsqstat->qs_gquota.qfs_nextents))
+ break;
+ /* Copying the rest */
+ if (copy_in_user(&compat_fsqstat->qs_incoredqs,
+ &fsqstat->qs_incoredqs,
+ sizeof(struct compat_fs_quota_stat) -
+ offsetof(struct compat_fs_quota_stat, qs_incoredqs)) ||
+ get_user(xdata, &fsqstat->qs_iwarnlimit) ||
+ put_user(xdata, &compat_fsqstat->qs_iwarnlimit))
+ break;
+ ret = 0;
+ break;
+ default:
+ ret = sys_quotactl(cmd, special, id, addr);
+ }
+ return ret;
+}
+#endif
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c
index 30eebfb1b2d..2070aeee2a5 100644
--- a/fs/reiserfs/file.c
+++ b/fs/reiserfs/file.c
@@ -1305,7 +1305,6 @@ static ssize_t reiserfs_file_write(struct file *file, /* the file we are going t
if (get_inode_item_key_version (inode) == KEY_FORMAT_3_5 &&
*ppos + count > MAX_NON_LFS) {
if (*ppos >= MAX_NON_LFS) {
- send_sig(SIGXFSZ, current, 0);
return -EFBIG;
}
if (count > MAX_NON_LFS - (unsigned long)*ppos)
diff --git a/fs/seq_file.c b/fs/seq_file.c
index 49194a4e6b9..bbb19be260c 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -177,21 +177,23 @@ EXPORT_SYMBOL(seq_read);
static int traverse(struct seq_file *m, loff_t offset)
{
- loff_t pos = 0;
+ loff_t pos = 0, index;
int error = 0;
void *p;
m->version = 0;
- m->index = 0;
+ index = 0;
m->count = m->from = 0;
- if (!offset)
+ if (!offset) {
+ m->index = index;
return 0;
+ }
if (!m->buf) {
m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
if (!m->buf)
return -ENOMEM;
}
- p = m->op->start(m, &m->index);
+ p = m->op->start(m, &index);
while (p) {
error = PTR_ERR(p);
if (IS_ERR(p))
@@ -204,15 +206,17 @@ static int traverse(struct seq_file *m, loff_t offset)
if (pos + m->count > offset) {
m->from = offset - pos;
m->count -= m->from;
+ m->index = index;
break;
}
pos += m->count;
m->count = 0;
if (pos == offset) {
- m->index++;
+ index++;
+ m->index = index;
break;
}
- p = m->op->next(m, p, &m->index);
+ p = m->op->next(m, p, &index);
}
m->op->stop(m, p);
return error;
@@ -260,8 +264,8 @@ loff_t seq_lseek(struct file *file, loff_t offset, int origin)
}
}
}
- mutex_unlock(&m->lock);
file->f_version = m->version;
+ mutex_unlock(&m->lock);
return retval;
}
EXPORT_SYMBOL(seq_lseek);
diff --git a/fs/super.c b/fs/super.c
index 5260d620c55..fc8ebedc6be 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -884,6 +884,7 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void
error = type->get_sb(type, flags, name, data, mnt);
if (error < 0)
goto out_free_secdata;
+ BUG_ON(!mnt->mnt_sb);
error = security_sb_kern_mount(mnt->mnt_sb, secdata);
if (error)
diff --git a/fs/udf/crc.c b/fs/udf/crc.c
index 1b82a4adc2f..ef2bfaa19d7 100644
--- a/fs/udf/crc.c
+++ b/fs/udf/crc.c
@@ -106,8 +106,8 @@ int main(void)
{
unsigned short x;
- x = udf_crc16(bytes, sizeof bytes);
- printf("udf_crc16: calculated = %4.4x, correct = %4.4x\n", x, 0x3299U);
+ x = udf_crc(bytes, sizeof bytes);
+ printf("udf_crc: calculated = %4.4x, correct = %4.4x\n", x, 0x3299U);
return 0;
}
diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c
index 8206983f2eb..10f3188738a 100644
--- a/fs/udf/ialloc.c
+++ b/fs/udf/ialloc.c
@@ -50,7 +50,7 @@ void udf_free_inode(struct inode * inode)
else
UDF_SB_LVIDIU(sb)->numFiles =
cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) - 1);
-
+
mark_buffer_dirty(sbi->s_lvidbh);
}
mutex_unlock(&sbi->s_alloc_mutex);
@@ -136,6 +136,13 @@ struct inode * udf_new_inode (struct inode *dir, int mode, int * err)
UDF_I_EFE(inode) = 0;
UDF_I_DATA(inode) = kzalloc(inode->i_sb->s_blocksize - sizeof(struct fileEntry), GFP_KERNEL);
}
+ if (!UDF_I_DATA(inode))
+ {
+ iput(inode);
+ *err = -ENOMEM;
+ mutex_unlock(&sbi->s_alloc_mutex);
+ return NULL;
+ }
if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_AD_IN_ICB))
UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB;
else if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD))
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index bf7de0bdbab..5b82e489af7 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -49,6 +49,7 @@ MODULE_LICENSE("GPL");
static mode_t udf_convert_permissions(struct fileEntry *);
static int udf_update_inode(struct inode *, int);
static void udf_fill_inode(struct inode *, struct buffer_head *);
+static int udf_alloc_i_data(struct inode *inode, size_t size);
static struct buffer_head *inode_getblk(struct inode *, sector_t, int *,
long *, int *);
static int8_t udf_insert_aext(struct inode *, struct extent_position,
@@ -734,7 +735,7 @@ static void udf_split_extents(struct inode *inode, int *c, int offset, int newbl
(*c) ++;
(*endnum) ++;
}
-
+
laarr[curr].extLocation.logicalBlockNum = newblocknum;
if (etype == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
laarr[curr].extLocation.partitionReferenceNum =
@@ -836,7 +837,7 @@ static void udf_prealloc_extents(struct inode *inode, int c, int lastblock,
{
numalloc -= elen;
if (*endnum > (i+1))
- memmove(&laarr[i], &laarr[i+1],
+ memmove(&laarr[i], &laarr[i+1],
sizeof(long_ad) * (*endnum - (i+1)));
i --;
(*endnum) --;
@@ -1024,7 +1025,7 @@ void udf_truncate(struct inode * inode)
{
block_truncate_page(inode->i_mapping, inode->i_size, udf_get_block);
udf_truncate_extents(inode);
- }
+ }
inode->i_mtime = inode->i_ctime = current_fs_time(inode->i_sb);
if (IS_SYNC(inode))
@@ -1087,10 +1088,10 @@ __udf_read_inode(struct inode *inode)
{
kernel_lb_addr loc;
ie = (struct indirectEntry *)ibh->b_data;
-
+
loc = lelb_to_cpu(ie->indirectICB.extLocation);
-
- if (ie->indirectICB.extLength &&
+
+ if (ie->indirectICB.extLength &&
(nbh = udf_read_ptagged(inode->i_sb, loc, 0, &ident)))
{
if (ident == TAG_IDENT_FE ||
@@ -1156,14 +1157,22 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
{
UDF_I_EFE(inode) = 1;
UDF_I_USE(inode) = 0;
- UDF_I_DATA(inode) = kmalloc(inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry), GFP_KERNEL);
+ if (udf_alloc_i_data(inode, inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry)))
+ {
+ make_bad_inode(inode);
+ return;
+ }
memcpy(UDF_I_DATA(inode), bh->b_data + sizeof(struct extendedFileEntry), inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry));
}
else if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_FE)
{
UDF_I_EFE(inode) = 0;
UDF_I_USE(inode) = 0;
- UDF_I_DATA(inode) = kmalloc(inode->i_sb->s_blocksize - sizeof(struct fileEntry), GFP_KERNEL);
+ if (udf_alloc_i_data(inode, inode->i_sb->s_blocksize - sizeof(struct fileEntry)))
+ {
+ make_bad_inode(inode);
+ return;
+ }
memcpy(UDF_I_DATA(inode), bh->b_data + sizeof(struct fileEntry), inode->i_sb->s_blocksize - sizeof(struct fileEntry));
}
else if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_USE)
@@ -1173,7 +1182,11 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
UDF_I_LENALLOC(inode) =
le32_to_cpu(
((struct unallocSpaceEntry *)bh->b_data)->lengthAllocDescs);
- UDF_I_DATA(inode) = kmalloc(inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry), GFP_KERNEL);
+ if (udf_alloc_i_data(inode, inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry)))
+ {
+ make_bad_inode(inode);
+ return;
+ }
memcpy(UDF_I_DATA(inode), bh->b_data + sizeof(struct unallocSpaceEntry), inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry));
return;
}
@@ -1191,7 +1204,7 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
inode->i_nlink = le16_to_cpu(fe->fileLinkCount);
if (!inode->i_nlink)
inode->i_nlink = 1;
-
+
inode->i_size = le64_to_cpu(fe->informationLength);
UDF_I_LENEXTENTS(inode) = inode->i_size;
@@ -1243,7 +1256,7 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
}
else
{
- inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) <<
+ inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) <<
(inode->i_sb->s_blocksize_bits - 9);
if ( udf_stamp_to_time(&convtime, &convtime_usec,
@@ -1374,6 +1387,20 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
}
}
+static int udf_alloc_i_data(struct inode *inode, size_t size)
+{
+ UDF_I_DATA(inode) = kmalloc(size, GFP_KERNEL);
+
+ if (!UDF_I_DATA(inode))
+ {
+ printk(KERN_ERR "udf:udf_alloc_i_data (ino %ld) no free memory\n",
+ inode->i_ino);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
static mode_t
udf_convert_permissions(struct fileEntry *fe)
{
@@ -2072,7 +2099,7 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos,
mark_buffer_dirty_inode(oepos.bh, inode);
}
}
-
+
brelse(epos.bh);
brelse(oepos.bh);
return (elen >> 30);
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index 22ff6ed55ce..2b3011689e8 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -87,6 +87,7 @@
#include <linux/smp_lock.h>
#include <linux/buffer_head.h>
#include <linux/vfs.h>
+#include <linux/log2.h>
#include "swab.h"
#include "util.h"
@@ -854,7 +855,7 @@ magic_found:
uspi->s_fmask = fs32_to_cpu(sb, usb1->fs_fmask);
uspi->s_fshift = fs32_to_cpu(sb, usb1->fs_fshift);
- if (uspi->s_fsize & (uspi->s_fsize - 1)) {
+ if (!is_power_of_2(uspi->s_fsize)) {
printk(KERN_ERR "ufs_read_super: fragment size %u is not a power of 2\n",
uspi->s_fsize);
goto failed;
@@ -869,7 +870,7 @@ magic_found:
uspi->s_fsize);
goto failed;
}
- if (uspi->s_bsize & (uspi->s_bsize - 1)) {
+ if (!is_power_of_2(uspi->s_bsize)) {
printk(KERN_ERR "ufs_read_super: block size %u is not a power of 2\n",
uspi->s_bsize);
goto failed;