summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/9p/9p.c1
-rw-r--r--fs/9p/fid.c145
-rw-r--r--fs/9p/fid.h6
-rw-r--r--fs/9p/trans_fd.c1
-rw-r--r--fs/9p/v9fs.c1
-rw-r--r--fs/9p/v9fs_vfs.h1
-rw-r--r--fs/9p/vfs_dentry.c45
-rw-r--r--fs/9p/vfs_dir.c1
-rw-r--r--fs/9p/vfs_file.c106
-rw-r--r--fs/9p/vfs_inode.c479
-rw-r--r--fs/9p/vfs_super.c10
-rw-r--r--fs/befs/linuxvfs.c2
-rw-r--r--fs/binfmt_elf.c5
-rw-r--r--fs/buffer.c60
-rw-r--r--fs/char_dev.c17
-rw-r--r--fs/cifs/CHANGES2
-rw-r--r--fs/cifs/cifsproto.h2
-rw-r--r--fs/cifs/connect.c2
-rw-r--r--fs/cifs/misc.c4
-rw-r--r--fs/compat_ioctl.c15
-rw-r--r--fs/cramfs/inode.c60
-rw-r--r--fs/dcache.c2
-rw-r--r--fs/debugfs/file.c46
-rw-r--r--fs/direct-io.c21
-rw-r--r--fs/exec.c6
-rw-r--r--fs/ext2/dir.c28
-rw-r--r--fs/ext3/inode.c17
-rw-r--r--fs/ext3/namei.c3
-rw-r--r--fs/fat/dir.c2
-rw-r--r--fs/fat/inode.c2
-rw-r--r--fs/fifo.c7
-rw-r--r--fs/file_table.c87
-rw-r--r--fs/fuse/dir.c10
-rw-r--r--fs/hugetlbfs/inode.c92
-rw-r--r--fs/isofs/joliet.c2
-rw-r--r--fs/jffs2/nodelist.c3
-rw-r--r--fs/jffs2/readinode.c2
-rw-r--r--fs/jffs2/scan.c2
-rw-r--r--fs/jfs/Makefile3
-rw-r--r--fs/jfs/acl.c7
-rw-r--r--fs/jfs/file.c1
-rw-r--r--fs/jfs/inode.c15
-rw-r--r--fs/jfs/ioctl.c107
-rw-r--r--fs/jfs/jfs_dinode.h31
-rw-r--r--fs/jfs/jfs_dmap.c15
-rw-r--r--fs/jfs/jfs_dmap.h2
-rw-r--r--fs/jfs/jfs_dtree.c13
-rw-r--r--fs/jfs/jfs_extent.c20
-rw-r--r--fs/jfs/jfs_imap.c78
-rw-r--r--fs/jfs/jfs_imap.h4
-rw-r--r--fs/jfs/jfs_incore.h10
-rw-r--r--fs/jfs/jfs_inode.c46
-rw-r--r--fs/jfs/jfs_inode.h3
-rw-r--r--fs/jfs/jfs_lock.h1
-rw-r--r--fs/jfs/jfs_logmgr.c35
-rw-r--r--fs/jfs/jfs_logmgr.h2
-rw-r--r--fs/jfs/jfs_metapage.c3
-rw-r--r--fs/jfs/jfs_superblock.h9
-rw-r--r--fs/jfs/jfs_txnmgr.c36
-rw-r--r--fs/jfs/namei.c99
-rw-r--r--fs/jfs/super.c98
-rw-r--r--fs/jfs/xattr.c8
-rw-r--r--fs/lockd/clntproc.c9
-rw-r--r--fs/namei.c21
-rw-r--r--fs/namespace.c5
-rw-r--r--fs/nfs/direct.c10
-rw-r--r--fs/nfs/nfs4proc.c2
-rw-r--r--fs/nfsctl.c4
-rw-r--r--fs/nls/Kconfig2
-rw-r--r--fs/ocfs2/cluster/masklog.c1
-rw-r--r--fs/ocfs2/cluster/masklog.h2
-rw-r--r--fs/ocfs2/cluster/nodemanager.c4
-rw-r--r--fs/ocfs2/cluster/tcp.c14
-rw-r--r--fs/ocfs2/cluster/tcp.h5
-rw-r--r--fs/ocfs2/dlm/dlmcommon.h8
-rw-r--r--fs/ocfs2/dlm/dlmdebug.c12
-rw-r--r--fs/ocfs2/dlm/dlmdomain.c39
-rw-r--r--fs/ocfs2/dlm/dlmmaster.c4
-rw-r--r--fs/ocfs2/dlm/dlmrecovery.c23
-rw-r--r--fs/ocfs2/extent_map.c38
-rw-r--r--fs/ocfs2/file.c51
-rw-r--r--fs/ocfs2/heartbeat.c1
-rw-r--r--fs/ocfs2/inode.c46
-rw-r--r--fs/ocfs2/journal.c124
-rw-r--r--fs/ocfs2/ocfs2.h7
-rw-r--r--fs/ocfs2/ocfs2_fs.h1
-rw-r--r--fs/ocfs2/super.c13
-rw-r--r--fs/partitions/ibm.c16
-rw-r--r--fs/pipe.c6
-rw-r--r--fs/proc/task_mmu.c11
-rw-r--r--fs/ramfs/file-nommu.c3
-rw-r--r--fs/ramfs/inode.c3
-rw-r--r--fs/reiserfs/file.c14
-rw-r--r--fs/reiserfs/inode.c8
-rw-r--r--fs/reiserfs/journal.c3
-rw-r--r--fs/reiserfs/namei.c8
-rw-r--r--fs/sysfs/dir.c37
-rw-r--r--fs/sysfs/file.c9
-rw-r--r--fs/sysfs/inode.c9
-rw-r--r--fs/sysfs/symlink.c6
-rw-r--r--fs/sysfs/sysfs.h1
-rw-r--r--fs/udf/inode.c16
-rw-r--r--fs/udf/super.c18
-rw-r--r--fs/udf/udf_sb.h4
-rw-r--r--fs/xfs/linux-2.6/xfs_aops.c2
-rw-r--r--fs/xfs/linux-2.6/xfs_buf.c1
-rw-r--r--fs/xfs/quota/xfs_qm.c11
-rw-r--r--fs/xfs/xfs_rtalloc.c29
108 files changed, 1477 insertions, 1127 deletions
diff --git a/fs/9p/9p.c b/fs/9p/9p.c
index 1a6d08761f39..f86a28d1d6a6 100644
--- a/fs/9p/9p.c
+++ b/fs/9p/9p.c
@@ -111,7 +111,6 @@ static void v9fs_t_clunk_cb(void *a, struct v9fs_fcall *tc,
if (!rc)
return;
- dprintk(DEBUG_9P, "tcall id %d rcall id %d\n", tc->id, rc->id);
v9ses = a;
if (rc->id == RCLUNK)
v9fs_put_idpool(fid, &v9ses->fidpool);
diff --git a/fs/9p/fid.c b/fs/9p/fid.c
index eda449778fa5..c4d13bf904d2 100644
--- a/fs/9p/fid.c
+++ b/fs/9p/fid.c
@@ -1,7 +1,7 @@
/*
* V9FS FID Management
*
- * Copyright (C) 2005 by Eric Van Hensbergen <ericvh@gmail.com>
+ * Copyright (C) 2005, 2006 by Eric Van Hensbergen <ericvh@gmail.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
@@ -40,7 +40,7 @@
*
*/
-static int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry)
+int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry)
{
struct list_head *fid_list = (struct list_head *)dentry->d_fsdata;
dprintk(DEBUG_9P, "fid %d (%p) dentry %s (%p)\n", fid->fid, fid,
@@ -57,7 +57,6 @@ static int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry)
}
fid->uid = current->uid;
- fid->pid = current->pid;
list_add(&fid->list, fid_list);
return 0;
}
@@ -68,14 +67,11 @@ static int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry)
*
*/
-struct v9fs_fid *v9fs_fid_create(struct dentry *dentry,
- struct v9fs_session_info *v9ses, int fid, int create)
+struct v9fs_fid *v9fs_fid_create(struct v9fs_session_info *v9ses, int fid)
{
struct v9fs_fid *new;
- dprintk(DEBUG_9P, "fid create dentry %p, fid %d, create %d\n",
- dentry, fid, create);
-
+ dprintk(DEBUG_9P, "fid create fid %d\n", fid);
new = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL);
if (new == NULL) {
dprintk(DEBUG_ERROR, "Out of Memory\n");
@@ -85,19 +81,13 @@ struct v9fs_fid *v9fs_fid_create(struct dentry *dentry,
new->fid = fid;
new->v9ses = v9ses;
new->fidopen = 0;
- new->fidcreate = create;
new->fidclunked = 0;
new->iounit = 0;
new->rdir_pos = 0;
new->rdir_fcall = NULL;
+ INIT_LIST_HEAD(&new->list);
- if (v9fs_fid_insert(new, dentry) == 0)
- return new;
- else {
- dprintk(DEBUG_ERROR, "Problems inserting to dentry\n");
- kfree(new);
- return NULL;
- }
+ return new;
}
/**
@@ -113,140 +103,29 @@ void v9fs_fid_destroy(struct v9fs_fid *fid)
}
/**
- * v9fs_fid_walk_up - walks from the process current directory
- * up to the specified dentry.
- */
-static struct v9fs_fid *v9fs_fid_walk_up(struct dentry *dentry)
-{
- int fidnum, cfidnum, err;
- struct v9fs_fid *cfid;
- struct dentry *cde;
- struct v9fs_session_info *v9ses;
-
- v9ses = v9fs_inode2v9ses(current->fs->pwd->d_inode);
- cfid = v9fs_fid_lookup(current->fs->pwd);
- if (cfid == NULL) {
- dprintk(DEBUG_ERROR, "process cwd doesn't have a fid\n");
- return ERR_PTR(-ENOENT);
- }
-
- cfidnum = cfid->fid;
- cde = current->fs->pwd;
- /* TODO: take advantage of multiwalk */
-
- fidnum = v9fs_get_idpool(&v9ses->fidpool);
- if (fidnum < 0) {
- dprintk(DEBUG_ERROR, "could not get a new fid num\n");
- err = -ENOENT;
- goto clunk_fid;
- }
-
- while (cde != dentry) {
- if (cde == cde->d_parent) {
- dprintk(DEBUG_ERROR, "can't find dentry\n");
- err = -ENOENT;
- goto clunk_fid;
- }
-
- err = v9fs_t_walk(v9ses, cfidnum, fidnum, "..", NULL);
- if (err < 0) {
- dprintk(DEBUG_ERROR, "problem walking to parent\n");
- goto clunk_fid;
- }
-
- cfidnum = fidnum;
- cde = cde->d_parent;
- }
-
- return v9fs_fid_create(dentry, v9ses, fidnum, 0);
-
-clunk_fid:
- v9fs_t_clunk(v9ses, fidnum);
- return ERR_PTR(err);
-}
-
-/**
* v9fs_fid_lookup - retrieve the right fid from a particular dentry
* @dentry: dentry to look for fid in
* @type: intent of lookup (operation or traversal)
*
- * search list of fids associated with a dentry for a fid with a matching
- * thread id or uid. If that fails, look up the dentry's parents to see if you
- * can find a matching fid.
+ * find a fid in the dentry
+ *
+ * TODO: only match fids that have the same uid as current user
*
*/
struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry)
{
struct list_head *fid_list = (struct list_head *)dentry->d_fsdata;
- struct v9fs_fid *current_fid = NULL;
- struct v9fs_fid *temp = NULL;
struct v9fs_fid *return_fid = NULL;
dprintk(DEBUG_9P, " dentry: %s (%p)\n", dentry->d_iname, dentry);
- if (fid_list) {
- list_for_each_entry_safe(current_fid, temp, fid_list, list) {
- if (!current_fid->fidcreate) {
- return_fid = current_fid;
- break;
- }
- }
-
- if (!return_fid)
- return_fid = current_fid;
- }
-
- /* we are at the root but didn't match */
- if ((!return_fid) && (dentry->d_parent == dentry)) {
- /* TODO: clone attach with new uid */
- return_fid = current_fid;
- }
+ if (fid_list)
+ return_fid = list_entry(fid_list->next, struct v9fs_fid, list);
if (!return_fid) {
- struct dentry *par = current->fs->pwd->d_parent;
- int count = 1;
- while (par != NULL) {
- if (par == dentry)
- break;
- count++;
- if (par == par->d_parent) {
- dprintk(DEBUG_ERROR,
- "got to root without finding dentry\n");
- break;
- }
- par = par->d_parent;
- }
-
-/* XXX - there may be some duplication we can get rid of */
- if (par == dentry) {
- return_fid = v9fs_fid_walk_up(dentry);
- if (IS_ERR(return_fid))
- return_fid = NULL;
- }
+ dprintk(DEBUG_ERROR, "Couldn't find a fid in dentry\n");
}
return return_fid;
}
-
-struct v9fs_fid *v9fs_fid_get_created(struct dentry *dentry)
-{
- struct list_head *fid_list;
- struct v9fs_fid *fid, *ftmp, *ret;
-
- dprintk(DEBUG_9P, " dentry: %s (%p)\n", dentry->d_iname, dentry);
- fid_list = (struct list_head *)dentry->d_fsdata;
- ret = NULL;
- if (fid_list) {
- list_for_each_entry_safe(fid, ftmp, fid_list, list) {
- if (fid->fidcreate && fid->pid == current->pid) {
- list_del(&fid->list);
- ret = fid;
- break;
- }
- }
- }
-
- dprintk(DEBUG_9P, "return %p\n", ret);
- return ret;
-}
diff --git a/fs/9p/fid.h b/fs/9p/fid.h
index 84c673a44c83..1fc2dd08d75a 100644
--- a/fs/9p/fid.h
+++ b/fs/9p/fid.h
@@ -33,7 +33,6 @@ struct v9fs_fid {
u32 fid;
unsigned char fidopen; /* set when fid is opened */
- unsigned char fidcreate; /* set when fid was just created */
unsigned char fidclunked; /* set when fid has already been clunked */
struct v9fs_qid qid;
@@ -45,7 +44,6 @@ struct v9fs_fid {
struct v9fs_fcall *rdir_fcall;
/* management stuff */
- pid_t pid; /* thread associated with this fid */
uid_t uid; /* user associated with this fid */
/* private data */
@@ -56,5 +54,5 @@ struct v9fs_fid {
struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry);
struct v9fs_fid *v9fs_fid_get_created(struct dentry *);
void v9fs_fid_destroy(struct v9fs_fid *fid);
-struct v9fs_fid *v9fs_fid_create(struct dentry *,
- struct v9fs_session_info *v9ses, int fid, int create);
+struct v9fs_fid *v9fs_fid_create(struct v9fs_session_info *, int fid);
+int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry);
diff --git a/fs/9p/trans_fd.c b/fs/9p/trans_fd.c
index 1a28ef97a3d1..5b2ce21b10fa 100644
--- a/fs/9p/trans_fd.c
+++ b/fs/9p/trans_fd.c
@@ -80,6 +80,7 @@ static int v9fs_fd_send(struct v9fs_transport *trans, void *v, int len)
if (!trans || trans->status != Connected || !ts)
return -EIO;
+ oldfs = get_fs();
set_fs(get_ds());
/* The cast to a user pointer is valid due to the set_fs() */
ret = vfs_write(ts->out_file, (void __user *)v, len, &ts->out_file->f_pos);
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index ef3386549140..61352491ba36 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -397,6 +397,7 @@ v9fs_session_init(struct v9fs_session_info *v9ses,
}
if (v9ses->afid != ~0) {
+ dprintk(DEBUG_ERROR, "afid not equal to ~0\n");
if (v9fs_t_clunk(v9ses, v9ses->afid))
dprintk(DEBUG_ERROR, "clunk failed\n");
}
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h
index 69cf2905dc90..a759278acaae 100644
--- a/fs/9p/v9fs_vfs.h
+++ b/fs/9p/v9fs_vfs.h
@@ -51,3 +51,4 @@ int v9fs_dir_release(struct inode *inode, struct file *filp);
int v9fs_file_open(struct inode *inode, struct file *file);
void v9fs_inode2stat(struct inode *inode, struct v9fs_stat *stat);
void v9fs_dentry_release(struct dentry *);
+int v9fs_uflags2omode(int uflags);
diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c
index 2dd806dac9f1..12c9cc926b71 100644
--- a/fs/9p/vfs_dentry.c
+++ b/fs/9p/vfs_dentry.c
@@ -43,47 +43,18 @@
#include "fid.h"
/**
- * v9fs_dentry_validate - VFS dcache hook to validate cache
- * @dentry: dentry that is being validated
- * @nd: path data
+ * v9fs_dentry_delete - called when dentry refcount equals 0
+ * @dentry: dentry in question
*
- * dcache really shouldn't be used for 9P2000 as at all due to
- * potential attached semantics to directory traversal (walk).
- *
- * FUTURE: look into how to use dcache to allow multi-stage
- * walks in Plan 9 & potential for better dcache operation which
- * would remain valid for Plan 9 semantics. Older versions
- * had validation via stat for those interested. However, since
- * stat has the same approximate overhead as walk there really
- * is no difference. The only improvement would be from a
- * time-decay cache like NFS has and that undermines the
- * synchronous nature of 9P2000.
+ * By returning 1 here we should remove cacheing of unused
+ * dentry components.
*
*/
-static int v9fs_dentry_validate(struct dentry *dentry, struct nameidata *nd)
+int v9fs_dentry_delete(struct dentry *dentry)
{
- struct dentry *dc = current->fs->pwd;
-
- dprintk(DEBUG_VFS, "dentry: %s (%p)\n", dentry->d_iname, dentry);
- if (v9fs_fid_lookup(dentry)) {
- dprintk(DEBUG_VFS, "VALID\n");
- return 1;
- }
-
- while (dc != NULL) {
- if (dc == dentry) {
- dprintk(DEBUG_VFS, "VALID\n");
- return 1;
- }
- if (dc == dc->d_parent)
- break;
-
- dc = dc->d_parent;
- }
-
- dprintk(DEBUG_VFS, "INVALID\n");
- return 0;
+ dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
+ return 1;
}
/**
@@ -118,6 +89,6 @@ void v9fs_dentry_release(struct dentry *dentry)
}
struct dentry_operations v9fs_dentry_operations = {
- .d_revalidate = v9fs_dentry_validate,
+ .d_delete = v9fs_dentry_delete,
.d_release = v9fs_dentry_release,
};
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c
index ae6d032b9b59..cd5eeb032d64 100644
--- a/fs/9p/vfs_dir.c
+++ b/fs/9p/vfs_dir.c
@@ -202,7 +202,6 @@ int v9fs_dir_release(struct inode *inode, struct file *filp)
filp->private_data = NULL;
}
- d_drop(filp->f_dentry);
return 0;
}
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index c7e14d917215..de3a129698da 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -53,94 +53,70 @@
int v9fs_file_open(struct inode *inode, struct file *file)
{
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
- struct v9fs_fid *v9fid, *fid;
+ struct v9fs_fid *vfid;
struct v9fs_fcall *fcall = NULL;
- int open_mode = 0;
- unsigned int iounit = 0;
- int newfid = -1;
- long result = -1;
+ int omode;
+ int fid = V9FS_NOFID;
+ int err;
dprintk(DEBUG_VFS, "inode: %p file: %p \n", inode, file);
- v9fid = v9fs_fid_get_created(file->f_dentry);
- if (!v9fid)
- v9fid = v9fs_fid_lookup(file->f_dentry);
-
- if (!v9fid) {
+ vfid = v9fs_fid_lookup(file->f_dentry);
+ if (!vfid) {
dprintk(DEBUG_ERROR, "Couldn't resolve fid from dentry\n");
return -EBADF;
}
- if (!v9fid->fidcreate) {
- fid = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL);
- if (fid == NULL) {
- dprintk(DEBUG_ERROR, "Out of Memory\n");
- return -ENOMEM;
- }
-
- fid->fidopen = 0;
- fid->fidcreate = 0;
- fid->fidclunked = 0;
- fid->iounit = 0;
- fid->v9ses = v9ses;
-
- newfid = v9fs_get_idpool(&v9ses->fidpool);
- if (newfid < 0) {
+ fid = v9fs_get_idpool(&v9ses->fidpool);
+ if (fid < 0) {
eprintk(KERN_WARNING, "newfid fails!\n");
return -ENOSPC;
}
- result =
- v9fs_t_walk(v9ses, v9fid->fid, newfid, NULL, NULL);
-
- if (result < 0) {
- v9fs_put_idpool(newfid, &v9ses->fidpool);
+ err = v9fs_t_walk(v9ses, vfid->fid, fid, NULL, NULL);
+ if (err < 0) {
dprintk(DEBUG_ERROR, "rewalk didn't work\n");
- return -EBADF;
+ goto put_fid;
+ }
+
+ vfid = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL);
+ if (vfid == NULL) {
+ dprintk(DEBUG_ERROR, "out of memory\n");
+ goto clunk_fid;
}
- fid->fid = newfid;
- v9fid = fid;
/* TODO: do special things for O_EXCL, O_NOFOLLOW, O_SYNC */
/* translate open mode appropriately */
- open_mode = file->f_flags & 0x3;
+ omode = v9fs_uflags2omode(file->f_flags);
+ err = v9fs_t_open(v9ses, fid, omode, &fcall);
+ if (err < 0) {
+ PRINT_FCALL_ERROR("open failed", fcall);
+ goto destroy_vfid;
+ }
- if (file->f_flags & O_EXCL)
- open_mode |= V9FS_OEXCL;
+ file->private_data = vfid;
+ vfid->fid = fid;
+ vfid->fidopen = 1;
+ vfid->fidclunked = 0;
+ vfid->iounit = fcall->params.ropen.iounit;
+ vfid->rdir_pos = 0;
+ vfid->rdir_fcall = NULL;
+ vfid->filp = file;
+ kfree(fcall);
- if (v9ses->extended) {
- if (file->f_flags & O_TRUNC)
- open_mode |= V9FS_OTRUNC;
+ return 0;
- if (file->f_flags & O_APPEND)
- open_mode |= V9FS_OAPPEND;
- }
+destroy_vfid:
+ v9fs_fid_destroy(vfid);
- result = v9fs_t_open(v9ses, newfid, open_mode, &fcall);
- if (result < 0) {
- PRINT_FCALL_ERROR("open failed", fcall);
- kfree(fcall);
- return result;
- }
+clunk_fid:
+ v9fs_t_clunk(v9ses, fid);
- iounit = fcall->params.ropen.iounit;
+put_fid:
+ v9fs_put_idpool(fid, &v9ses->fidpool);
kfree(fcall);
- } else {
- /* create case */
- newfid = v9fid->fid;
- iounit = v9fid->iounit;
- v9fid->fidcreate = 0;
- }
-
- file->private_data = v9fid;
-
- v9fid->rdir_pos = 0;
- v9fid->rdir_fcall = NULL;
- v9fid->fidopen = 1;
- v9fid->filp = file;
- v9fid->iounit = iounit;
- return 0;
+ return err;
}
/**
@@ -289,9 +265,7 @@ v9fs_file_write(struct file *filp, const char __user * data,
total += result;
} while (count);
- if(inode->i_mapping->nrpages)
invalidate_inode_pages2(inode->i_mapping);
-
return total;
}
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 63e5b0398e8b..651a9e14d9a9 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -125,6 +125,38 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode)
return res;
}
+int v9fs_uflags2omode(int uflags)
+{
+ int ret;
+
+ ret = 0;
+ switch (uflags&3) {
+ default:
+ case O_RDONLY:
+ ret = V9FS_OREAD;
+ break;
+
+ case O_WRONLY:
+ ret = V9FS_OWRITE;
+ break;
+
+ case O_RDWR:
+ ret = V9FS_ORDWR;
+ break;
+ }
+
+ if (uflags & O_EXCL)
+ ret |= V9FS_OEXCL;
+
+ if (uflags & O_TRUNC)
+ ret |= V9FS_OTRUNC;
+
+ if (uflags & O_APPEND)
+ ret |= V9FS_OAPPEND;
+
+ return ret;
+}
+
/**
* v9fs_blank_wstat - helper function to setup a 9P stat structure
* @v9ses: 9P session info (for determining extended mode)
@@ -163,7 +195,7 @@ v9fs_blank_wstat(struct v9fs_wstat *wstat)
struct inode *v9fs_get_inode(struct super_block *sb, int mode)
{
- struct inode *inode = NULL;
+ struct inode *inode;
struct v9fs_session_info *v9ses = sb->s_fs_info;
dprintk(DEBUG_VFS, "super block: %p mode: %o\n", sb, mode);
@@ -222,171 +254,133 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
return inode;
}
-/**
- * v9fs_create - helper function to create files and directories
- * @dir: directory inode file is being created in
- * @file_dentry: dentry file is being created in
- * @perm: permissions file is being created with
- * @open_mode: resulting open mode for file
- *
- */
-
static int
-v9fs_create(struct inode *dir,
- struct dentry *file_dentry,
- unsigned int perm, unsigned int open_mode)
+v9fs_create(struct v9fs_session_info *v9ses, u32 pfid, char *name,
+ u32 perm, u8 mode, u32 *fidp, struct v9fs_qid *qid, u32 *iounit)
{
- struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);
- struct super_block *sb = dir->i_sb;
- struct v9fs_fid *dirfid =
- v9fs_fid_lookup(file_dentry->d_parent);
- struct v9fs_fid *fid = NULL;
- struct inode *file_inode = NULL;
- struct v9fs_fcall *fcall = NULL;
- struct v9fs_qid qid;
- int dirfidnum = -1;
- long newfid = -1;
- int result = 0;
- unsigned int iounit = 0;
- int wfidno = -1;
+ u32 fid;
int err;
+ struct v9fs_fcall *fcall;
- perm = unixmode2p9mode(v9ses, perm);
-
- dprintk(DEBUG_VFS, "dir: %p dentry: %p perm: %o mode: %o\n", dir,
- file_dentry, perm, open_mode);
-
- if (!dirfid)
- return -EBADF;
-
- dirfidnum = dirfid->fid;
- if (dirfidnum < 0) {
- dprintk(DEBUG_ERROR, "No fid for the directory #%lu\n",
- dir->i_ino);
- return -EBADF;
- }
-
- if (file_dentry->d_inode) {
- dprintk(DEBUG_ERROR,
- "Odd. There is an inode for dir %lu, name :%s:\n",
- dir->i_ino, file_dentry->d_name.name);
- return -EEXIST;
- }
-
- newfid = v9fs_get_idpool(&v9ses->fidpool);
- if (newfid < 0) {
+ fid = v9fs_get_idpool(&v9ses->fidpool);
+ if (fid < 0) {
eprintk(KERN_WARNING, "no free fids available\n");
return -ENOSPC;
}
- result = v9fs_t_walk(v9ses, dirfidnum, newfid, NULL, &fcall);
- if (result < 0) {
+ err = v9fs_t_walk(v9ses, pfid, fid, NULL, &fcall);
+ if (err < 0) {
PRINT_FCALL_ERROR("clone error", fcall);
- v9fs_put_idpool(newfid, &v9ses->fidpool);
- newfid = -1;
- goto CleanUpFid;
+ goto error;
}
-
kfree(fcall);
- fcall = NULL;
- result = v9fs_t_create(v9ses, newfid, (char *)file_dentry->d_name.name,
- perm, open_mode, &fcall);
- if (result < 0) {
+ err = v9fs_t_create(v9ses, fid, name, perm, mode, &fcall);
+ if (err < 0) {
PRINT_FCALL_ERROR("create fails", fcall);
- goto CleanUpFid;
+ goto error;
}
- iounit = fcall->params.rcreate.iounit;
- qid = fcall->params.rcreate.qid;
+ if (iounit)
+ *iounit = fcall->params.rcreate.iounit;
+
+ if (qid)
+ *qid = fcall->params.rcreate.qid;
+
+ if (fidp)
+ *fidp = fid;
+
kfree(fcall);
- fcall = NULL;
+ return 0;
- if (!(perm&V9FS_DMDIR)) {
- fid = v9fs_fid_create(file_dentry, v9ses, newfid, 1);
- dprintk(DEBUG_VFS, "fid %p %d\n", fid, fid->fidcreate);
- if (!fid) {
- result = -ENOMEM;
- goto CleanUpFid;
- }
+error:
+ if (fid >= 0)
+ v9fs_put_idpool(fid, &v9ses->fidpool);
- fid->qid = qid;
- fid->iounit = iounit;
- } else {
- err = v9fs_t_clunk(v9ses, newfid);
- newfid = -1;
- if (err < 0)
- dprintk(DEBUG_ERROR, "clunk for mkdir failed: %d\n", err);
- }
+ kfree(fcall);
+ return err;
+}
+
+static struct v9fs_fid*
+v9fs_clone_walk(struct v9fs_session_info *v9ses, u32 fid, struct dentry *dentry)
+{
+ int err;
+ u32 nfid;
+ struct v9fs_fid *ret;
+ struct v9fs_fcall *fcall;
- /* walk to the newly created file and put the fid in the dentry */
- wfidno = v9fs_get_idpool(&v9ses->fidpool);
- if (wfidno < 0) {
+ nfid = v9fs_get_idpool(&v9ses->fidpool);
+ if (nfid < 0) {
eprintk(KERN_WARNING, "no free fids available\n");
- return -ENOSPC;
+ return ERR_PTR(-ENOSPC);
}
- result = v9fs_t_walk(v9ses, dirfidnum, wfidno,
- (char *) file_dentry->d_name.name, &fcall);
- if (result < 0) {
- PRINT_FCALL_ERROR("clone error", fcall);
- v9fs_put_idpool(wfidno, &v9ses->fidpool);
- wfidno = -1;
- goto CleanUpFid;
+ err = v9fs_t_walk(v9ses, fid, nfid, (char *) dentry->d_name.name,
+ &fcall);
+
+ if (err < 0) {
+ PRINT_FCALL_ERROR("walk error", fcall);
+ v9fs_put_idpool(nfid, &v9ses->fidpool);
+ goto error;
}
+
kfree(fcall);
fcall = NULL;
+ ret = v9fs_fid_create(v9ses, nfid);
+ if (!ret) {
+ err = -ENOMEM;
+ goto clunk_fid;
+ }
- if (!v9fs_fid_create(file_dentry, v9ses, wfidno, 0)) {
- v9fs_put_idpool(wfidno, &v9ses->fidpool);
-
- goto CleanUpFid;
+ err = v9fs_fid_insert(ret, dentry);
+ if (err < 0) {
+ v9fs_fid_destroy(ret);
+ goto clunk_fid;
}
- if ((perm & V9FS_DMSYMLINK) || (perm & V9FS_DMLINK) ||
- (perm & V9FS_DMNAMEDPIPE) || (perm & V9FS_DMSOCKET) ||
- (perm & V9FS_DMDEVICE))
- return 0;
+ return ret;
- result = v9fs_t_stat(v9ses, wfidno, &fcall);
- if (result < 0) {
- PRINT_FCALL_ERROR("stat error", fcall);
- goto CleanUpFid;
- }
+clunk_fid:
+ v9fs_t_clunk(v9ses, nfid);
+error:
+ kfree(fcall);
+ return ERR_PTR(err);
+}
+
+struct inode *
+v9fs_inode_from_fid(struct v9fs_session_info *v9ses, u32 fid,
+ struct super_block *sb)
+{
+ int err, umode;
+ struct inode *ret;
+ struct v9fs_fcall *fcall;
- file_inode = v9fs_get_inode(sb,
- p9mode2unixmode(v9ses, fcall->params.rstat.stat.mode));
+ ret = NULL;
+ err = v9fs_t_stat(v9ses, fid, &fcall);
+ if (err) {
+ PRINT_FCALL_ERROR("stat error", fcall);
+ goto error;
+ }
- if ((!file_inode) || IS_ERR(file_inode)) {
- dprintk(DEBUG_ERROR, "create inode failed\n");
- result = -EBADF;
- goto CleanUpFid;
+ umode = p9mode2unixmode(v9ses, fcall->params.rstat.stat.mode);
+ ret = v9fs_get_inode(sb, umode);
+ if (IS_ERR(ret)) {
+ err = PTR_ERR(ret);
+ ret = NULL;
+ goto error;
}
- v9fs_stat2inode(&fcall->params.rstat.stat, file_inode, sb);
+ v9fs_stat2inode(&fcall->params.rstat.stat, ret, sb);
kfree(fcall);
- fcall = NULL;
- file_dentry->d_op = &v9fs_dentry_operations;
- d_instantiate(file_dentry, file_inode);
-
- return 0;
+ return ret;
- CleanUpFid:
+error:
kfree(fcall);
- fcall = NULL;
+ if (ret)
+ iput(ret);
- if (newfid >= 0) {
- err = v9fs_t_clunk(v9ses, newfid);
- if (err < 0)
- dprintk(DEBUG_ERROR, "clunk failed: %d\n", err);
- }
- if (wfidno >= 0) {
- err = v9fs_t_clunk(v9ses, wfidno);
- if (err < 0)
- dprintk(DEBUG_ERROR, "clunk failed: %d\n", err);
- }
- return result;
+ return ERR_PTR(err);
}
/**
@@ -440,20 +434,97 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
return result;
}
+static int
+v9fs_open_created(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
/**
* v9fs_vfs_create - VFS hook to create files
* @inode: directory inode that is being deleted
* @dentry: dentry that is being deleted
- * @perm: create permissions
+ * @mode: create permissions
* @nd: path information
*
*/
static int
-v9fs_vfs_create(struct inode *inode, struct dentry *dentry, int perm,
+v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
struct nameidata *nd)
{
- return v9fs_create(inode, dentry, perm, O_RDWR);
+ int err;
+ u32 fid, perm, iounit;
+ int flags;
+ struct v9fs_session_info *v9ses;
+ struct v9fs_fid *dfid, *vfid, *ffid;
+ struct inode *inode;
+ struct v9fs_qid qid;
+ struct file *filp;
+
+ inode = NULL;
+ vfid = NULL;
+ v9ses = v9fs_inode2v9ses(dir);
+ dfid = v9fs_fid_lookup(dentry->d_parent);
+ perm = unixmode2p9mode(v9ses, mode);
+
+ if (nd && nd->flags & LOOKUP_OPEN)
+ flags = nd->intent.open.flags - 1;
+ else
+ flags = O_RDWR;
+
+ err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name,
+ perm, v9fs_uflags2omode(flags), &fid, &qid, &iounit);
+
+ if (err)
+ goto error;
+
+ vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry);
+ if (IS_ERR(vfid)) {
+ err = PTR_ERR(vfid);
+ vfid = NULL;
+ goto error;
+ }
+
+ inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb);
+ if (IS_ERR(inode)) {
+ err = PTR_ERR(inode);
+ inode = NULL;
+ goto error;
+ }
+
+ dentry->d_op = &v9fs_dentry_operations;
+ d_instantiate(dentry, inode);
+
+ if (nd && nd->flags & LOOKUP_OPEN) {
+ ffid = v9fs_fid_create(v9ses, fid);
+ if (!ffid)
+ return -ENOMEM;
+
+ filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created);
+ if (IS_ERR(filp)) {
+ v9fs_fid_destroy(ffid);
+ return PTR_ERR(filp);
+ }
+
+ ffid->rdir_pos = 0;
+ ffid->rdir_fcall = NULL;
+ ffid->fidopen = 1;
+ ffid->iounit = iounit;
+ ffid->filp = filp;
+ filp->private_data = ffid;
+ }
+
+ return 0;
+
+error:
+ if (vfid)
+ v9fs_fid_destroy(vfid);
+
+ if (inode)
+ iput(inode);
+
+ return err;
}
/**
@@ -464,9 +535,57 @@ v9fs_vfs_create(struct inode *inode, struct dentry *dentry, int perm,
*
*/
-static int v9fs_vfs_mkdir(struct inode *inode, struct dentry *dentry, int mode)
+static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
- return v9fs_create(inode, dentry, mode | S_IFDIR, O_RDONLY);
+ int err;
+ u32 fid, perm;
+ struct v9fs_session_info *v9ses;
+ struct v9fs_fid *dfid, *vfid;
+ struct inode *inode;
+
+ inode = NULL;
+ vfid = NULL;
+ v9ses = v9fs_inode2v9ses(dir);
+ dfid = v9fs_fid_lookup(dentry->d_parent);
+ perm = unixmode2p9mode(v9ses, mode | S_IFDIR);
+
+ err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name,
+ perm, V9FS_OREAD, &fid, NULL, NULL);
+
+ if (err) {
+ dprintk(DEBUG_ERROR, "create error %d\n", err);
+ goto error;
+ }
+
+ err = v9fs_t_clunk(v9ses, fid);
+ if (err) {
+ dprintk(DEBUG_ERROR, "clunk error %d\n", err);
+ goto error;
+ }
+
+ vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry);
+ if (IS_ERR(vfid)) {
+ err = PTR_ERR(vfid);
+ vfid = NULL;
+ goto error;
+ }
+
+ inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb);
+ if (IS_ERR(inode)) {
+ err = PTR_ERR(inode);
+ inode = NULL;
+ goto error;
+ }
+
+ dentry->d_op = &v9fs_dentry_operations;
+ d_instantiate(dentry, inode);
+ return 0;
+
+error:
+ if (vfid)
+ v9fs_fid_destroy(vfid);
+
+ return err;
}
/**
@@ -491,10 +610,11 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
int result = 0;
dprintk(DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n",
- dir, dentry->d_iname, dentry, nameidata);
+ dir, dentry->d_name.name, dentry, nameidata);
sb = dir->i_sb;
v9ses = v9fs_inode2v9ses(dir);
+ dentry->d_op = &v9fs_dentry_operations;
dirfid = v9fs_fid_lookup(dentry->d_parent);
if (!dirfid) {
@@ -516,9 +636,8 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
return ERR_PTR(-ENOSPC);
}
- result =
- v9fs_t_walk(v9ses, dirfidnum, newfid, (char *)dentry->d_name.name,
- NULL);
+ result = v9fs_t_walk(v9ses, dirfidnum, newfid,
+ (char *)dentry->d_name.name, NULL);
if (result < 0) {
v9fs_put_idpool(newfid, &v9ses->fidpool);
if (result == -ENOENT) {
@@ -551,16 +670,18 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat.qid);
- fid = v9fs_fid_create(dentry, v9ses, newfid, 0);
+ fid = v9fs_fid_create(v9ses, newfid);
if (fid == NULL) {
dprintk(DEBUG_ERROR, "couldn't insert\n");
result = -ENOMEM;
goto FreeFcall;
}
- fid->qid = fcall->params.rstat.stat.qid;
+ result = v9fs_fid_insert(fid, dentry);
+ if (result < 0)
+ goto FreeFcall;
- dentry->d_op = &v9fs_dentry_operations;
+ fid->qid = fcall->params.rstat.stat.qid;
v9fs_stat2inode(&fcall->params.rstat.stat, inode, inode->i_sb);
d_add(dentry, inode);
@@ -886,8 +1007,8 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
}
/* copy extension buffer into buffer */
- if (fcall->params.rstat.stat.extension.len+1 < buflen)
- buflen = fcall->params.rstat.stat.extension.len + 1;
+ if (fcall->params.rstat.stat.extension.len < buflen)
+ buflen = fcall->params.rstat.stat.extension.len;
memcpy(buffer, fcall->params.rstat.stat.extension.str, buflen - 1);
buffer[buflen-1] = 0;
@@ -951,7 +1072,7 @@ static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd)
if (!link)
link = ERR_PTR(-ENOMEM);
else {
- len = v9fs_readlink(dentry, link, PATH_MAX);
+ len = v9fs_readlink(dentry, link, strlen(link));
if (len < 0) {
__putname(link);
@@ -983,53 +1104,75 @@ static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void
static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
int mode, const char *extension)
{
- int err, retval;
+ int err;
+ u32 fid, perm;
struct v9fs_session_info *v9ses;
+ struct v9fs_fid *dfid, *vfid;
+ struct inode *inode;
struct v9fs_fcall *fcall;
- struct v9fs_fid *fid;
struct v9fs_wstat wstat;
- v9ses = v9fs_inode2v9ses(dir);
- retval = -EPERM;
fcall = NULL;
+ inode = NULL;
+ vfid = NULL;
+ v9ses = v9fs_inode2v9ses(dir);
+ dfid = v9fs_fid_lookup(dentry->d_parent);
+ perm = unixmode2p9mode(v9ses, mode);
if (!v9ses->extended) {
dprintk(DEBUG_ERROR, "not extended\n");
- goto free_mem;
+ return -EPERM;
}
- /* issue a create */
- retval = v9fs_create(dir, dentry, mode, 0);
- if (retval != 0)
- goto free_mem;
+ err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name,
+ perm, V9FS_OREAD, &fid, NULL, NULL);
- fid = v9fs_fid_get_created(dentry);
- if (!fid) {
- dprintk(DEBUG_ERROR, "couldn't resolve fid from dentry\n");
- goto free_mem;
+ if (err)
+ goto error;
+
+ err = v9fs_t_clunk(v9ses, fid);
+ if (err)
+ goto error;
+
+ vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry);
+ if (IS_ERR(vfid)) {
+ err = PTR_ERR(vfid);
+ vfid = NULL;
+ goto error;
+ }
+
+ inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb);
+ if (IS_ERR(inode)) {
+ err = PTR_ERR(inode);
+ inode = NULL;
+ goto error;
}
/* issue a Twstat */
v9fs_blank_wstat(&wstat);
wstat.muid = v9ses->name;
wstat.extension = (char *) extension;
- retval = v9fs_t_wstat(v9ses, fid->fid, &wstat, &fcall);
- if (retval < 0) {
- PRINT_FCALL_ERROR("wstat error", fcall);
- goto free_mem;
- }
-
- err = v9fs_t_clunk(v9ses, fid->fid);
+ err = v9fs_t_wstat(v9ses, vfid->fid, &wstat, &fcall);
if (err < 0) {
- dprintk(DEBUG_ERROR, "clunk failed: %d\n", err);
- goto free_mem;
+ PRINT_FCALL_ERROR("wstat error", fcall);
+ goto error;
}
- d_drop(dentry); /* FID - will this also clunk? */
+ kfree(fcall);
+ dentry->d_op = &v9fs_dentry_operations;
+ d_instantiate(dentry, inode);
+ return 0;
-free_mem:
+error:
kfree(fcall);
- return retval;
+ if (vfid)
+ v9fs_fid_destroy(vfid);
+
+ if (inode)
+ iput(inode);
+
+ return err;
+
}
/**
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index 2c4fa75be025..d05318fa684e 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -146,7 +146,6 @@ static struct super_block *v9fs_get_sb(struct file_system_type
inode->i_gid = gid;
root = d_alloc_root(inode);
-
if (!root) {
retval = -ENOMEM;
goto put_back_sb;
@@ -158,15 +157,20 @@ static struct super_block *v9fs_get_sb(struct file_system_type
if (stat_result < 0) {
dprintk(DEBUG_ERROR, "stat error\n");
v9fs_t_clunk(v9ses, newfid);
- v9fs_put_idpool(newfid, &v9ses->fidpool);
} else {
/* Setup the Root Inode */
- root_fid = v9fs_fid_create(root, v9ses, newfid, 0);
+ root_fid = v9fs_fid_create(v9ses, newfid);
if (root_fid == NULL) {
retval = -ENOMEM;
goto put_back_sb;
}
+ retval = v9fs_fid_insert(root_fid, root);
+ if (retval < 0) {
+ kfree(fcall);
+ goto put_back_sb;
+ }
+
root_fid->qid = fcall->params.rstat.stat.qid;
root->d_inode->i_ino =
v9fs_qid2ino(&fcall->params.rstat.stat.qid);
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index 2d365cb8eec6..dd6048ce0532 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -561,7 +561,7 @@ befs_utf2nls(struct super_block *sb, const char *in,
* @sb: Superblock
* @src: Input string buffer in NLS format
* @srclen: Length of input string in bytes
- * @dest: The output string in UTF8 format
+ * @dest: The output string in UTF-8 format
* @destlen: Length of the output buffer
*
* Converts input string @src, which is in the format of the loaded NLS map,
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 1b117a441298..c2eac2a50bd2 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -938,6 +938,11 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
kfree(elf_interpreter);
} else {
elf_entry = loc->elf_ex.e_entry;
+ if (BAD_ADDR(elf_entry)) {
+ send_sig(SIGSEGV, current, 0);
+ retval = -ENOEXEC; /* Nobody gets to see this, but.. */
+ goto out_free_dentry;
+ }
}
kfree(elf_phdata);
diff --git a/fs/buffer.c b/fs/buffer.c
index 62cfd17dc5fe..1d3683d496f8 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -3051,66 +3051,6 @@ asmlinkage long sys_bdflush(int func, long data)
}
/*
- * Migration function for pages with buffers. This function can only be used
- * if the underlying filesystem guarantees that no other references to "page"
- * exist.
- */
-#ifdef CONFIG_MIGRATION
-int buffer_migrate_page(struct page *newpage, struct page *page)
-{
- struct address_space *mapping = page->mapping;
- struct buffer_head *bh, *head;
-
- if (!mapping)
- return -EAGAIN;
-
- if (!page_has_buffers(page))
- return migrate_page(newpage, page);
-
- head = page_buffers(page);
-
- if (migrate_page_remove_references(newpage, page, 3))
- return -EAGAIN;
-
- bh = head;
- do {
- get_bh(bh);
- lock_buffer(bh);
- bh = bh->b_this_page;
-
- } while (bh != head);
-
- ClearPagePrivate(page);
- set_page_private(newpage, page_private(page));
- set_page_private(page, 0);
- put_page(page);
- get_page(newpage);
-
- bh = head;
- do {
- set_bh_page(bh, newpage, bh_offset(bh));
- bh = bh->b_this_page;
-
- } while (bh != head);
-
- SetPagePrivate(newpage);
-
- migrate_page_copy(newpage, page);
-
- bh = head;
- do {
- unlock_buffer(bh);
- put_bh(bh);
- bh = bh->b_this_page;
-
- } while (bh != head);
-
- return 0;
-}
-EXPORT_SYMBOL(buffer_migrate_page);
-#endif
-
-/*
* Buffer-head allocation
*/
static kmem_cache_t *bh_cachep;
diff --git a/fs/char_dev.c b/fs/char_dev.c
index 21195c481637..5c36345c9bf7 100644
--- a/fs/char_dev.c
+++ b/fs/char_dev.c
@@ -19,6 +19,7 @@
#include <linux/kobject.h>
#include <linux/kobj_map.h>
#include <linux/cdev.h>
+#include <linux/mutex.h>
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
@@ -28,7 +29,7 @@ static struct kobj_map *cdev_map;
#define MAX_PROBE_HASH 255 /* random */
-static DECLARE_MUTEX(chrdevs_lock);
+static DEFINE_MUTEX(chrdevs_lock);
static struct char_device_struct {
struct char_device_struct *next;
@@ -88,13 +89,13 @@ out:
void *acquire_chrdev_list(void)
{
- down(&chrdevs_lock);
+ mutex_lock(&chrdevs_lock);
return get_next_chrdev(NULL);
}
void release_chrdev_list(void *dev)
{
- up(&chrdevs_lock);
+ mutex_unlock(&chrdevs_lock);
kfree(dev);
}
@@ -151,7 +152,7 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor,
memset(cd, 0, sizeof(struct char_device_struct));
- down(&chrdevs_lock);
+ mutex_lock(&chrdevs_lock);
/* temporary */
if (major == 0) {
@@ -186,10 +187,10 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor,
}
cd->next = *cp;
*cp = cd;
- up(&chrdevs_lock);
+ mutex_unlock(&chrdevs_lock);
return cd;
out:
- up(&chrdevs_lock);
+ mutex_unlock(&chrdevs_lock);
kfree(cd);
return ERR_PTR(ret);
}
@@ -200,7 +201,7 @@ __unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct)
struct char_device_struct *cd = NULL, **cp;
int i = major_to_index(major);
- down(&chrdevs_lock);
+ mutex_lock(&chrdevs_lock);
for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
if ((*cp)->major == major &&
(*cp)->baseminor == baseminor &&
@@ -210,7 +211,7 @@ __unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct)
cd = *cp;
*cp = cd->next;
}
- up(&chrdevs_lock);
+ mutex_unlock(&chrdevs_lock);
return cd;
}
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index d335015473a5..cb68efba35db 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -160,7 +160,7 @@ improperly zeroed buffer in CIFS Unix extensions set times call.
Version 1.25
------------
Fix internationalization problem in cifs readdir with filenames that map to
-longer UTF8 strings than the string on the wire was in Unicode. Add workaround
+longer UTF-8 strings than the string on the wire was in Unicode. Add workaround
for readdir to netapp servers. Fix search rewind (seek into readdir to return
non-consecutive entries). Do not do readdir when server negotiates
buffer size to small to fit filename. Add support for reading POSIX ACLs from
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 3c03aadaff0c..7b25463d3c14 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -52,7 +52,7 @@ extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
int * /* type of buf returned */ , const int long_op);
extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid);
extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);
-extern int is_valid_oplock_break(struct smb_hdr *smb);
+extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *);
extern int is_size_safe_to_change(struct cifsInodeInfo *);
extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *);
extern unsigned int smbCalcSize(struct smb_hdr *ptr);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index ef5ae6f93c75..2a0c1f4ca0ae 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -630,7 +630,7 @@ multi_t2_fnd:
smallbuf = NULL;
}
wake_up_process(task_to_wake);
- } else if ((is_valid_oplock_break(smb_buffer) == FALSE)
+ } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE)
&& (isMultiRsp == FALSE)) {
cERROR(1, ("No task to wake, unknown frame rcvd!"));
cifs_dump_mem("Received Data is: ",(char *)smb_buffer,
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 812c6bb0fe38..432ba15e2c2d 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -475,7 +475,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length)
return 0;
}
int
-is_valid_oplock_break(struct smb_hdr *buf)
+is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
{
struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)buf;
struct list_head *tmp;
@@ -535,7 +535,7 @@ is_valid_oplock_break(struct smb_hdr *buf)
read_lock(&GlobalSMBSeslock);
list_for_each(tmp, &GlobalTreeConnectionList) {
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
- if (tcon->tid == buf->Tid) {
+ if ((tcon->tid == buf->Tid) && (srv == tcon->ses->server)) {
cifs_stats_inc(&tcon->num_oplock_brks);
list_for_each(tmp1,&tcon->openFileList){
netfile = list_entry(tmp1,struct cifsFileInfo,
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 057e60217fc5..c666769a875d 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -446,7 +446,7 @@ static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg)
ifr = ifc.ifc_req;
ifr32 = compat_ptr(ifc32.ifcbuf);
for (i = 0, j = 0;
- i + sizeof (struct ifreq32) < ifc32.ifc_len && j < ifc.ifc_len;
+ i + sizeof (struct ifreq32) <= ifc32.ifc_len && j < ifc.ifc_len;
i += sizeof (struct ifreq32), j += sizeof (struct ifreq)) {
if (copy_in_user(ifr32, ifr, sizeof (struct ifreq32)))
return -EFAULT;
@@ -2531,18 +2531,9 @@ static int rtc_ioctl(unsigned fd, unsigned cmd, unsigned long arg)
val32 = kval;
return put_user(val32, (unsigned int __user *)arg);
case RTC_IRQP_SET32:
+ return sys_ioctl(fd, RTC_IRQP_SET, arg);
case RTC_EPOCH_SET32:
- ret = get_user(val32, (unsigned int __user *)arg);
- if (ret)
- return ret;
- kval = val32;
-
- set_fs(KERNEL_DS);
- ret = sys_ioctl(fd, (cmd == RTC_IRQP_SET32) ?
- RTC_IRQP_SET : RTC_EPOCH_SET,
- (unsigned long)&kval);
- set_fs(oldfs);
- return ret;
+ return sys_ioctl(fd, RTC_EPOCH_SET, arg);
default:
/* unreached */
return -ENOIOCTLCMD;
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index 7fe85415ae7c..8ad52f5bf255 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -36,7 +36,7 @@ static DECLARE_MUTEX(read_mutex);
/* These two macros may change in future, to provide better st_ino
semantics. */
-#define CRAMINO(x) ((x)->offset?(x)->offset<<2:1)
+#define CRAMINO(x) (((x)->offset && (x)->size)?(x)->offset<<2:1)
#define OFFSET(x) ((x)->i_ino)
@@ -66,8 +66,36 @@ static int cramfs_iget5_test(struct inode *inode, void *opaque)
static int cramfs_iget5_set(struct inode *inode, void *opaque)
{
+ static struct timespec zerotime;
struct cramfs_inode *cramfs_inode = opaque;
+ inode->i_mode = cramfs_inode->mode;
+ inode->i_uid = cramfs_inode->uid;
+ inode->i_size = cramfs_inode->size;
+ inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1;
+ inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_gid = cramfs_inode->gid;
+ /* Struct copy intentional */
+ inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime;
inode->i_ino = CRAMINO(cramfs_inode);
+ /* inode->i_nlink is left 1 - arguably wrong for directories,
+ but it's the best we can do without reading the directory
+ contents. 1 yields the right result in GNU find, even
+ without -noleaf option. */
+ if (S_ISREG(inode->i_mode)) {
+ inode->i_fop = &generic_ro_fops;
+ inode->i_data.a_ops = &cramfs_aops;
+ } else if (S_ISDIR(inode->i_mode)) {
+ inode->i_op = &cramfs_dir_inode_operations;
+ inode->i_fop = &cramfs_directory_operations;
+ } else if (S_ISLNK(inode->i_mode)) {
+ inode->i_op = &page_symlink_inode_operations;
+ inode->i_data.a_ops = &cramfs_aops;
+ } else {
+ inode->i_size = 0;
+ inode->i_blocks = 0;
+ init_special_inode(inode, inode->i_mode,
+ old_decode_dev(cramfs_inode->size));
+ }
return 0;
}
@@ -77,37 +105,7 @@ static struct inode *get_cramfs_inode(struct super_block *sb,
struct inode *inode = iget5_locked(sb, CRAMINO(cramfs_inode),
cramfs_iget5_test, cramfs_iget5_set,
cramfs_inode);
- static struct timespec zerotime;
-
if (inode && (inode->i_state & I_NEW)) {
- inode->i_mode = cramfs_inode->mode;
- inode->i_uid = cramfs_inode->uid;
- inode->i_size = cramfs_inode->size;
- inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1;
- inode->i_blksize = PAGE_CACHE_SIZE;
- inode->i_gid = cramfs_inode->gid;
- /* Struct copy intentional */
- inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime;
- inode->i_ino = CRAMINO(cramfs_inode);
- /* inode->i_nlink is left 1 - arguably wrong for directories,
- but it's the best we can do without reading the directory
- contents. 1 yields the right result in GNU find, even
- without -noleaf option. */
- if (S_ISREG(inode->i_mode)) {
- inode->i_fop = &generic_ro_fops;
- inode->i_data.a_ops = &cramfs_aops;
- } else if (S_ISDIR(inode->i_mode)) {
- inode->i_op = &cramfs_dir_inode_operations;
- inode->i_fop = &cramfs_directory_operations;
- } else if (S_ISLNK(inode->i_mode)) {
- inode->i_op = &page_symlink_inode_operations;
- inode->i_data.a_ops = &cramfs_aops;
- } else {
- inode->i_size = 0;
- inode->i_blocks = 0;
- init_special_inode(inode, inode->i_mode,
- old_decode_dev(cramfs_inode->size));
- }
unlock_new_inode(inode);
}
return inode;
diff --git a/fs/dcache.c b/fs/dcache.c
index a173bba32666..11dc83092d4a 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1736,7 +1736,7 @@ void __init vfs_caches_init(unsigned long mempages)
SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0,
- SLAB_HWCACHE_ALIGN|SLAB_PANIC, filp_ctor, filp_dtor);
+ SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
dcache_init(mempages);
inode_init(mempages);
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c
index d575452cd9f7..40c4fc973fad 100644
--- a/fs/debugfs/file.c
+++ b/fs/debugfs/file.c
@@ -251,3 +251,49 @@ struct dentry *debugfs_create_bool(const char *name, mode_t mode,
}
EXPORT_SYMBOL_GPL(debugfs_create_bool);
+static ssize_t read_file_blob(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct debugfs_blob_wrapper *blob = file->private_data;
+ return simple_read_from_buffer(user_buf, count, ppos, blob->data,
+ blob->size);
+}
+
+static struct file_operations fops_blob = {
+ .read = read_file_blob,
+ .open = default_open,
+};
+
+/**
+ * debugfs_create_blob - create a file in the debugfs filesystem that is
+ * used to read and write a binary blob.
+ *
+ * @name: a pointer to a string containing the name of the file to create.
+ * @mode: the permission that the file should have
+ * @parent: a pointer to the parent dentry for this file. This should be a
+ * directory dentry if set. If this paramater is NULL, then the
+ * file will be created in the root of the debugfs filesystem.
+ * @blob: a pointer to a struct debugfs_blob_wrapper which contains a pointer
+ * to the blob data and the size of the data.
+ *
+ * This function creates a file in debugfs with the given name that exports
+ * @blob->data as a binary blob. If the @mode variable is so set it can be
+ * read from. Writing is not supported.
+ *
+ * This function will return a pointer to a dentry if it succeeds. This
+ * pointer must be passed to the debugfs_remove() function when the file is
+ * to be removed (no automatic cleanup happens if your module is unloaded,
+ * you are responsible here.) If an error occurs, NULL will be returned.
+ *
+ * If debugfs is not enabled in the kernel, the value -ENODEV will be
+ * returned. It is not wise to check for this value, but rather, check for
+ * NULL or !NULL instead as to eliminate the need for #ifdef in the calling
+ * code.
+ */
+struct dentry *debugfs_create_blob(const char *name, mode_t mode,
+ struct dentry *parent,
+ struct debugfs_blob_wrapper *blob)
+{
+ return debugfs_create_file(name, mode, parent, blob, &fops_blob);
+}
+EXPORT_SYMBOL_GPL(debugfs_create_blob);
diff --git a/fs/direct-io.c b/fs/direct-io.c
index 848044af7e16..27f3e787faca 100644
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -1155,15 +1155,16 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
* For writes, i_mutex is not held on entry; it is never taken.
*
* DIO_LOCKING (simple locking for regular files)
- * For writes we are called under i_mutex and return with i_mutex held, even though
- * it is internally dropped.
+ * For writes we are called under i_mutex and return with i_mutex held, even
+ * though it is internally dropped.
* For reads, i_mutex is not held on entry, but it is taken and dropped before
* returning.
*
* DIO_OWN_LOCKING (filesystem provides synchronisation and handling of
* uninitialised data, allowing parallel direct readers and writers)
* For writes we are called without i_mutex, return without it, never touch it.
- * For reads, i_mutex is held on entry and will be released before returning.
+ * For reads we are called under i_mutex and return with i_mutex held, even
+ * though it may be internally dropped.
*
* Additional i_alloc_sem locking requirements described inline below.
*/
@@ -1182,7 +1183,8 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
ssize_t retval = -EINVAL;
loff_t end = offset;
struct dio *dio;
- int reader_with_isem = (rw == READ && dio_lock_type == DIO_OWN_LOCKING);
+ int release_i_mutex = 0;
+ int acquire_i_mutex = 0;
if (rw & WRITE)
current->flags |= PF_SYNCWRITE;
@@ -1225,7 +1227,6 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
* writers need to grab i_alloc_sem only (i_mutex is already held)
* For regular files using DIO_OWN_LOCKING,
* neither readers nor writers take any locks here
- * (i_mutex is already held and release for writers here)
*/
dio->lock_type = dio_lock_type;
if (dio_lock_type != DIO_NO_LOCKING) {
@@ -1236,7 +1237,7 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
mapping = iocb->ki_filp->f_mapping;
if (dio_lock_type != DIO_OWN_LOCKING) {
mutex_lock(&inode->i_mutex);
- reader_with_isem = 1;
+ release_i_mutex = 1;
}
retval = filemap_write_and_wait_range(mapping, offset,
@@ -1248,7 +1249,7 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
if (dio_lock_type == DIO_OWN_LOCKING) {
mutex_unlock(&inode->i_mutex);
- reader_with_isem = 0;
+ acquire_i_mutex = 1;
}
}
@@ -1269,11 +1270,13 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
nr_segs, blkbits, get_blocks, end_io, dio);
if (rw == READ && dio_lock_type == DIO_LOCKING)
- reader_with_isem = 0;
+ release_i_mutex = 0;
out:
- if (reader_with_isem)
+ if (release_i_mutex)
mutex_unlock(&inode->i_mutex);
+ else if (acquire_i_mutex)
+ mutex_lock(&inode->i_mutex);
if (rw & WRITE)
current->flags &= ~PF_SYNCWRITE;
return retval;
diff --git a/fs/exec.c b/fs/exec.c
index 0e1c95074d42..0b515ac53134 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -885,6 +885,12 @@ int flush_old_exec(struct linux_binprm * bprm)
current->flags &= ~PF_RANDOMIZE;
flush_thread();
+ /* Set the new mm task size. We have to do that late because it may
+ * depend on TIF_32BIT which is only updated in flush_thread() on
+ * some architectures like powerpc
+ */
+ current->mm->task_size = TASK_SIZE;
+
if (bprm->e_uid != current->euid || bprm->e_gid != current->egid ||
file_permission(bprm->file, MAY_READ) ||
(bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) {
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index 7442bdd1267a..b3dbd716cd3a 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -256,11 +256,10 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
unsigned long npages = dir_pages(inode);
unsigned chunk_mask = ~(ext2_chunk_size(inode)-1);
unsigned char *types = NULL;
- int need_revalidate = (filp->f_version != inode->i_version);
- int ret;
+ int need_revalidate = filp->f_version != inode->i_version;
if (pos > inode->i_size - EXT2_DIR_REC_LEN(1))
- goto success;
+ return 0;
if (EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_FILETYPE))
types = ext2_filetype_table;
@@ -275,12 +274,15 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
"bad page in #%lu",
inode->i_ino);
filp->f_pos += PAGE_CACHE_SIZE - offset;
- ret = -EIO;
- goto done;
+ return -EIO;
}
kaddr = page_address(page);
- if (need_revalidate) {
- offset = ext2_validate_entry(kaddr, offset, chunk_mask);
+ if (unlikely(need_revalidate)) {
+ if (offset) {
+ offset = ext2_validate_entry(kaddr, offset, chunk_mask);
+ filp->f_pos = (n<<PAGE_CACHE_SHIFT) + offset;
+ }
+ filp->f_version = inode->i_version;
need_revalidate = 0;
}
de = (ext2_dirent *)(kaddr+offset);
@@ -289,9 +291,8 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
if (de->rec_len == 0) {
ext2_error(sb, __FUNCTION__,
"zero-length directory entry");
- ret = -EIO;
ext2_put_page(page);
- goto done;
+ return -EIO;
}
if (de->inode) {
int over;
@@ -306,19 +307,14 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
le32_to_cpu(de->inode), d_type);
if (over) {
ext2_put_page(page);
- goto success;
+ return 0;
}
}
filp->f_pos += le16_to_cpu(de->rec_len);
}
ext2_put_page(page);
}
-
-success:
- ret = 0;
-done:
- filp->f_version = inode->i_version;
- return ret;
+ return 0;
}
/*
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 3fc4238e9703..0384e539b88f 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -1624,15 +1624,14 @@ static int ext3_block_truncate_page(handle_t *handle, struct page *page,
* For "nobh" option, we can only work if we don't need to
* read-in the page - otherwise we create buffers to do the IO.
*/
- if (!page_has_buffers(page) && test_opt(inode->i_sb, NOBH)) {
- if (PageUptodate(page)) {
- kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr + offset, 0, length);
- flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
- set_page_dirty(page);
- goto unlock;
- }
+ if (!page_has_buffers(page) && test_opt(inode->i_sb, NOBH) &&
+ ext3_should_writeback_data(inode) && PageUptodate(page)) {
+ kaddr = kmap_atomic(page, KM_USER0);
+ memset(kaddr + offset, 0, length);
+ flush_dcache_page(page);
+ kunmap_atomic(kaddr, KM_USER0);
+ set_page_dirty(page);
+ goto unlock;
}
if (!page_has_buffers(page))
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index 8bd8ac077704..b8f5cd1e540d 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -2141,7 +2141,8 @@ retry:
* We have a transaction open. All is sweetness. It also sets
* i_size in generic_commit_write().
*/
- err = page_symlink(inode, symname, l);
+ err = __page_symlink(inode, symname, l,
+ mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS);
if (err) {
ext3_dec_count(handle, inode);
ext3_mark_inode_dirty(handle, inode);
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index db0de5c621c7..4095bc149eb1 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -114,7 +114,7 @@ static inline int fat_get_entry(struct inode *dir, loff_t *pos,
}
/*
- * Convert Unicode 16 to UTF8, translated Unicode, or ASCII.
+ * Convert Unicode 16 to UTF-8, translated Unicode, or ASCII.
* If uni_xlate is enabled and we can't get a 1:1 conversion, use a
* colon as an escape character since it is normally invalid on the vfat
* filesystem. The following four characters are the hexadecimal digits
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index e7f4aa7fc686..e78d7b4842cc 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -1101,7 +1101,7 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug,
return -EINVAL;
}
}
- /* UTF8 doesn't provide FAT semantics */
+ /* UTF-8 doesn't provide FAT semantics */
if (!strcmp(opts->iocharset, "utf8")) {
printk(KERN_ERR "FAT: utf8 is not a recommended IO charset"
" for FAT filesystems, filesystem will be case sensitive!\n");
diff --git a/fs/fifo.c b/fs/fifo.c
index 923371b753ab..d13fcd3ec803 100644
--- a/fs/fifo.c
+++ b/fs/fifo.c
@@ -34,10 +34,7 @@ static int fifo_open(struct inode *inode, struct file *filp)
{
int ret;
- ret = -ERESTARTSYS;
- if (mutex_lock_interruptible(PIPE_MUTEX(*inode)))
- goto err_nolock_nocleanup;
-
+ mutex_lock(PIPE_MUTEX(*inode));
if (!inode->i_pipe) {
ret = -ENOMEM;
if(!pipe_new(inode))
@@ -140,8 +137,6 @@ err:
err_nocleanup:
mutex_unlock(PIPE_MUTEX(*inode));
-
-err_nolock_nocleanup:
return ret;
}
diff --git a/fs/file_table.c b/fs/file_table.c
index 768b58167543..44fabeaa9415 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -5,6 +5,7 @@
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
*/
+#include <linux/config.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/file.h>
@@ -19,52 +20,67 @@
#include <linux/capability.h>
#include <linux/cdev.h>
#include <linux/fsnotify.h>
+#include <linux/sysctl.h>
+#include <linux/percpu_counter.h>
+
+#include <asm/atomic.h>
/* sysctl tunables... */
struct files_stat_struct files_stat = {
.max_files = NR_FILE
};
-EXPORT_SYMBOL(files_stat); /* Needed by unix.o */
-
/* public. Not pretty! */
- __cacheline_aligned_in_smp DEFINE_SPINLOCK(files_lock);
+__cacheline_aligned_in_smp DEFINE_SPINLOCK(files_lock);
-static DEFINE_SPINLOCK(filp_count_lock);
+static struct percpu_counter nr_files __cacheline_aligned_in_smp;
-/* slab constructors and destructors are called from arbitrary
- * context and must be fully threaded - use a local spinlock
- * to protect files_stat.nr_files
- */
-void filp_ctor(void *objp, struct kmem_cache *cachep, unsigned long cflags)
+static inline void file_free_rcu(struct rcu_head *head)
{
- if ((cflags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR) {
- unsigned long flags;
- spin_lock_irqsave(&filp_count_lock, flags);
- files_stat.nr_files++;
- spin_unlock_irqrestore(&filp_count_lock, flags);
- }
+ struct file *f = container_of(head, struct file, f_u.fu_rcuhead);
+ kmem_cache_free(filp_cachep, f);
}
-void filp_dtor(void *objp, struct kmem_cache *cachep, unsigned long dflags)
+static inline void file_free(struct file *f)
{
- unsigned long flags;
- spin_lock_irqsave(&filp_count_lock, flags);
- files_stat.nr_files--;
- spin_unlock_irqrestore(&filp_count_lock, flags);
+ percpu_counter_dec(&nr_files);
+ call_rcu(&f->f_u.fu_rcuhead, file_free_rcu);
}
-static inline void file_free_rcu(struct rcu_head *head)
+/*
+ * Return the total number of open files in the system
+ */
+static int get_nr_files(void)
{
- struct file *f = container_of(head, struct file, f_u.fu_rcuhead);
- kmem_cache_free(filp_cachep, f);
+ return percpu_counter_read_positive(&nr_files);
}
-static inline void file_free(struct file *f)
+/*
+ * Return the maximum number of open files in the system
+ */
+int get_max_files(void)
{
- call_rcu(&f->f_u.fu_rcuhead, file_free_rcu);
+ return files_stat.max_files;
}
+EXPORT_SYMBOL_GPL(get_max_files);
+
+/*
+ * Handle nr_files sysctl
+ */
+#if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS)
+int proc_nr_files(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ files_stat.nr_files = get_nr_files();
+ return proc_dointvec(table, write, filp, buffer, lenp, ppos);
+}
+#else
+int proc_nr_files(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ return -ENOSYS;
+}
+#endif
/* Find an unused file structure and return a pointer to it.
* Returns NULL, if there are no more free file structures or
@@ -78,14 +94,20 @@ struct file *get_empty_filp(void)
/*
* Privileged users can go above max_files
*/
- if (files_stat.nr_files >= files_stat.max_files &&
- !capable(CAP_SYS_ADMIN))
- goto over;
+ if (get_nr_files() >= files_stat.max_files && !capable(CAP_SYS_ADMIN)) {
+ /*
+ * percpu_counters are inaccurate. Do an expensive check before
+ * we go and fail.
+ */
+ if (percpu_counter_sum(&nr_files) >= files_stat.max_files)
+ goto over;
+ }
f = kmem_cache_alloc(filp_cachep, GFP_KERNEL);
if (f == NULL)
goto fail;
+ percpu_counter_inc(&nr_files);
memset(f, 0, sizeof(*f));
if (security_file_alloc(f))
goto fail_sec;
@@ -101,10 +123,10 @@ struct file *get_empty_filp(void)
over:
/* Ran out of filps - report that */
- if (files_stat.nr_files > old_max) {
+ if (get_nr_files() > old_max) {
printk(KERN_INFO "VFS: file-max limit %d reached\n",
- files_stat.max_files);
- old_max = files_stat.nr_files;
+ get_max_files());
+ old_max = get_nr_files();
}
goto fail;
@@ -276,4 +298,5 @@ void __init files_init(unsigned long mempages)
if (files_stat.max_files < NR_FILE)
files_stat.max_files = NR_FILE;
files_defer_init();
+ percpu_counter_init(&nr_files);
}
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 21fd59c7bc24..c72a8a97935c 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -111,6 +111,8 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
/* Doesn't hurt to "reset" the validity timeout */
fuse_invalidate_entry_cache(entry);
+
+ /* For negative dentries, always do a fresh lookup */
if (!inode)
return 0;
@@ -122,6 +124,9 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg);
request_send(fc, req);
err = req->out.h.error;
+ /* Zero nodeid is same as -ENOENT */
+ if (!err && !outarg.nodeid)
+ err = -ENOENT;
if (!err) {
struct fuse_inode *fi = get_fuse_inode(inode);
if (outarg.nodeid != get_node_id(inode)) {
@@ -190,8 +195,9 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
fuse_lookup_init(req, dir, entry, &outarg);
request_send(fc, req);
err = req->out.h.error;
- if (!err && ((outarg.nodeid && invalid_nodeid(outarg.nodeid)) ||
- !valid_mode(outarg.attr.mode)))
+ /* Zero nodeid is same as -ENOENT, but with valid timeout */
+ if (!err && outarg.nodeid &&
+ (invalid_nodeid(outarg.nodeid) || !valid_mode(outarg.attr.mode)))
err = -EIO;
if (!err && outarg.nodeid) {
inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index b35195289945..25fa8bba8cb5 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -56,48 +56,10 @@ static void huge_pagevec_release(struct pagevec *pvec)
pagevec_reinit(pvec);
}
-/*
- * huge_pages_needed tries to determine the number of new huge pages that
- * will be required to fully populate this VMA. This will be equal to
- * the size of the VMA in huge pages minus the number of huge pages
- * (covered by this VMA) that are found in the page cache.
- *
- * Result is in bytes to be compatible with is_hugepage_mem_enough()
- */
-static unsigned long
-huge_pages_needed(struct address_space *mapping, struct vm_area_struct *vma)
-{
- int i;
- struct pagevec pvec;
- unsigned long start = vma->vm_start;
- unsigned long end = vma->vm_end;
- unsigned long hugepages = (end - start) >> HPAGE_SHIFT;
- pgoff_t next = vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT);
- pgoff_t endpg = next + hugepages;
-
- pagevec_init(&pvec, 0);
- while (next < endpg) {
- if (!pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE))
- break;
- for (i = 0; i < pagevec_count(&pvec); i++) {
- struct page *page = pvec.pages[i];
- if (page->index > next)
- next = page->index;
- if (page->index >= endpg)
- break;
- next++;
- hugepages--;
- }
- huge_pagevec_release(&pvec);
- }
- return hugepages << HPAGE_SHIFT;
-}
-
static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)
{
struct inode *inode = file->f_dentry->d_inode;
- struct address_space *mapping = inode->i_mapping;
- unsigned long bytes;
+ struct hugetlbfs_inode_info *info = HUGETLBFS_I(inode);
loff_t len, vma_len;
int ret;
@@ -113,10 +75,6 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)
if (vma->vm_end - vma->vm_start < HPAGE_SIZE)
return -EINVAL;
- bytes = huge_pages_needed(mapping, vma);
- if (!is_hugepage_mem_enough(bytes))
- return -ENOMEM;
-
vma_len = (loff_t)(vma->vm_end - vma->vm_start);
mutex_lock(&inode->i_mutex);
@@ -129,6 +87,10 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)
if (!(vma->vm_flags & VM_WRITE) && len > inode->i_size)
goto out;
+ if (vma->vm_flags & VM_MAYSHARE)
+ if (hugetlb_extend_reservation(info, len >> HPAGE_SHIFT) != 0)
+ goto out;
+
ret = 0;
hugetlb_prefault_arch_hook(vma->vm_mm);
if (inode->i_size < len)
@@ -227,13 +189,18 @@ static void truncate_huge_page(struct page *page)
put_page(page);
}
-static void truncate_hugepages(struct address_space *mapping, loff_t lstart)
+static void truncate_hugepages(struct inode *inode, loff_t lstart)
{
+ struct address_space *mapping = &inode->i_data;
const pgoff_t start = lstart >> HPAGE_SHIFT;
struct pagevec pvec;
pgoff_t next;
int i;
+ hugetlb_truncate_reservation(HUGETLBFS_I(inode),
+ lstart >> HPAGE_SHIFT);
+ if (!mapping->nrpages)
+ return;
pagevec_init(&pvec, 0);
next = start;
while (1) {
@@ -262,8 +229,7 @@ static void truncate_hugepages(struct address_space *mapping, loff_t lstart)
static void hugetlbfs_delete_inode(struct inode *inode)
{
- if (inode->i_data.nrpages)
- truncate_hugepages(&inode->i_data, 0);
+ truncate_hugepages(inode, 0);
clear_inode(inode);
}
@@ -296,8 +262,7 @@ static void hugetlbfs_forget_inode(struct inode *inode)
inode->i_state |= I_FREEING;
inodes_stat.nr_inodes--;
spin_unlock(&inode_lock);
- if (inode->i_data.nrpages)
- truncate_hugepages(&inode->i_data, 0);
+ truncate_hugepages(inode, 0);
clear_inode(inode);
destroy_inode(inode);
}
@@ -356,7 +321,7 @@ static int hugetlb_vmtruncate(struct inode *inode, loff_t offset)
if (!prio_tree_empty(&mapping->i_mmap))
hugetlb_vmtruncate_list(&mapping->i_mmap, pgoff);
spin_unlock(&mapping->i_mmap_lock);
- truncate_hugepages(mapping, offset);
+ truncate_hugepages(inode, offset);
return 0;
}
@@ -573,6 +538,7 @@ static struct inode *hugetlbfs_alloc_inode(struct super_block *sb)
hugetlbfs_inc_free_inodes(sbinfo);
return NULL;
}
+ p->prereserved_hpages = 0;
return &p->vfs_inode;
}
@@ -771,21 +737,6 @@ static struct file_system_type hugetlbfs_fs_type = {
static struct vfsmount *hugetlbfs_vfsmount;
-/*
- * Return the next identifier for a shm file
- */
-static unsigned long hugetlbfs_counter(void)
-{
- static DEFINE_SPINLOCK(lock);
- static unsigned long counter;
- unsigned long ret;
-
- spin_lock(&lock);
- ret = ++counter;
- spin_unlock(&lock);
- return ret;
-}
-
static int can_do_hugetlb_shm(void)
{
return likely(capable(CAP_IPC_LOCK) ||
@@ -801,18 +752,16 @@ struct file *hugetlb_zero_setup(size_t size)
struct dentry *dentry, *root;
struct qstr quick_string;
char buf[16];
+ static atomic_t counter;
if (!can_do_hugetlb_shm())
return ERR_PTR(-EPERM);
- if (!is_hugepage_mem_enough(size))
- return ERR_PTR(-ENOMEM);
-
if (!user_shm_lock(size, current->user))
return ERR_PTR(-ENOMEM);
root = hugetlbfs_vfsmount->mnt_root;
- snprintf(buf, 16, "%lu", hugetlbfs_counter());
+ snprintf(buf, 16, "%u", atomic_inc_return(&counter));
quick_string.name = buf;
quick_string.len = strlen(quick_string.name);
quick_string.hash = 0;
@@ -831,6 +780,11 @@ struct file *hugetlb_zero_setup(size_t size)
if (!inode)
goto out_file;
+ error = -ENOMEM;
+ if (hugetlb_extend_reservation(HUGETLBFS_I(inode),
+ size >> HPAGE_SHIFT) != 0)
+ goto out_inode;
+
d_instantiate(dentry, inode);
inode->i_size = size;
inode->i_nlink = 0;
@@ -841,6 +795,8 @@ struct file *hugetlb_zero_setup(size_t size)
file->f_mode = FMODE_WRITE | FMODE_READ;
return file;
+out_inode:
+ iput(inode);
out_file:
put_filp(file);
out_dentry:
diff --git a/fs/isofs/joliet.c b/fs/isofs/joliet.c
index 2931de7f1a6a..81a90e170ac3 100644
--- a/fs/isofs/joliet.c
+++ b/fs/isofs/joliet.c
@@ -11,7 +11,7 @@
#include "isofs.h"
/*
- * Convert Unicode 16 to UTF8 or ASCII.
+ * Convert Unicode 16 to UTF-8 or ASCII.
*/
static int
uni16_to_x8(unsigned char *ascii, u16 *uni, int len, struct nls_table *nls)
diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c
index b635e167a3fa..d4d0c41490cd 100644
--- a/fs/jffs2/nodelist.c
+++ b/fs/jffs2/nodelist.c
@@ -406,7 +406,8 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info
int err = 0, pointed = 0;
struct jffs2_eraseblock *jeb;
unsigned char *buffer;
- uint32_t crc, ofs, retlen, len;
+ uint32_t crc, ofs, len;
+ size_t retlen;
BUG_ON(tn->csize == 0);
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
index 5f0652df5d47..f1695642d0f7 100644
--- a/fs/jffs2/readinode.c
+++ b/fs/jffs2/readinode.c
@@ -112,7 +112,7 @@ static struct jffs2_raw_node_ref *jffs2_first_valid_node(struct jffs2_raw_node_r
* negative error code on failure.
*/
static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref,
- struct jffs2_raw_dirent *rd, uint32_t read, struct jffs2_full_dirent **fdp,
+ struct jffs2_raw_dirent *rd, size_t read, struct jffs2_full_dirent **fdp,
uint32_t *latest_mctime, uint32_t *mctime_ver)
{
struct jffs2_full_dirent *fd;
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c
index 3e51dd1da8aa..cf55b221fc2b 100644
--- a/fs/jffs2/scan.c
+++ b/fs/jffs2/scan.c
@@ -233,7 +233,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
c->nextblock->dirty_size = 0;
}
#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
- if (!jffs2_can_mark_obsolete(c) && c->nextblock && (c->nextblock->free_size % c->wbuf_pagesize)) {
+ if (!jffs2_can_mark_obsolete(c) && c->wbuf_pagesize && c->nextblock && (c->nextblock->free_size % c->wbuf_pagesize)) {
/* If we're going to start writing into a block which already
contains data, and the end of the data isn't page-aligned,
skip a little and align it. */
diff --git a/fs/jfs/Makefile b/fs/jfs/Makefile
index 6f1e0e95587a..3adb6395e42d 100644
--- a/fs/jfs/Makefile
+++ b/fs/jfs/Makefile
@@ -8,7 +8,8 @@ jfs-y := super.o file.o inode.o namei.o jfs_mount.o jfs_umount.o \
jfs_xtree.o jfs_imap.o jfs_debug.o jfs_dmap.o \
jfs_unicode.o jfs_dtree.o jfs_inode.o \
jfs_extent.o symlink.o jfs_metapage.o \
- jfs_logmgr.o jfs_txnmgr.o jfs_uniupr.o resize.o xattr.o
+ jfs_logmgr.o jfs_txnmgr.o jfs_uniupr.o \
+ resize.o xattr.o ioctl.o
jfs-$(CONFIG_JFS_POSIX_ACL) += acl.o
diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c
index 461e4934ca7c..e2281300979c 100644
--- a/fs/jfs/acl.c
+++ b/fs/jfs/acl.c
@@ -183,6 +183,9 @@ cleanup:
posix_acl_release(acl);
} else
inode->i_mode &= ~current->fs->umask;
+
+ JFS_IP(inode)->mode2 = (JFS_IP(inode)->mode2 & 0xffff0000) |
+ inode->i_mode;
return rc;
}
@@ -207,12 +210,12 @@ static int jfs_acl_chmod(struct inode *inode)
rc = posix_acl_chmod_masq(clone, inode->i_mode);
if (!rc) {
tid_t tid = txBegin(inode->i_sb, 0);
- down(&JFS_IP(inode)->commit_sem);
+ mutex_lock(&JFS_IP(inode)->commit_mutex);
rc = jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, clone);
if (!rc)
rc = txCommit(tid, 1, &inode, 0);
txEnd(tid);
- up(&JFS_IP(inode)->commit_sem);
+ mutex_unlock(&JFS_IP(inode)->commit_mutex);
}
posix_acl_release(clone);
diff --git a/fs/jfs/file.c b/fs/jfs/file.c
index c2c19c9ed9a4..e1ac6e497e2b 100644
--- a/fs/jfs/file.c
+++ b/fs/jfs/file.c
@@ -113,4 +113,5 @@ struct file_operations jfs_file_operations = {
.sendfile = generic_file_sendfile,
.fsync = jfs_fsync,
.release = jfs_release,
+ .ioctl = jfs_ioctl,
};
diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c
index 9f942ca8e4e3..51a5fed90cca 100644
--- a/fs/jfs/inode.c
+++ b/fs/jfs/inode.c
@@ -55,6 +55,7 @@ void jfs_read_inode(struct inode *inode)
inode->i_op = &jfs_file_inode_operations;
init_special_inode(inode, inode->i_mode, inode->i_rdev);
}
+ jfs_set_inode_flags(inode);
}
/*
@@ -89,16 +90,16 @@ int jfs_commit_inode(struct inode *inode, int wait)
}
tid = txBegin(inode->i_sb, COMMIT_INODE);
- down(&JFS_IP(inode)->commit_sem);
+ mutex_lock(&JFS_IP(inode)->commit_mutex);
/*
- * Retest inode state after taking commit_sem
+ * Retest inode state after taking commit_mutex
*/
if (inode->i_nlink && test_cflag(COMMIT_Dirty, inode))
rc = txCommit(tid, 1, &inode, wait ? COMMIT_SYNC : 0);
txEnd(tid);
- up(&JFS_IP(inode)->commit_sem);
+ mutex_unlock(&JFS_IP(inode)->commit_mutex);
return rc;
}
@@ -335,18 +336,18 @@ void jfs_truncate_nolock(struct inode *ip, loff_t length)
tid = txBegin(ip->i_sb, 0);
/*
- * The commit_sem cannot be taken before txBegin.
+ * The commit_mutex cannot be taken before txBegin.
* txBegin may block and there is a chance the inode
* could be marked dirty and need to be committed
* before txBegin unblocks
*/
- down(&JFS_IP(ip)->commit_sem);
+ mutex_lock(&JFS_IP(ip)->commit_mutex);
newsize = xtTruncate(tid, ip, length,
COMMIT_TRUNCATE | COMMIT_PWMAP);
if (newsize < 0) {
txEnd(tid);
- up(&JFS_IP(ip)->commit_sem);
+ mutex_unlock(&JFS_IP(ip)->commit_mutex);
break;
}
@@ -355,7 +356,7 @@ void jfs_truncate_nolock(struct inode *ip, loff_t length)
txCommit(tid, 1, &ip, 0);
txEnd(tid);
- up(&JFS_IP(ip)->commit_sem);
+ mutex_unlock(&JFS_IP(ip)->commit_mutex);
} while (newsize > length); /* Truncate isn't always atomic */
}
diff --git a/fs/jfs/ioctl.c b/fs/jfs/ioctl.c
new file mode 100644
index 000000000000..67b3774820eb
--- /dev/null
+++ b/fs/jfs/ioctl.c
@@ -0,0 +1,107 @@
+/*
+ * linux/fs/jfs/ioctl.c
+ *
+ * Copyright (C) 2006 Herbert Poetzl
+ * adapted from Remy Card's ext2/ioctl.c
+ */
+
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+#include <linux/ctype.h>
+#include <linux/capability.h>
+#include <linux/time.h>
+#include <asm/current.h>
+#include <asm/uaccess.h>
+
+#include "jfs_incore.h"
+#include "jfs_dinode.h"
+#include "jfs_inode.h"
+
+
+static struct {
+ long jfs_flag;
+ long ext2_flag;
+} jfs_map[] = {
+ {JFS_NOATIME_FL, EXT2_NOATIME_FL},
+ {JFS_DIRSYNC_FL, EXT2_DIRSYNC_FL},
+ {JFS_SYNC_FL, EXT2_SYNC_FL},
+ {JFS_SECRM_FL, EXT2_SECRM_FL},
+ {JFS_UNRM_FL, EXT2_UNRM_FL},
+ {JFS_APPEND_FL, EXT2_APPEND_FL},
+ {JFS_IMMUTABLE_FL, EXT2_IMMUTABLE_FL},
+ {0, 0},
+};
+
+static long jfs_map_ext2(unsigned long flags, int from)
+{
+ int index=0;
+ long mapped=0;
+
+ while (jfs_map[index].jfs_flag) {
+ if (from) {
+ if (jfs_map[index].ext2_flag & flags)
+ mapped |= jfs_map[index].jfs_flag;
+ } else {
+ if (jfs_map[index].jfs_flag & flags)
+ mapped |= jfs_map[index].ext2_flag;
+ }
+ index++;
+ }
+ return mapped;
+}
+
+
+int jfs_ioctl(struct inode * inode, struct file * filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct jfs_inode_info *jfs_inode = JFS_IP(inode);
+ unsigned int flags;
+
+ switch (cmd) {
+ case JFS_IOC_GETFLAGS:
+ flags = jfs_inode->mode2 & JFS_FL_USER_VISIBLE;
+ flags = jfs_map_ext2(flags, 0);
+ return put_user(flags, (int __user *) arg);
+ case JFS_IOC_SETFLAGS: {
+ unsigned int oldflags;
+
+ if (IS_RDONLY(inode))
+ return -EROFS;
+
+ if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+ return -EACCES;
+
+ if (get_user(flags, (int __user *) arg))
+ return -EFAULT;
+
+ flags = jfs_map_ext2(flags, 1);
+ if (!S_ISDIR(inode->i_mode))
+ flags &= ~JFS_DIRSYNC_FL;
+
+ oldflags = jfs_inode->mode2;
+
+ /*
+ * The IMMUTABLE and APPEND_ONLY flags can only be changed by
+ * the relevant capability.
+ */
+ if ((oldflags & JFS_IMMUTABLE_FL) ||
+ ((flags ^ oldflags) &
+ (JFS_APPEND_FL | JFS_IMMUTABLE_FL))) {
+ if (!capable(CAP_LINUX_IMMUTABLE))
+ return -EPERM;
+ }
+
+ flags = flags & JFS_FL_USER_MODIFIABLE;
+ flags |= oldflags & ~JFS_FL_USER_MODIFIABLE;
+ jfs_inode->mode2 = flags;
+
+ jfs_set_inode_flags(inode);
+ inode->i_ctime = CURRENT_TIME_SEC;
+ mark_inode_dirty(inode);
+ return 0;
+ }
+ default:
+ return -ENOTTY;
+ }
+}
+
diff --git a/fs/jfs/jfs_dinode.h b/fs/jfs/jfs_dinode.h
index 580a3258449b..9f2572aea561 100644
--- a/fs/jfs/jfs_dinode.h
+++ b/fs/jfs/jfs_dinode.h
@@ -139,13 +139,36 @@ struct dinode {
/* more extended mode bits: attributes for OS/2 */
#define IREADONLY 0x02000000 /* no write access to file */
-#define IARCHIVE 0x40000000 /* file archive bit */
-#define ISYSTEM 0x08000000 /* system file */
#define IHIDDEN 0x04000000 /* hidden file */
-#define IRASH 0x4E000000 /* mask for changeable attributes */
-#define INEWNAME 0x80000000 /* non-8.3 filename format */
+#define ISYSTEM 0x08000000 /* system file */
+
#define IDIRECTORY 0x20000000 /* directory (shadow of real bit) */
+#define IARCHIVE 0x40000000 /* file archive bit */
+#define INEWNAME 0x80000000 /* non-8.3 filename format */
+
+#define IRASH 0x4E000000 /* mask for changeable attributes */
#define ATTRSHIFT 25 /* bits to shift to move attribute
specification to mode position */
+/* extended attributes for Linux */
+
+#define JFS_NOATIME_FL 0x00080000 /* do not update atime */
+
+#define JFS_DIRSYNC_FL 0x00100000 /* dirsync behaviour */
+#define JFS_SYNC_FL 0x00200000 /* Synchronous updates */
+#define JFS_SECRM_FL 0x00400000 /* Secure deletion */
+#define JFS_UNRM_FL 0x00800000 /* allow for undelete */
+
+#define JFS_APPEND_FL 0x01000000 /* writes to file may only append */
+#define JFS_IMMUTABLE_FL 0x02000000 /* Immutable file */
+
+#define JFS_FL_USER_VISIBLE 0x03F80000
+#define JFS_FL_USER_MODIFIABLE 0x03F80000
+#define JFS_FL_INHERIT 0x03C80000
+
+/* These are identical to EXT[23]_IOC_GETFLAGS/SETFLAGS */
+#define JFS_IOC_GETFLAGS _IOR('f', 1, long)
+#define JFS_IOC_SETFLAGS _IOW('f', 2, long)
+
+
#endif /*_H_JFS_DINODE */
diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c
index 2967b7393415..c161c98954e0 100644
--- a/fs/jfs/jfs_dmap.c
+++ b/fs/jfs/jfs_dmap.c
@@ -64,9 +64,9 @@
* to the persistent bitmaps in dmaps) is guarded by (busy) buffers.
*/
-#define BMAP_LOCK_INIT(bmp) init_MUTEX(&bmp->db_bmaplock)
-#define BMAP_LOCK(bmp) down(&bmp->db_bmaplock)
-#define BMAP_UNLOCK(bmp) up(&bmp->db_bmaplock)
+#define BMAP_LOCK_INIT(bmp) mutex_init(&bmp->db_bmaplock)
+#define BMAP_LOCK(bmp) mutex_lock(&bmp->db_bmaplock)
+#define BMAP_UNLOCK(bmp) mutex_unlock(&bmp->db_bmaplock)
/*
* forward references
@@ -125,7 +125,7 @@ static int dbGetL2AGSize(s64 nblocks);
* into the table, with the table elements yielding the maximum
* binary buddy of free bits within the character.
*/
-static s8 budtab[256] = {
+static const s8 budtab[256] = {
3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -532,10 +532,10 @@ dbUpdatePMap(struct inode *ipbmap,
lastlblkno = lblkno;
+ LOGSYNC_LOCK(log, flags);
if (mp->lsn != 0) {
/* inherit older/smaller lsn */
logdiff(diffp, mp->lsn, log);
- LOGSYNC_LOCK(log, flags);
if (difft < diffp) {
mp->lsn = lsn;
@@ -548,20 +548,17 @@ dbUpdatePMap(struct inode *ipbmap,
logdiff(diffp, mp->clsn, log);
if (difft > diffp)
mp->clsn = tblk->clsn;
- LOGSYNC_UNLOCK(log, flags);
} else {
mp->log = log;
mp->lsn = lsn;
/* insert bp after tblock in logsync list */
- LOGSYNC_LOCK(log, flags);
-
log->count++;
list_add(&mp->synclist, &tblk->synclist);
mp->clsn = tblk->clsn;
- LOGSYNC_UNLOCK(log, flags);
}
+ LOGSYNC_UNLOCK(log, flags);
}
/* write the last buffer. */
diff --git a/fs/jfs/jfs_dmap.h b/fs/jfs/jfs_dmap.h
index 32e25884e7e8..8b14cc8e0228 100644
--- a/fs/jfs/jfs_dmap.h
+++ b/fs/jfs/jfs_dmap.h
@@ -243,7 +243,7 @@ struct dbmap {
struct bmap {
struct dbmap db_bmap; /* on-disk aggregate map descriptor */
struct inode *db_ipbmap; /* ptr to aggregate map incore inode */
- struct semaphore db_bmaplock; /* aggregate map lock */
+ struct mutex db_bmaplock; /* aggregate map lock */
atomic_t db_active[MAXAG]; /* count of active, open files in AG */
u32 *db_DBmap;
};
diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c
index 404f33eae507..6c3f08319846 100644
--- a/fs/jfs/jfs_dtree.c
+++ b/fs/jfs/jfs_dtree.c
@@ -1005,6 +1005,9 @@ static int dtSplitUp(tid_t tid,
DT_PUTPAGE(smp);
+ if (!DO_INDEX(ip))
+ ip->i_size = xlen << sbi->l2bsize;
+
goto freeKeyName;
}
@@ -1055,7 +1058,9 @@ static int dtSplitUp(tid_t tid,
xaddr = addressPXD(pxd) + xlen;
dbFree(ip, xaddr, (s64) n);
}
- }
+ } else if (!DO_INDEX(ip))
+ ip->i_size = lengthPXD(pxd) << sbi->l2bsize;
+
extendOut:
DT_PUTPAGE(smp);
@@ -1098,6 +1103,9 @@ static int dtSplitUp(tid_t tid,
goto splitOut;
}
+ if (!DO_INDEX(ip))
+ ip->i_size += PSIZE;
+
/*
* propagate up the router entry for the leaf page just split
*
@@ -2424,6 +2432,9 @@ static int dtDeleteUp(tid_t tid, struct inode *ip,
break;
}
+ if (!DO_INDEX(ip))
+ ip->i_size -= PSIZE;
+
return 0;
}
diff --git a/fs/jfs/jfs_extent.c b/fs/jfs/jfs_extent.c
index 4879603daa1c..5549378358bf 100644
--- a/fs/jfs/jfs_extent.c
+++ b/fs/jfs/jfs_extent.c
@@ -94,7 +94,7 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr)
txBeginAnon(ip->i_sb);
/* Avoid race with jfs_commit_inode() */
- down(&JFS_IP(ip)->commit_sem);
+ mutex_lock(&JFS_IP(ip)->commit_mutex);
/* validate extent length */
if (xlen > MAXXLEN)
@@ -136,14 +136,14 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr)
*/
nxlen = xlen;
if ((rc = extBalloc(ip, hint ? hint : INOHINT(ip), &nxlen, &nxaddr))) {
- up(&JFS_IP(ip)->commit_sem);
+ mutex_unlock(&JFS_IP(ip)->commit_mutex);
return (rc);
}
/* Allocate blocks to quota. */
if (DQUOT_ALLOC_BLOCK(ip, nxlen)) {
dbFree(ip, nxaddr, (s64) nxlen);
- up(&JFS_IP(ip)->commit_sem);
+ mutex_unlock(&JFS_IP(ip)->commit_mutex);
return -EDQUOT;
}
@@ -165,7 +165,7 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr)
if (rc) {
dbFree(ip, nxaddr, nxlen);
DQUOT_FREE_BLOCK(ip, nxlen);
- up(&JFS_IP(ip)->commit_sem);
+ mutex_unlock(&JFS_IP(ip)->commit_mutex);
return (rc);
}
@@ -177,7 +177,7 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr)
mark_inode_dirty(ip);
- up(&JFS_IP(ip)->commit_sem);
+ mutex_unlock(&JFS_IP(ip)->commit_mutex);
/*
* COMMIT_SyncList flags an anonymous tlock on page that is on
* sync list.
@@ -222,7 +222,7 @@ int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, boolean_t abnr)
/* This blocks if we are low on resources */
txBeginAnon(ip->i_sb);
- down(&JFS_IP(ip)->commit_sem);
+ mutex_lock(&JFS_IP(ip)->commit_mutex);
/* validate extent length */
if (nxlen > MAXXLEN)
nxlen = MAXXLEN;
@@ -258,7 +258,7 @@ int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, boolean_t abnr)
/* Allocat blocks to quota. */
if (DQUOT_ALLOC_BLOCK(ip, nxlen)) {
dbFree(ip, nxaddr, (s64) nxlen);
- up(&JFS_IP(ip)->commit_sem);
+ mutex_unlock(&JFS_IP(ip)->commit_mutex);
return -EDQUOT;
}
@@ -338,7 +338,7 @@ int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, boolean_t abnr)
mark_inode_dirty(ip);
exit:
- up(&JFS_IP(ip)->commit_sem);
+ mutex_unlock(&JFS_IP(ip)->commit_mutex);
return (rc);
}
#endif /* _NOTYET */
@@ -439,12 +439,12 @@ int extRecord(struct inode *ip, xad_t * xp)
txBeginAnon(ip->i_sb);
- down(&JFS_IP(ip)->commit_sem);
+ mutex_lock(&JFS_IP(ip)->commit_mutex);
/* update the extent */
rc = xtUpdate(0, ip, xp);
- up(&JFS_IP(ip)->commit_sem);
+ mutex_unlock(&JFS_IP(ip)->commit_mutex);
return rc;
}
diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c
index 31b4aa13dd4b..ccbe60aff83d 100644
--- a/fs/jfs/jfs_imap.c
+++ b/fs/jfs/jfs_imap.c
@@ -66,14 +66,14 @@ static HLIST_HEAD(aggregate_hash);
* imap locks
*/
/* iag free list lock */
-#define IAGFREE_LOCK_INIT(imap) init_MUTEX(&imap->im_freelock)
-#define IAGFREE_LOCK(imap) down(&imap->im_freelock)
-#define IAGFREE_UNLOCK(imap) up(&imap->im_freelock)
+#define IAGFREE_LOCK_INIT(imap) mutex_init(&imap->im_freelock)
+#define IAGFREE_LOCK(imap) mutex_lock(&imap->im_freelock)
+#define IAGFREE_UNLOCK(imap) mutex_unlock(&imap->im_freelock)
/* per ag iag list locks */
-#define AG_LOCK_INIT(imap,index) init_MUTEX(&(imap->im_aglock[index]))
-#define AG_LOCK(imap,agno) down(&imap->im_aglock[agno])
-#define AG_UNLOCK(imap,agno) up(&imap->im_aglock[agno])
+#define AG_LOCK_INIT(imap,index) mutex_init(&(imap->im_aglock[index]))
+#define AG_LOCK(imap,agno) mutex_lock(&imap->im_aglock[agno])
+#define AG_UNLOCK(imap,agno) mutex_unlock(&imap->im_aglock[agno])
/*
* forward references
@@ -1261,7 +1261,7 @@ int diFree(struct inode *ip)
* to be freed by the transaction;
*/
tid = txBegin(ipimap->i_sb, COMMIT_FORCE);
- down(&JFS_IP(ipimap)->commit_sem);
+ mutex_lock(&JFS_IP(ipimap)->commit_mutex);
/* acquire tlock of the iag page of the freed ixad
* to force the page NOHOMEOK (even though no data is
@@ -1294,7 +1294,7 @@ int diFree(struct inode *ip)
rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE);
txEnd(tid);
- up(&JFS_IP(ipimap)->commit_sem);
+ mutex_unlock(&JFS_IP(ipimap)->commit_mutex);
/* unlock the AG inode map information */
AG_UNLOCK(imap, agno);
@@ -2554,13 +2554,13 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
* addressing structure pointing to the new iag page;
*/
tid = txBegin(sb, COMMIT_FORCE);
- down(&JFS_IP(ipimap)->commit_sem);
+ mutex_lock(&JFS_IP(ipimap)->commit_mutex);
/* update the inode map addressing structure to point to it */
if ((rc =
xtInsert(tid, ipimap, 0, blkno, xlen, &xaddr, 0))) {
txEnd(tid);
- up(&JFS_IP(ipimap)->commit_sem);
+ mutex_unlock(&JFS_IP(ipimap)->commit_mutex);
/* Free the blocks allocated for the iag since it was
* not successfully added to the inode map
*/
@@ -2626,7 +2626,7 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE);
txEnd(tid);
- up(&JFS_IP(ipimap)->commit_sem);
+ mutex_unlock(&JFS_IP(ipimap)->commit_mutex);
duplicateIXtree(sb, blkno, xlen, &xaddr);
@@ -2844,11 +2844,11 @@ diUpdatePMap(struct inode *ipimap,
*/
lsn = tblk->lsn;
log = JFS_SBI(tblk->sb)->log;
+ LOGSYNC_LOCK(log, flags);
if (mp->lsn != 0) {
/* inherit older/smaller lsn */
logdiff(difft, lsn, log);
logdiff(diffp, mp->lsn, log);
- LOGSYNC_LOCK(log, flags);
if (difft < diffp) {
mp->lsn = lsn;
/* move mp after tblock in logsync list */
@@ -2860,17 +2860,15 @@ diUpdatePMap(struct inode *ipimap,
logdiff(diffp, mp->clsn, log);
if (difft > diffp)
mp->clsn = tblk->clsn;
- LOGSYNC_UNLOCK(log, flags);
} else {
mp->log = log;
mp->lsn = lsn;
/* insert mp after tblock in logsync list */
- LOGSYNC_LOCK(log, flags);
log->count++;
list_add(&mp->synclist, &tblk->synclist);
mp->clsn = tblk->clsn;
- LOGSYNC_UNLOCK(log, flags);
}
+ LOGSYNC_UNLOCK(log, flags);
write_metapage(mp);
return (0);
}
@@ -3076,14 +3074,40 @@ static void duplicateIXtree(struct super_block *sb, s64 blkno,
static int copy_from_dinode(struct dinode * dip, struct inode *ip)
{
struct jfs_inode_info *jfs_ip = JFS_IP(ip);
+ struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
jfs_ip->fileset = le32_to_cpu(dip->di_fileset);
jfs_ip->mode2 = le32_to_cpu(dip->di_mode);
ip->i_mode = le32_to_cpu(dip->di_mode) & 0xffff;
+ if (sbi->umask != -1) {
+ ip->i_mode = (ip->i_mode & ~0777) | (0777 & ~sbi->umask);
+ /* For directories, add x permission if r is allowed by umask */
+ if (S_ISDIR(ip->i_mode)) {
+ if (ip->i_mode & 0400)
+ ip->i_mode |= 0100;
+ if (ip->i_mode & 0040)
+ ip->i_mode |= 0010;
+ if (ip->i_mode & 0004)
+ ip->i_mode |= 0001;
+ }
+ }
ip->i_nlink = le32_to_cpu(dip->di_nlink);
- ip->i_uid = le32_to_cpu(dip->di_uid);
- ip->i_gid = le32_to_cpu(dip->di_gid);
+
+ jfs_ip->saved_uid = le32_to_cpu(dip->di_uid);
+ if (sbi->uid == -1)
+ ip->i_uid = jfs_ip->saved_uid;
+ else {
+ ip->i_uid = sbi->uid;
+ }
+
+ jfs_ip->saved_gid = le32_to_cpu(dip->di_gid);
+ if (sbi->gid == -1)
+ ip->i_gid = jfs_ip->saved_gid;
+ else {
+ ip->i_gid = sbi->gid;
+ }
+
ip->i_size = le64_to_cpu(dip->di_size);
ip->i_atime.tv_sec = le32_to_cpu(dip->di_atime.tv_sec);
ip->i_atime.tv_nsec = le32_to_cpu(dip->di_atime.tv_nsec);
@@ -3134,21 +3158,33 @@ static int copy_from_dinode(struct dinode * dip, struct inode *ip)
static void copy_to_dinode(struct dinode * dip, struct inode *ip)
{
struct jfs_inode_info *jfs_ip = JFS_IP(ip);
+ struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
dip->di_fileset = cpu_to_le32(jfs_ip->fileset);
- dip->di_inostamp = cpu_to_le32(JFS_SBI(ip->i_sb)->inostamp);
+ dip->di_inostamp = cpu_to_le32(sbi->inostamp);
dip->di_number = cpu_to_le32(ip->i_ino);
dip->di_gen = cpu_to_le32(ip->i_generation);
dip->di_size = cpu_to_le64(ip->i_size);
dip->di_nblocks = cpu_to_le64(PBLK2LBLK(ip->i_sb, ip->i_blocks));
dip->di_nlink = cpu_to_le32(ip->i_nlink);
- dip->di_uid = cpu_to_le32(ip->i_uid);
- dip->di_gid = cpu_to_le32(ip->i_gid);
+ if (sbi->uid == -1)
+ dip->di_uid = cpu_to_le32(ip->i_uid);
+ else
+ dip->di_uid = cpu_to_le32(jfs_ip->saved_uid);
+ if (sbi->gid == -1)
+ dip->di_gid = cpu_to_le32(ip->i_gid);
+ else
+ dip->di_gid = cpu_to_le32(jfs_ip->saved_gid);
/*
* mode2 is only needed for storing the higher order bits.
* Trust i_mode for the lower order ones
*/
- dip->di_mode = cpu_to_le32((jfs_ip->mode2 & 0xffff0000) | ip->i_mode);
+ if (sbi->umask == -1)
+ dip->di_mode = cpu_to_le32((jfs_ip->mode2 & 0xffff0000) |
+ ip->i_mode);
+ else /* Leave the original permissions alone */
+ dip->di_mode = cpu_to_le32(jfs_ip->mode2);
+
dip->di_atime.tv_sec = cpu_to_le32(ip->i_atime.tv_sec);
dip->di_atime.tv_nsec = cpu_to_le32(ip->i_atime.tv_nsec);
dip->di_ctime.tv_sec = cpu_to_le32(ip->i_ctime.tv_sec);
diff --git a/fs/jfs/jfs_imap.h b/fs/jfs/jfs_imap.h
index 6b59adec036a..6e24465f0f98 100644
--- a/fs/jfs/jfs_imap.h
+++ b/fs/jfs/jfs_imap.h
@@ -140,8 +140,8 @@ struct dinomap {
struct inomap {
struct dinomap im_imap; /* 4096: inode allocation control */
struct inode *im_ipimap; /* 4: ptr to inode for imap */
- struct semaphore im_freelock; /* 4: iag free list lock */
- struct semaphore im_aglock[MAXAG]; /* 512: per AG locks */
+ struct mutex im_freelock; /* 4: iag free list lock */
+ struct mutex im_aglock[MAXAG]; /* 512: per AG locks */
u32 *im_DBGdimap;
atomic_t im_numinos; /* num of backed inodes */
atomic_t im_numfree; /* num of free backed inodes */
diff --git a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h
index dc21a5bd54d4..54d73716ca8c 100644
--- a/fs/jfs/jfs_incore.h
+++ b/fs/jfs/jfs_incore.h
@@ -19,6 +19,7 @@
#ifndef _H_JFS_INCORE
#define _H_JFS_INCORE
+#include <linux/mutex.h>
#include <linux/rwsem.h>
#include <linux/slab.h>
#include <linux/bitops.h>
@@ -37,6 +38,8 @@
struct jfs_inode_info {
int fileset; /* fileset number (always 16)*/
uint mode2; /* jfs-specific mode */
+ uint saved_uid; /* saved for uid mount option */
+ uint saved_gid; /* saved for gid mount option */
pxd_t ixpxd; /* inode extent descriptor */
dxd_t acl; /* dxd describing acl */
dxd_t ea; /* dxd describing ea */
@@ -62,12 +65,12 @@ struct jfs_inode_info {
*/
struct rw_semaphore rdwrlock;
/*
- * commit_sem serializes transaction processing on an inode.
+ * commit_mutex serializes transaction processing on an inode.
* It must be taken after beginning a transaction (txBegin), since
* dirty inodes may be committed while a new transaction on the
* inode is blocked in txBegin or TxBeginAnon
*/
- struct semaphore commit_sem;
+ struct mutex commit_mutex;
/* xattr_sem allows us to access the xattrs without taking i_mutex */
struct rw_semaphore xattr_sem;
lid_t xtlid; /* lid of xtree lock on directory */
@@ -169,6 +172,9 @@ struct jfs_sb_info {
uint state; /* mount/recovery state */
unsigned long flag; /* mount time flags */
uint p_state; /* state prior to going no integrity */
+ uint uid; /* uid to override on-disk uid */
+ uint gid; /* gid to override on-disk gid */
+ uint umask; /* umask to override on-disk umask */
};
/* jfs_sb_info commit_state */
diff --git a/fs/jfs/jfs_inode.c b/fs/jfs/jfs_inode.c
index 2af5efbfd06f..495df402916d 100644
--- a/fs/jfs/jfs_inode.c
+++ b/fs/jfs/jfs_inode.c
@@ -25,6 +25,26 @@
#include "jfs_dinode.h"
#include "jfs_debug.h"
+
+void jfs_set_inode_flags(struct inode *inode)
+{
+ unsigned int flags = JFS_IP(inode)->mode2;
+
+ inode->i_flags &= ~(S_IMMUTABLE | S_APPEND |
+ S_NOATIME | S_DIRSYNC | S_SYNC);
+
+ if (flags & JFS_IMMUTABLE_FL)
+ inode->i_flags |= S_IMMUTABLE;
+ if (flags & JFS_APPEND_FL)
+ inode->i_flags |= S_APPEND;
+ if (flags & JFS_NOATIME_FL)
+ inode->i_flags |= S_NOATIME;
+ if (flags & JFS_DIRSYNC_FL)
+ inode->i_flags |= S_DIRSYNC;
+ if (flags & JFS_SYNC_FL)
+ inode->i_flags |= S_SYNC;
+}
+
/*
* NAME: ialloc()
*
@@ -63,6 +83,13 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
inode->i_gid = current->fsgid;
/*
+ * New inodes need to save sane values on disk when
+ * uid & gid mount options are used
+ */
+ jfs_inode->saved_uid = inode->i_uid;
+ jfs_inode->saved_gid = inode->i_gid;
+
+ /*
* Allocate inode to quota.
*/
if (DQUOT_ALLOC_INODE(inode)) {
@@ -74,10 +101,20 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
}
inode->i_mode = mode;
- if (S_ISDIR(mode))
- jfs_inode->mode2 = IDIRECTORY | mode;
- else
- jfs_inode->mode2 = INLINEEA | ISPARSE | mode;
+ /* inherit flags from parent */
+ jfs_inode->mode2 = JFS_IP(parent)->mode2 & JFS_FL_INHERIT;
+
+ if (S_ISDIR(mode)) {
+ jfs_inode->mode2 |= IDIRECTORY;
+ jfs_inode->mode2 &= ~JFS_DIRSYNC_FL;
+ }
+ else {
+ jfs_inode->mode2 |= INLINEEA | ISPARSE;
+ if (S_ISLNK(mode))
+ jfs_inode->mode2 &= ~(JFS_IMMUTABLE_FL|JFS_APPEND_FL);
+ }
+ jfs_inode->mode2 |= mode;
+
inode->i_blksize = sb->s_blocksize;
inode->i_blocks = 0;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
@@ -98,6 +135,7 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
jfs_inode->atlhead = 0;
jfs_inode->atltail = 0;
jfs_inode->xtlid = 0;
+ jfs_set_inode_flags(inode);
jfs_info("ialloc returns inode = 0x%p\n", inode);
diff --git a/fs/jfs/jfs_inode.h b/fs/jfs/jfs_inode.h
index b54bac576cb3..095d471b9f9a 100644
--- a/fs/jfs/jfs_inode.h
+++ b/fs/jfs/jfs_inode.h
@@ -20,6 +20,8 @@
extern struct inode *ialloc(struct inode *, umode_t);
extern int jfs_fsync(struct file *, struct dentry *, int);
+extern int jfs_ioctl(struct inode *, struct file *,
+ unsigned int, unsigned long);
extern void jfs_read_inode(struct inode *);
extern int jfs_commit_inode(struct inode *, int);
extern int jfs_write_inode(struct inode*, int);
@@ -29,6 +31,7 @@ extern void jfs_truncate(struct inode *);
extern void jfs_truncate_nolock(struct inode *, loff_t);
extern void jfs_free_zero_link(struct inode *);
extern struct dentry *jfs_get_parent(struct dentry *dentry);
+extern void jfs_set_inode_flags(struct inode *);
extern struct address_space_operations jfs_aops;
extern struct inode_operations jfs_dir_inode_operations;
diff --git a/fs/jfs/jfs_lock.h b/fs/jfs/jfs_lock.h
index 10ad1d086685..70ac9f7d1e00 100644
--- a/fs/jfs/jfs_lock.h
+++ b/fs/jfs/jfs_lock.h
@@ -20,6 +20,7 @@
#define _H_JFS_LOCK
#include <linux/spinlock.h>
+#include <linux/mutex.h>
#include <linux/sched.h>
/*
diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
index d27bac6acaa3..0b348b13b551 100644
--- a/fs/jfs/jfs_logmgr.c
+++ b/fs/jfs/jfs_logmgr.c
@@ -64,6 +64,7 @@
#include <linux/interrupt.h>
#include <linux/smp_lock.h>
#include <linux/completion.h>
+#include <linux/kthread.h>
#include <linux/buffer_head.h> /* for sync_blockdev() */
#include <linux/bio.h>
#include <linux/suspend.h>
@@ -81,15 +82,14 @@
*/
static struct lbuf *log_redrive_list;
static DEFINE_SPINLOCK(log_redrive_lock);
-DECLARE_WAIT_QUEUE_HEAD(jfs_IO_thread_wait);
/*
* log read/write serialization (per log)
*/
-#define LOG_LOCK_INIT(log) init_MUTEX(&(log)->loglock)
-#define LOG_LOCK(log) down(&((log)->loglock))
-#define LOG_UNLOCK(log) up(&((log)->loglock))
+#define LOG_LOCK_INIT(log) mutex_init(&(log)->loglock)
+#define LOG_LOCK(log) mutex_lock(&((log)->loglock))
+#define LOG_UNLOCK(log) mutex_unlock(&((log)->loglock))
/*
@@ -1105,11 +1105,10 @@ int lmLogOpen(struct super_block *sb)
}
}
- if (!(log = kmalloc(sizeof(struct jfs_log), GFP_KERNEL))) {
+ if (!(log = kzalloc(sizeof(struct jfs_log), GFP_KERNEL))) {
up(&jfs_log_sem);
return -ENOMEM;
}
- memset(log, 0, sizeof(struct jfs_log));
INIT_LIST_HEAD(&log->sb_list);
init_waitqueue_head(&log->syncwait);
@@ -1181,9 +1180,8 @@ static int open_inline_log(struct super_block *sb)
struct jfs_log *log;
int rc;
- if (!(log = kmalloc(sizeof(struct jfs_log), GFP_KERNEL)))
+ if (!(log = kzalloc(sizeof(struct jfs_log), GFP_KERNEL)))
return -ENOMEM;
- memset(log, 0, sizeof(struct jfs_log));
INIT_LIST_HEAD(&log->sb_list);
init_waitqueue_head(&log->syncwait);
@@ -1216,12 +1214,11 @@ static int open_dummy_log(struct super_block *sb)
down(&jfs_log_sem);
if (!dummy_log) {
- dummy_log = kmalloc(sizeof(struct jfs_log), GFP_KERNEL);
+ dummy_log = kzalloc(sizeof(struct jfs_log), GFP_KERNEL);
if (!dummy_log) {
up(&jfs_log_sem);
return -ENOMEM;
}
- memset(dummy_log, 0, sizeof(struct jfs_log));
INIT_LIST_HEAD(&dummy_log->sb_list);
init_waitqueue_head(&dummy_log->syncwait);
dummy_log->no_integrity = 1;
@@ -1980,7 +1977,7 @@ static inline void lbmRedrive(struct lbuf *bp)
log_redrive_list = bp;
spin_unlock_irqrestore(&log_redrive_lock, flags);
- wake_up(&jfs_IO_thread_wait);
+ wake_up_process(jfsIOthread);
}
@@ -2347,13 +2344,7 @@ int jfsIOWait(void *arg)
{
struct lbuf *bp;
- daemonize("jfsIO");
-
- complete(&jfsIOwait);
-
do {
- DECLARE_WAITQUEUE(wq, current);
-
spin_lock_irq(&log_redrive_lock);
while ((bp = log_redrive_list) != 0) {
log_redrive_list = bp->l_redrive_next;
@@ -2362,21 +2353,19 @@ int jfsIOWait(void *arg)
lbmStartIO(bp);
spin_lock_irq(&log_redrive_lock);
}
+ spin_unlock_irq(&log_redrive_lock);
+
if (freezing(current)) {
- spin_unlock_irq(&log_redrive_lock);
refrigerator();
} else {
- add_wait_queue(&jfs_IO_thread_wait, &wq);
set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irq(&log_redrive_lock);
schedule();
current->state = TASK_RUNNING;
- remove_wait_queue(&jfs_IO_thread_wait, &wq);
}
- } while (!jfs_stop_threads);
+ } while (!kthread_should_stop());
jfs_info("jfsIOWait being killed!");
- complete_and_exit(&jfsIOwait, 0);
+ return 0;
}
/*
diff --git a/fs/jfs/jfs_logmgr.h b/fs/jfs/jfs_logmgr.h
index e4978b5b65ee..8c6909b80014 100644
--- a/fs/jfs/jfs_logmgr.h
+++ b/fs/jfs/jfs_logmgr.h
@@ -389,7 +389,7 @@ struct jfs_log {
int eor; /* 4: eor of last record in eol page */
struct lbuf *bp; /* 4: current log page buffer */
- struct semaphore loglock; /* 4: log write serialization lock */
+ struct mutex loglock; /* 4: log write serialization lock */
/* syncpt */
int nextsync; /* 4: bytes to write before next syncpt */
diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c
index 8a53981f9f27..5fbaeaadccd3 100644
--- a/fs/jfs/jfs_metapage.c
+++ b/fs/jfs/jfs_metapage.c
@@ -104,10 +104,9 @@ static inline int insert_metapage(struct page *page, struct metapage *mp)
if (PagePrivate(page))
a = mp_anchor(page);
else {
- a = kmalloc(sizeof(struct meta_anchor), GFP_NOFS);
+ a = kzalloc(sizeof(struct meta_anchor), GFP_NOFS);
if (!a)
return -ENOMEM;
- memset(a, 0, sizeof(struct meta_anchor));
set_page_private(page, (unsigned long)a);
SetPagePrivate(page);
kmap(page);
diff --git a/fs/jfs/jfs_superblock.h b/fs/jfs/jfs_superblock.h
index fcf781bf31cb..682cf1a68a18 100644
--- a/fs/jfs/jfs_superblock.h
+++ b/fs/jfs/jfs_superblock.h
@@ -113,12 +113,9 @@ extern int jfs_mount(struct super_block *);
extern int jfs_mount_rw(struct super_block *, int);
extern int jfs_umount(struct super_block *);
extern int jfs_umount_rw(struct super_block *);
-
-extern int jfs_stop_threads;
-extern struct completion jfsIOwait;
-extern wait_queue_head_t jfs_IO_thread_wait;
-extern wait_queue_head_t jfs_commit_thread_wait;
-extern wait_queue_head_t jfs_sync_thread_wait;
extern int jfs_extendfs(struct super_block *, s64, int);
+extern struct task_struct *jfsIOthread;
+extern struct task_struct *jfsSyncThread;
+
#endif /*_H_JFS_SUPERBLOCK */
diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
index 2ddb6b892bcf..ac3d66948e8c 100644
--- a/fs/jfs/jfs_txnmgr.c
+++ b/fs/jfs/jfs_txnmgr.c
@@ -49,6 +49,7 @@
#include <linux/suspend.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/kthread.h>
#include "jfs_incore.h"
#include "jfs_inode.h"
#include "jfs_filsys.h"
@@ -121,8 +122,7 @@ static DEFINE_SPINLOCK(jfsTxnLock);
#define LAZY_LOCK(flags) spin_lock_irqsave(&TxAnchor.LazyLock, flags)
#define LAZY_UNLOCK(flags) spin_unlock_irqrestore(&TxAnchor.LazyLock, flags)
-DECLARE_WAIT_QUEUE_HEAD(jfs_sync_thread_wait);
-DECLARE_WAIT_QUEUE_HEAD(jfs_commit_thread_wait);
+static DECLARE_WAIT_QUEUE_HEAD(jfs_commit_thread_wait);
static int jfs_commit_thread_waking;
/*
@@ -207,7 +207,7 @@ static lid_t txLockAlloc(void)
if ((++TxAnchor.tlocksInUse > TxLockHWM) && (jfs_tlocks_low == 0)) {
jfs_info("txLockAlloc tlocks low");
jfs_tlocks_low = 1;
- wake_up(&jfs_sync_thread_wait);
+ wake_up_process(jfsSyncThread);
}
return lid;
@@ -2743,10 +2743,6 @@ int jfs_lazycommit(void *arg)
unsigned long flags;
struct jfs_sb_info *sbi;
- daemonize("jfsCommit");
-
- complete(&jfsIOwait);
-
do {
LAZY_LOCK(flags);
jfs_commit_thread_waking = 0; /* OK to wake another thread */
@@ -2806,13 +2802,13 @@ int jfs_lazycommit(void *arg)
current->state = TASK_RUNNING;
remove_wait_queue(&jfs_commit_thread_wait, &wq);
}
- } while (!jfs_stop_threads);
+ } while (!kthread_should_stop());
if (!list_empty(&TxAnchor.unlock_queue))
jfs_err("jfs_lazycommit being killed w/pending transactions!");
else
jfs_info("jfs_lazycommit being killed\n");
- complete_and_exit(&jfsIOwait, 0);
+ return 0;
}
void txLazyUnlock(struct tblock * tblk)
@@ -2876,10 +2872,10 @@ restart:
*/
TXN_UNLOCK();
tid = txBegin(ip->i_sb, COMMIT_INODE | COMMIT_FORCE);
- down(&jfs_ip->commit_sem);
+ mutex_lock(&jfs_ip->commit_mutex);
txCommit(tid, 1, &ip, 0);
txEnd(tid);
- up(&jfs_ip->commit_sem);
+ mutex_unlock(&jfs_ip->commit_mutex);
/*
* Just to be safe. I don't know how
* long we can run without blocking
@@ -2932,10 +2928,6 @@ int jfs_sync(void *arg)
int rc;
tid_t tid;
- daemonize("jfsSync");
-
- complete(&jfsIOwait);
-
do {
/*
* write each inode on the anonymous inode list
@@ -2952,7 +2944,7 @@ int jfs_sync(void *arg)
* Inode is being freed
*/
list_del_init(&jfs_ip->anon_inode_list);
- } else if (! down_trylock(&jfs_ip->commit_sem)) {
+ } else if (! !mutex_trylock(&jfs_ip->commit_mutex)) {
/*
* inode will be removed from anonymous list
* when it is committed
@@ -2961,7 +2953,7 @@ int jfs_sync(void *arg)
tid = txBegin(ip->i_sb, COMMIT_INODE);
rc = txCommit(tid, 1, &ip, 0);
txEnd(tid);
- up(&jfs_ip->commit_sem);
+ mutex_unlock(&jfs_ip->commit_mutex);
iput(ip);
/*
@@ -2971,7 +2963,7 @@ int jfs_sync(void *arg)
cond_resched();
TXN_LOCK();
} else {
- /* We can't get the commit semaphore. It may
+ /* We can't get the commit mutex. It may
* be held by a thread waiting for tlock's
* so let's not block here. Save it to
* put back on the anon_list.
@@ -2996,19 +2988,15 @@ int jfs_sync(void *arg)
TXN_UNLOCK();
refrigerator();
} else {
- DECLARE_WAITQUEUE(wq, current);
-
- add_wait_queue(&jfs_sync_thread_wait, &wq);
set_current_state(TASK_INTERRUPTIBLE);
TXN_UNLOCK();
schedule();
current->state = TASK_RUNNING;
- remove_wait_queue(&jfs_sync_thread_wait, &wq);
}
- } while (!jfs_stop_threads);
+ } while (!kthread_should_stop());
jfs_info("jfs_sync being killed");
- complete_and_exit(&jfsIOwait, 0);
+ return 0;
}
#if defined(CONFIG_PROC_FS) && defined(CONFIG_JFS_DEBUG)
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index 4abbe8604302..309cee575f7d 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -104,8 +104,8 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
tid = txBegin(dip->i_sb, 0);
- down(&JFS_IP(dip)->commit_sem);
- down(&JFS_IP(ip)->commit_sem);
+ mutex_lock(&JFS_IP(dip)->commit_mutex);
+ mutex_lock(&JFS_IP(ip)->commit_mutex);
rc = jfs_init_acl(tid, ip, dip);
if (rc)
@@ -165,8 +165,8 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
out3:
txEnd(tid);
- up(&JFS_IP(dip)->commit_sem);
- up(&JFS_IP(ip)->commit_sem);
+ mutex_unlock(&JFS_IP(dip)->commit_mutex);
+ mutex_unlock(&JFS_IP(ip)->commit_mutex);
if (rc) {
free_ea_wmap(ip);
ip->i_nlink = 0;
@@ -238,8 +238,8 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
tid = txBegin(dip->i_sb, 0);
- down(&JFS_IP(dip)->commit_sem);
- down(&JFS_IP(ip)->commit_sem);
+ mutex_lock(&JFS_IP(dip)->commit_mutex);
+ mutex_lock(&JFS_IP(ip)->commit_mutex);
rc = jfs_init_acl(tid, ip, dip);
if (rc)
@@ -300,8 +300,8 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
out3:
txEnd(tid);
- up(&JFS_IP(dip)->commit_sem);
- up(&JFS_IP(ip)->commit_sem);
+ mutex_unlock(&JFS_IP(dip)->commit_mutex);
+ mutex_unlock(&JFS_IP(ip)->commit_mutex);
if (rc) {
free_ea_wmap(ip);
ip->i_nlink = 0;
@@ -365,8 +365,8 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
tid = txBegin(dip->i_sb, 0);
- down(&JFS_IP(dip)->commit_sem);
- down(&JFS_IP(ip)->commit_sem);
+ mutex_lock(&JFS_IP(dip)->commit_mutex);
+ mutex_lock(&JFS_IP(ip)->commit_mutex);
iplist[0] = dip;
iplist[1] = ip;
@@ -384,8 +384,8 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
if (rc == -EIO)
txAbort(tid, 1);
txEnd(tid);
- up(&JFS_IP(dip)->commit_sem);
- up(&JFS_IP(ip)->commit_sem);
+ mutex_unlock(&JFS_IP(dip)->commit_mutex);
+ mutex_unlock(&JFS_IP(ip)->commit_mutex);
goto out2;
}
@@ -422,8 +422,8 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
txEnd(tid);
- up(&JFS_IP(dip)->commit_sem);
- up(&JFS_IP(ip)->commit_sem);
+ mutex_unlock(&JFS_IP(dip)->commit_mutex);
+ mutex_unlock(&JFS_IP(ip)->commit_mutex);
/*
* Truncating the directory index table is not guaranteed. It
@@ -488,8 +488,8 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
tid = txBegin(dip->i_sb, 0);
- down(&JFS_IP(dip)->commit_sem);
- down(&JFS_IP(ip)->commit_sem);
+ mutex_lock(&JFS_IP(dip)->commit_mutex);
+ mutex_lock(&JFS_IP(ip)->commit_mutex);
iplist[0] = dip;
iplist[1] = ip;
@@ -503,8 +503,8 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
if (rc == -EIO)
txAbort(tid, 1); /* Marks FS Dirty */
txEnd(tid);
- up(&JFS_IP(dip)->commit_sem);
- up(&JFS_IP(ip)->commit_sem);
+ mutex_unlock(&JFS_IP(dip)->commit_mutex);
+ mutex_unlock(&JFS_IP(ip)->commit_mutex);
IWRITE_UNLOCK(ip);
goto out1;
}
@@ -527,8 +527,8 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
if ((new_size = commitZeroLink(tid, ip)) < 0) {
txAbort(tid, 1); /* Marks FS Dirty */
txEnd(tid);
- up(&JFS_IP(dip)->commit_sem);
- up(&JFS_IP(ip)->commit_sem);
+ mutex_unlock(&JFS_IP(dip)->commit_mutex);
+ mutex_unlock(&JFS_IP(ip)->commit_mutex);
IWRITE_UNLOCK(ip);
rc = new_size;
goto out1;
@@ -556,13 +556,13 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
txEnd(tid);
- up(&JFS_IP(dip)->commit_sem);
- up(&JFS_IP(ip)->commit_sem);
+ mutex_unlock(&JFS_IP(dip)->commit_mutex);
+ mutex_unlock(&JFS_IP(ip)->commit_mutex);
while (new_size && (rc == 0)) {
tid = txBegin(dip->i_sb, 0);
- down(&JFS_IP(ip)->commit_sem);
+ mutex_lock(&JFS_IP(ip)->commit_mutex);
new_size = xtTruncate_pmap(tid, ip, new_size);
if (new_size < 0) {
txAbort(tid, 1); /* Marks FS Dirty */
@@ -570,7 +570,7 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
} else
rc = txCommit(tid, 2, &iplist[0], COMMIT_SYNC);
txEnd(tid);
- up(&JFS_IP(ip)->commit_sem);
+ mutex_unlock(&JFS_IP(ip)->commit_mutex);
}
if (ip->i_nlink == 0)
@@ -805,8 +805,8 @@ static int jfs_link(struct dentry *old_dentry,
tid = txBegin(ip->i_sb, 0);
- down(&JFS_IP(dir)->commit_sem);
- down(&JFS_IP(ip)->commit_sem);
+ mutex_lock(&JFS_IP(dir)->commit_mutex);
+ mutex_lock(&JFS_IP(ip)->commit_mutex);
/*
* scan parent directory for entry/freespace
@@ -847,8 +847,8 @@ static int jfs_link(struct dentry *old_dentry,
out:
txEnd(tid);
- up(&JFS_IP(dir)->commit_sem);
- up(&JFS_IP(ip)->commit_sem);
+ mutex_unlock(&JFS_IP(dir)->commit_mutex);
+ mutex_unlock(&JFS_IP(ip)->commit_mutex);
jfs_info("jfs_link: rc:%d", rc);
return rc;
@@ -916,8 +916,8 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
tid = txBegin(dip->i_sb, 0);
- down(&JFS_IP(dip)->commit_sem);
- down(&JFS_IP(ip)->commit_sem);
+ mutex_lock(&JFS_IP(dip)->commit_mutex);
+ mutex_lock(&JFS_IP(ip)->commit_mutex);
rc = jfs_init_security(tid, ip, dip);
if (rc)
@@ -1037,8 +1037,8 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
out3:
txEnd(tid);
- up(&JFS_IP(dip)->commit_sem);
- up(&JFS_IP(ip)->commit_sem);
+ mutex_unlock(&JFS_IP(dip)->commit_mutex);
+ mutex_unlock(&JFS_IP(ip)->commit_mutex);
if (rc) {
free_ea_wmap(ip);
ip->i_nlink = 0;
@@ -1141,13 +1141,13 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
*/
tid = txBegin(new_dir->i_sb, 0);
- down(&JFS_IP(new_dir)->commit_sem);
- down(&JFS_IP(old_ip)->commit_sem);
+ mutex_lock(&JFS_IP(new_dir)->commit_mutex);
+ mutex_lock(&JFS_IP(old_ip)->commit_mutex);
if (old_dir != new_dir)
- down(&JFS_IP(old_dir)->commit_sem);
+ mutex_lock(&JFS_IP(old_dir)->commit_mutex);
if (new_ip) {
- down(&JFS_IP(new_ip)->commit_sem);
+ mutex_lock(&JFS_IP(new_ip)->commit_mutex);
/*
* Change existing directory entry to new inode number
*/
@@ -1160,10 +1160,10 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (S_ISDIR(new_ip->i_mode)) {
new_ip->i_nlink--;
if (new_ip->i_nlink) {
- up(&JFS_IP(new_dir)->commit_sem);
- up(&JFS_IP(old_ip)->commit_sem);
+ mutex_unlock(&JFS_IP(new_dir)->commit_mutex);
+ mutex_unlock(&JFS_IP(old_ip)->commit_mutex);
if (old_dir != new_dir)
- up(&JFS_IP(old_dir)->commit_sem);
+ mutex_unlock(&JFS_IP(old_dir)->commit_mutex);
if (!S_ISDIR(old_ip->i_mode) && new_ip)
IWRITE_UNLOCK(new_ip);
jfs_error(new_ip->i_sb,
@@ -1282,16 +1282,16 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
out4:
txEnd(tid);
- up(&JFS_IP(new_dir)->commit_sem);
- up(&JFS_IP(old_ip)->commit_sem);
+ mutex_unlock(&JFS_IP(new_dir)->commit_mutex);
+ mutex_unlock(&JFS_IP(old_ip)->commit_mutex);
if (old_dir != new_dir)
- up(&JFS_IP(old_dir)->commit_sem);
+ mutex_unlock(&JFS_IP(old_dir)->commit_mutex);
if (new_ip)
- up(&JFS_IP(new_ip)->commit_sem);
+ mutex_unlock(&JFS_IP(new_ip)->commit_mutex);
while (new_size && (rc == 0)) {
tid = txBegin(new_ip->i_sb, 0);
- down(&JFS_IP(new_ip)->commit_sem);
+ mutex_lock(&JFS_IP(new_ip)->commit_mutex);
new_size = xtTruncate_pmap(tid, new_ip, new_size);
if (new_size < 0) {
txAbort(tid, 1);
@@ -1299,7 +1299,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
} else
rc = txCommit(tid, 1, &new_ip, COMMIT_SYNC);
txEnd(tid);
- up(&JFS_IP(new_ip)->commit_sem);
+ mutex_unlock(&JFS_IP(new_ip)->commit_mutex);
}
if (new_ip && (new_ip->i_nlink == 0))
set_cflag(COMMIT_Nolink, new_ip);
@@ -1361,8 +1361,8 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
tid = txBegin(dir->i_sb, 0);
- down(&JFS_IP(dir)->commit_sem);
- down(&JFS_IP(ip)->commit_sem);
+ mutex_lock(&JFS_IP(dir)->commit_mutex);
+ mutex_lock(&JFS_IP(ip)->commit_mutex);
rc = jfs_init_acl(tid, ip, dir);
if (rc)
@@ -1407,8 +1407,8 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
out3:
txEnd(tid);
- up(&JFS_IP(ip)->commit_sem);
- up(&JFS_IP(dir)->commit_sem);
+ mutex_unlock(&JFS_IP(ip)->commit_mutex);
+ mutex_unlock(&JFS_IP(dir)->commit_mutex);
if (rc) {
free_ea_wmap(ip);
ip->i_nlink = 0;
@@ -1523,6 +1523,7 @@ struct file_operations jfs_dir_operations = {
.read = generic_read_dir,
.readdir = jfs_readdir,
.fsync = jfs_fsync,
+ .ioctl = jfs_ioctl,
};
static int jfs_ci_hash(struct dentry *dir, struct qstr *this)
diff --git a/fs/jfs/super.c b/fs/jfs/super.c
index 8d31f1336431..18f69e6aa719 100644
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -25,6 +25,7 @@
#include <linux/vfs.h>
#include <linux/mount.h>
#include <linux/moduleparam.h>
+#include <linux/kthread.h>
#include <linux/posix_acl.h>
#include <asm/uaccess.h>
#include <linux/seq_file.h>
@@ -54,11 +55,9 @@ static int commit_threads = 0;
module_param(commit_threads, int, 0);
MODULE_PARM_DESC(commit_threads, "Number of commit threads");
-int jfs_stop_threads;
-static pid_t jfsIOthread;
-static pid_t jfsCommitThread[MAX_COMMIT_THREADS];
-static pid_t jfsSyncThread;
-DECLARE_COMPLETION(jfsIOwait);
+static struct task_struct *jfsCommitThread[MAX_COMMIT_THREADS];
+struct task_struct *jfsIOthread;
+struct task_struct *jfsSyncThread;
#ifdef CONFIG_JFS_DEBUG
int jfsloglevel = JFS_LOGLEVEL_WARN;
@@ -195,7 +194,7 @@ static void jfs_put_super(struct super_block *sb)
enum {
Opt_integrity, Opt_nointegrity, Opt_iocharset, Opt_resize,
Opt_resize_nosize, Opt_errors, Opt_ignore, Opt_err, Opt_quota,
- Opt_usrquota, Opt_grpquota
+ Opt_usrquota, Opt_grpquota, Opt_uid, Opt_gid, Opt_umask
};
static match_table_t tokens = {
@@ -209,6 +208,9 @@ static match_table_t tokens = {
{Opt_ignore, "quota"},
{Opt_usrquota, "usrquota"},
{Opt_grpquota, "grpquota"},
+ {Opt_uid, "uid=%u"},
+ {Opt_gid, "gid=%u"},
+ {Opt_umask, "umask=%u"},
{Opt_err, NULL}
};
@@ -313,7 +315,29 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize,
"JFS: quota operations not supported\n");
break;
#endif
-
+ case Opt_uid:
+ {
+ char *uid = args[0].from;
+ sbi->uid = simple_strtoul(uid, &uid, 0);
+ break;
+ }
+ case Opt_gid:
+ {
+ char *gid = args[0].from;
+ sbi->gid = simple_strtoul(gid, &gid, 0);
+ break;
+ }
+ case Opt_umask:
+ {
+ char *umask = args[0].from;
+ sbi->umask = simple_strtoul(umask, &umask, 8);
+ if (sbi->umask & ~0777) {
+ printk(KERN_ERR
+ "JFS: Invalid value of umask\n");
+ goto cleanup;
+ }
+ break;
+ }
default:
printk("jfs: Unrecognized mount option \"%s\" "
" or missing value\n", p);
@@ -396,12 +420,12 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
if (!new_valid_dev(sb->s_bdev->bd_dev))
return -EOVERFLOW;
- sbi = kmalloc(sizeof (struct jfs_sb_info), GFP_KERNEL);
+ sbi = kzalloc(sizeof (struct jfs_sb_info), GFP_KERNEL);
if (!sbi)
return -ENOSPC;
- memset(sbi, 0, sizeof (struct jfs_sb_info));
sb->s_fs_info = sbi;
sbi->sb = sb;
+ sbi->uid = sbi->gid = sbi->umask = -1;
/* initialize the mount flag and determine the default error handler */
flag = JFS_ERR_REMOUNT_RO;
@@ -564,10 +588,14 @@ static int jfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
{
struct jfs_sb_info *sbi = JFS_SBI(vfs->mnt_sb);
+ if (sbi->uid != -1)
+ seq_printf(seq, ",uid=%d", sbi->uid);
+ if (sbi->gid != -1)
+ seq_printf(seq, ",gid=%d", sbi->gid);
+ if (sbi->umask != -1)
+ seq_printf(seq, ",umask=%03o", sbi->umask);
if (sbi->flag & JFS_NOINTEGRITY)
seq_puts(seq, ",nointegrity");
- else
- seq_puts(seq, ",integrity");
#if defined(CONFIG_QUOTA)
if (sbi->flag & JFS_USRQUOTA)
@@ -617,7 +645,7 @@ static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags)
memset(jfs_ip, 0, sizeof(struct jfs_inode_info));
INIT_LIST_HEAD(&jfs_ip->anon_inode_list);
init_rwsem(&jfs_ip->rdwrlock);
- init_MUTEX(&jfs_ip->commit_sem);
+ mutex_init(&jfs_ip->commit_mutex);
init_rwsem(&jfs_ip->xattr_sem);
spin_lock_init(&jfs_ip->ag_lock);
jfs_ip->active_ag = -1;
@@ -661,12 +689,12 @@ static int __init init_jfs_fs(void)
/*
* I/O completion thread (endio)
*/
- jfsIOthread = kernel_thread(jfsIOWait, NULL, CLONE_KERNEL);
- if (jfsIOthread < 0) {
- jfs_err("init_jfs_fs: fork failed w/rc = %d", jfsIOthread);
+ jfsIOthread = kthread_run(jfsIOWait, NULL, "jfsIO");
+ if (IS_ERR(jfsIOthread)) {
+ rc = PTR_ERR(jfsIOthread);
+ jfs_err("init_jfs_fs: fork failed w/rc = %d", rc);
goto end_txmngr;
}
- wait_for_completion(&jfsIOwait); /* Wait until thread starts */
if (commit_threads < 1)
commit_threads = num_online_cpus();
@@ -674,24 +702,21 @@ static int __init init_jfs_fs(void)
commit_threads = MAX_COMMIT_THREADS;
for (i = 0; i < commit_threads; i++) {
- jfsCommitThread[i] = kernel_thread(jfs_lazycommit, NULL,
- CLONE_KERNEL);
- if (jfsCommitThread[i] < 0) {
- jfs_err("init_jfs_fs: fork failed w/rc = %d",
- jfsCommitThread[i]);
+ jfsCommitThread[i] = kthread_run(jfs_lazycommit, NULL, "jfsCommit");
+ if (IS_ERR(jfsCommitThread[i])) {
+ rc = PTR_ERR(jfsCommitThread[i]);
+ jfs_err("init_jfs_fs: fork failed w/rc = %d", rc);
commit_threads = i;
goto kill_committask;
}
- /* Wait until thread starts */
- wait_for_completion(&jfsIOwait);
}
- jfsSyncThread = kernel_thread(jfs_sync, NULL, CLONE_KERNEL);
- if (jfsSyncThread < 0) {
- jfs_err("init_jfs_fs: fork failed w/rc = %d", jfsSyncThread);
+ jfsSyncThread = kthread_run(jfs_sync, NULL, "jfsSync");
+ if (IS_ERR(jfsSyncThread)) {
+ rc = PTR_ERR(jfsSyncThread);
+ jfs_err("init_jfs_fs: fork failed w/rc = %d", rc);
goto kill_committask;
}
- wait_for_completion(&jfsIOwait); /* Wait until thread starts */
#ifdef PROC_FS_JFS
jfs_proc_init();
@@ -700,13 +725,9 @@ static int __init init_jfs_fs(void)
return register_filesystem(&jfs_fs_type);
kill_committask:
- jfs_stop_threads = 1;
- wake_up_all(&jfs_commit_thread_wait);
for (i = 0; i < commit_threads; i++)
- wait_for_completion(&jfsIOwait);
-
- wake_up(&jfs_IO_thread_wait);
- wait_for_completion(&jfsIOwait); /* Wait for thread exit */
+ kthread_stop(jfsCommitThread[i]);
+ kthread_stop(jfsIOthread);
end_txmngr:
txExit();
free_metapage:
@@ -722,16 +743,13 @@ static void __exit exit_jfs_fs(void)
jfs_info("exit_jfs_fs called");
- jfs_stop_threads = 1;
txExit();
metapage_exit();
- wake_up(&jfs_IO_thread_wait);
- wait_for_completion(&jfsIOwait); /* Wait until IO thread exits */
- wake_up_all(&jfs_commit_thread_wait);
+
+ kthread_stop(jfsIOthread);
for (i = 0; i < commit_threads; i++)
- wait_for_completion(&jfsIOwait);
- wake_up(&jfs_sync_thread_wait);
- wait_for_completion(&jfsIOwait); /* Wait until Sync thread exits */
+ kthread_stop(jfsCommitThread[i]);
+ kthread_stop(jfsSyncThread);
#ifdef PROC_FS_JFS
jfs_proc_clean();
#endif
diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c
index f23048f9471f..9bc5b7c055ce 100644
--- a/fs/jfs/xattr.c
+++ b/fs/jfs/xattr.c
@@ -934,13 +934,13 @@ int jfs_setxattr(struct dentry *dentry, const char *name, const void *value,
}
tid = txBegin(inode->i_sb, 0);
- down(&ji->commit_sem);
+ mutex_lock(&ji->commit_mutex);
rc = __jfs_setxattr(tid, dentry->d_inode, name, value, value_len,
flags);
if (!rc)
rc = txCommit(tid, 1, &inode, 0);
txEnd(tid);
- up(&ji->commit_sem);
+ mutex_unlock(&ji->commit_mutex);
return rc;
}
@@ -1093,12 +1093,12 @@ int jfs_removexattr(struct dentry *dentry, const char *name)
return rc;
tid = txBegin(inode->i_sb, 0);
- down(&ji->commit_sem);
+ mutex_lock(&ji->commit_mutex);
rc = __jfs_setxattr(tid, dentry->d_inode, name, NULL, 0, XATTR_REPLACE);
if (!rc)
rc = txCommit(tid, 1, &inode, 0);
txEnd(tid);
- up(&ji->commit_sem);
+ mutex_unlock(&ji->commit_mutex);
return rc;
}
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index 220058d8616d..970b6a6aa337 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -662,12 +662,18 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
* reclaimed while we're stuck in the unlock call. */
fl->fl_u.nfs_fl.flags &= ~NFS_LCK_GRANTED;
+ /*
+ * Note: the server is supposed to either grant us the unlock
+ * request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either
+ * case, we want to unlock.
+ */
+ do_vfs_lock(fl);
+
if (req->a_flags & RPC_TASK_ASYNC) {
status = nlmclnt_async_call(req, NLMPROC_UNLOCK,
&nlmclnt_unlock_ops);
/* Hrmf... Do the unlock early since locks_remove_posix()
* really expects us to free the lock synchronously */
- do_vfs_lock(fl);
if (status < 0) {
nlmclnt_release_lockargs(req);
kfree(req);
@@ -680,7 +686,6 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
if (status < 0)
return status;
- do_vfs_lock(fl);
if (resp->status == NLM_LCK_GRANTED)
return 0;
diff --git a/fs/namei.c b/fs/namei.c
index e28de846c591..8dc2b038d5d9 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2224,13 +2224,17 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
* and other special files. --ADM
*/
asmlinkage long sys_linkat(int olddfd, const char __user *oldname,
- int newdfd, const char __user *newname)
+ int newdfd, const char __user *newname,
+ int flags)
{
struct dentry *new_dentry;
struct nameidata nd, old_nd;
int error;
char * to;
+ if (flags != 0)
+ return -EINVAL;
+
to = getname(newname);
if (IS_ERR(to))
return PTR_ERR(to);
@@ -2263,7 +2267,7 @@ exit:
asmlinkage long sys_link(const char __user *oldname, const char __user *newname)
{
- return sys_linkat(AT_FDCWD, oldname, AT_FDCWD, newname);
+ return sys_linkat(AT_FDCWD, oldname, AT_FDCWD, newname, 0);
}
/*
@@ -2609,13 +2613,15 @@ void page_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
}
}
-int page_symlink(struct inode *inode, const char *symname, int len)
+int __page_symlink(struct inode *inode, const char *symname, int len,
+ gfp_t gfp_mask)
{
struct address_space *mapping = inode->i_mapping;
- struct page *page = grab_cache_page(mapping, 0);
+ struct page *page;
int err = -ENOMEM;
char *kaddr;
+ page = find_or_create_page(mapping, 0, gfp_mask);
if (!page)
goto fail;
err = mapping->a_ops->prepare_write(NULL, page, 0, len-1);
@@ -2650,6 +2656,12 @@ fail:
return err;
}
+int page_symlink(struct inode *inode, const char *symname, int len)
+{
+ return __page_symlink(inode, symname, len,
+ mapping_gfp_mask(inode->i_mapping));
+}
+
struct inode_operations page_symlink_inode_operations = {
.readlink = generic_readlink,
.follow_link = page_follow_link_light,
@@ -2668,6 +2680,7 @@ EXPORT_SYMBOL(lookup_one_len);
EXPORT_SYMBOL(page_follow_link_light);
EXPORT_SYMBOL(page_put_link);
EXPORT_SYMBOL(page_readlink);
+EXPORT_SYMBOL(__page_symlink);
EXPORT_SYMBOL(page_symlink);
EXPORT_SYMBOL(page_symlink_inode_operations);
EXPORT_SYMBOL(path_lookup);
diff --git a/fs/namespace.c b/fs/namespace.c
index 058a44865beb..39c81a8d6316 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1338,7 +1338,7 @@ struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs)
new_ns = kmalloc(sizeof(struct namespace), GFP_KERNEL);
if (!new_ns)
- goto out;
+ return NULL;
atomic_set(&new_ns->count, 1);
INIT_LIST_HEAD(&new_ns->list);
@@ -1352,7 +1352,7 @@ struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs)
if (!new_ns->root) {
up_write(&namespace_sem);
kfree(new_ns);
- goto out;
+ return NULL;
}
spin_lock(&vfsmount_lock);
list_add_tail(&new_ns->list, &new_ns->root->mnt_list);
@@ -1393,7 +1393,6 @@ struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs)
if (altrootmnt)
mntput(altrootmnt);
-out:
return new_ns;
}
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 04ab2fc360e7..4e9b3a1b36c5 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -57,6 +57,7 @@
#define NFSDBG_FACILITY NFSDBG_VFS
#define MAX_DIRECTIO_SIZE (4096UL << PAGE_SHIFT)
+static void nfs_free_user_pages(struct page **pages, int npages, int do_dirty);
static kmem_cache_t *nfs_direct_cachep;
/*
@@ -107,6 +108,15 @@ nfs_get_user_pages(int rw, unsigned long user_addr, size_t size,
page_count, (rw == READ), 0,
*pages, NULL);
up_read(&current->mm->mmap_sem);
+ /*
+ * If we got fewer pages than expected from get_user_pages(),
+ * the user buffer runs off the end of a mapping; return EFAULT.
+ */
+ if (result >= 0 && result < page_count) {
+ nfs_free_user_pages(*pages, result, 0);
+ *pages = NULL;
+ result = -EFAULT;
+ }
}
return result;
}
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 984ca3454d04..f8c0066e02e1 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -1430,7 +1430,7 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
if (status == 0)
status = nfs4_do_fsinfo(server, fhandle, info);
out:
- return status;
+ return nfs4_map_errors(status);
}
static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
diff --git a/fs/nfsctl.c b/fs/nfsctl.c
index 0d4cf9486068..1c72c7f85ddc 100644
--- a/fs/nfsctl.c
+++ b/fs/nfsctl.c
@@ -98,10 +98,8 @@ asmlinkage sys_nfsservctl(int cmd, struct nfsctl_arg __user *arg, void __user *r
if (copy_from_user(&version, &arg->ca_version, sizeof(int)))
return -EFAULT;
- if (version != NFSCTL_VERSION) {
- printk(KERN_WARNING "nfsd: incompatible version in syscall.\n");
+ if (version != NFSCTL_VERSION)
return -EINVAL;
- }
if (cmd < 0 || cmd >= sizeof(map)/sizeof(map[0]) || !map[cmd].name)
return -EINVAL;
diff --git a/fs/nls/Kconfig b/fs/nls/Kconfig
index 0ab8f00bdbb2..976ecccd6f56 100644
--- a/fs/nls/Kconfig
+++ b/fs/nls/Kconfig
@@ -491,7 +491,7 @@ config NLS_KOI8_U
(koi8-u) and Belarusian (koi8-ru) character sets.
config NLS_UTF8
- tristate "NLS UTF8"
+ tristate "NLS UTF-8"
depends on NLS
help
If you want to display filenames with native language characters
diff --git a/fs/ocfs2/cluster/masklog.c b/fs/ocfs2/cluster/masklog.c
index fd741cea5705..636593bf4d17 100644
--- a/fs/ocfs2/cluster/masklog.c
+++ b/fs/ocfs2/cluster/masklog.c
@@ -74,6 +74,7 @@ struct mlog_attribute {
#define define_mask(_name) { \
.attr = { \
.name = #_name, \
+ .owner = THIS_MODULE, \
.mode = S_IRUGO | S_IWUSR, \
}, \
.mask = ML_##_name, \
diff --git a/fs/ocfs2/cluster/masklog.h b/fs/ocfs2/cluster/masklog.h
index e8c56a3d9c64..2cadc3009c83 100644
--- a/fs/ocfs2/cluster/masklog.h
+++ b/fs/ocfs2/cluster/masklog.h
@@ -256,7 +256,7 @@ extern struct mlog_bits mlog_and_bits, mlog_not_bits;
} \
} while (0)
-#if (BITS_PER_LONG == 32) || defined(CONFIG_X86_64)
+#if (BITS_PER_LONG == 32) || defined(CONFIG_X86_64) || (defined(CONFIG_UML_X86) && defined(CONFIG_64BIT))
#define MLFi64 "lld"
#define MLFu64 "llu"
#define MLFx64 "llx"
diff --git a/fs/ocfs2/cluster/nodemanager.c b/fs/ocfs2/cluster/nodemanager.c
index cf7828f23361..e1fceb8aa32d 100644
--- a/fs/ocfs2/cluster/nodemanager.c
+++ b/fs/ocfs2/cluster/nodemanager.c
@@ -756,7 +756,7 @@ static int __init init_o2nm(void)
if (!ocfs2_table_header) {
printk(KERN_ERR "nodemanager: unable to register sysctl\n");
ret = -ENOMEM; /* or something. */
- goto out;
+ goto out_o2net;
}
ret = o2net_register_hb_callbacks();
@@ -780,6 +780,8 @@ out_callbacks:
o2net_unregister_hb_callbacks();
out_sysctl:
unregister_sysctl_table(ocfs2_table_header);
+out_o2net:
+ o2net_exit();
out:
return ret;
}
diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c
index d22d4cf08db1..0f60cc0d3985 100644
--- a/fs/ocfs2/cluster/tcp.c
+++ b/fs/ocfs2/cluster/tcp.c
@@ -1318,7 +1318,7 @@ static void o2net_start_connect(void *arg)
{
struct o2net_node *nn = arg;
struct o2net_sock_container *sc = NULL;
- struct o2nm_node *node = NULL;
+ struct o2nm_node *node = NULL, *mynode = NULL;
struct socket *sock = NULL;
struct sockaddr_in myaddr = {0, }, remoteaddr = {0, };
int ret = 0;
@@ -1334,6 +1334,12 @@ static void o2net_start_connect(void *arg)
goto out;
}
+ mynode = o2nm_get_node_by_num(o2nm_this_node());
+ if (mynode == NULL) {
+ ret = 0;
+ goto out;
+ }
+
spin_lock(&nn->nn_lock);
/* see if we already have one pending or have given up */
if (nn->nn_sc || nn->nn_persistent_error)
@@ -1361,12 +1367,14 @@ static void o2net_start_connect(void *arg)
sock->sk->sk_allocation = GFP_ATOMIC;
myaddr.sin_family = AF_INET;
+ myaddr.sin_addr.s_addr = (__force u32)mynode->nd_ipv4_address;
myaddr.sin_port = (__force u16)htons(0); /* any port */
ret = sock->ops->bind(sock, (struct sockaddr *)&myaddr,
sizeof(myaddr));
if (ret) {
- mlog(0, "bind failed: %d\n", ret);
+ mlog(ML_ERROR, "bind failed with %d at address %u.%u.%u.%u\n",
+ ret, NIPQUAD(mynode->nd_ipv4_address));
goto out;
}
@@ -1407,6 +1415,8 @@ out:
sc_put(sc);
if (node)
o2nm_node_put(node);
+ if (mynode)
+ o2nm_node_put(mynode);
return;
}
diff --git a/fs/ocfs2/cluster/tcp.h b/fs/ocfs2/cluster/tcp.h
index a6f4585501c8..616ff2b8434a 100644
--- a/fs/ocfs2/cluster/tcp.h
+++ b/fs/ocfs2/cluster/tcp.h
@@ -85,13 +85,10 @@ enum {
O2NET_DRIVER_READY,
};
-int o2net_init_tcp_sock(struct inode *inode);
int o2net_send_message(u32 msg_type, u32 key, void *data, u32 len,
u8 target_node, int *status);
int o2net_send_message_vec(u32 msg_type, u32 key, struct kvec *vec,
size_t veclen, u8 target_node, int *status);
-int o2net_broadcast_message(u32 msg_type, u32 key, void *data, u32 len,
- struct inode *group);
int o2net_register_handler(u32 msg_type, u32 key, u32 max_len,
o2net_msg_handler_func *func, void *data,
@@ -107,7 +104,5 @@ void o2net_disconnect_node(struct o2nm_node *node);
int o2net_init(void);
void o2net_exit(void);
-int o2net_proc_init(struct proc_dir_entry *parent);
-void o2net_proc_exit(struct proc_dir_entry *parent);
#endif /* O2CLUSTER_TCP_H */
diff --git a/fs/ocfs2/dlm/dlmcommon.h b/fs/ocfs2/dlm/dlmcommon.h
index 23ceaa7127b4..9c772583744a 100644
--- a/fs/ocfs2/dlm/dlmcommon.h
+++ b/fs/ocfs2/dlm/dlmcommon.h
@@ -37,9 +37,7 @@
#define DLM_THREAD_SHUFFLE_INTERVAL 5 // flush everything every 5 passes
#define DLM_THREAD_MS 200 // flush at least every 200 ms
-#define DLM_HASH_BITS 7
-#define DLM_HASH_SIZE (1 << DLM_HASH_BITS)
-#define DLM_HASH_MASK (DLM_HASH_SIZE - 1)
+#define DLM_HASH_BUCKETS (PAGE_SIZE / sizeof(struct hlist_head))
enum dlm_ast_type {
DLM_AST = 0,
@@ -87,7 +85,7 @@ enum dlm_ctxt_state {
struct dlm_ctxt
{
struct list_head list;
- struct list_head *resources;
+ struct hlist_head *lockres_hash;
struct list_head dirty_list;
struct list_head purge_list;
struct list_head pending_asts;
@@ -217,7 +215,7 @@ struct dlm_lock_resource
{
/* WARNING: Please see the comment in dlm_init_lockres before
* adding fields here. */
- struct list_head list;
+ struct hlist_node hash_node;
struct kref refs;
/* please keep these next 3 in this order
diff --git a/fs/ocfs2/dlm/dlmdebug.c b/fs/ocfs2/dlm/dlmdebug.c
index f339fe27975a..54f61b76ab51 100644
--- a/fs/ocfs2/dlm/dlmdebug.c
+++ b/fs/ocfs2/dlm/dlmdebug.c
@@ -117,8 +117,8 @@ EXPORT_SYMBOL_GPL(dlm_print_one_lock);
void dlm_dump_lock_resources(struct dlm_ctxt *dlm)
{
struct dlm_lock_resource *res;
- struct list_head *iter;
- struct list_head *bucket;
+ struct hlist_node *iter;
+ struct hlist_head *bucket;
int i;
mlog(ML_NOTICE, "struct dlm_ctxt: %s, node=%u, key=%u\n",
@@ -129,12 +129,10 @@ void dlm_dump_lock_resources(struct dlm_ctxt *dlm)
}
spin_lock(&dlm->spinlock);
- for (i=0; i<DLM_HASH_SIZE; i++) {
- bucket = &(dlm->resources[i]);
- list_for_each(iter, bucket) {
- res = list_entry(iter, struct dlm_lock_resource, list);
+ for (i=0; i<DLM_HASH_BUCKETS; i++) {
+ bucket = &(dlm->lockres_hash[i]);
+ hlist_for_each_entry(res, iter, bucket, hash_node)
dlm_print_one_lock_resource(res);
- }
}
spin_unlock(&dlm->spinlock);
}
diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c
index 6ee30837389c..8f3a9e3106fd 100644
--- a/fs/ocfs2/dlm/dlmdomain.c
+++ b/fs/ocfs2/dlm/dlmdomain.c
@@ -77,26 +77,26 @@ static void dlm_unregister_domain_handlers(struct dlm_ctxt *dlm);
void __dlm_unhash_lockres(struct dlm_lock_resource *lockres)
{
- list_del_init(&lockres->list);
+ hlist_del_init(&lockres->hash_node);
dlm_lockres_put(lockres);
}
void __dlm_insert_lockres(struct dlm_ctxt *dlm,
struct dlm_lock_resource *res)
{
- struct list_head *bucket;
+ struct hlist_head *bucket;
struct qstr *q;
assert_spin_locked(&dlm->spinlock);
q = &res->lockname;
q->hash = full_name_hash(q->name, q->len);
- bucket = &(dlm->resources[q->hash & DLM_HASH_MASK]);
+ bucket = &(dlm->lockres_hash[q->hash % DLM_HASH_BUCKETS]);
/* get a reference for our hashtable */
dlm_lockres_get(res);
- list_add_tail(&res->list, bucket);
+ hlist_add_head(&res->hash_node, bucket);
}
struct dlm_lock_resource * __dlm_lookup_lockres(struct dlm_ctxt *dlm,
@@ -104,9 +104,9 @@ struct dlm_lock_resource * __dlm_lookup_lockres(struct dlm_ctxt *dlm,
unsigned int len)
{
unsigned int hash;
- struct list_head *iter;
+ struct hlist_node *iter;
struct dlm_lock_resource *tmpres=NULL;
- struct list_head *bucket;
+ struct hlist_head *bucket;
mlog_entry("%.*s\n", len, name);
@@ -114,11 +114,11 @@ struct dlm_lock_resource * __dlm_lookup_lockres(struct dlm_ctxt *dlm,
hash = full_name_hash(name, len);
- bucket = &(dlm->resources[hash & DLM_HASH_MASK]);
+ bucket = &(dlm->lockres_hash[hash % DLM_HASH_BUCKETS]);
/* check for pre-existing lock */
- list_for_each(iter, bucket) {
- tmpres = list_entry(iter, struct dlm_lock_resource, list);
+ hlist_for_each(iter, bucket) {
+ tmpres = hlist_entry(iter, struct dlm_lock_resource, hash_node);
if (tmpres->lockname.len == len &&
memcmp(tmpres->lockname.name, name, len) == 0) {
dlm_lockres_get(tmpres);
@@ -193,8 +193,8 @@ static int dlm_wait_on_domain_helper(const char *domain)
static void dlm_free_ctxt_mem(struct dlm_ctxt *dlm)
{
- if (dlm->resources)
- free_page((unsigned long) dlm->resources);
+ if (dlm->lockres_hash)
+ free_page((unsigned long) dlm->lockres_hash);
if (dlm->name)
kfree(dlm->name);
@@ -303,10 +303,10 @@ static void dlm_migrate_all_locks(struct dlm_ctxt *dlm)
mlog(0, "Migrating locks from domain %s\n", dlm->name);
restart:
spin_lock(&dlm->spinlock);
- for (i=0; i<DLM_HASH_SIZE; i++) {
- while (!list_empty(&dlm->resources[i])) {
- res = list_entry(dlm->resources[i].next,
- struct dlm_lock_resource, list);
+ for (i = 0; i < DLM_HASH_BUCKETS; i++) {
+ while (!hlist_empty(&dlm->lockres_hash[i])) {
+ res = hlist_entry(dlm->lockres_hash[i].first,
+ struct dlm_lock_resource, hash_node);
/* need reference when manually grabbing lockres */
dlm_lockres_get(res);
/* this should unhash the lockres
@@ -1191,18 +1191,17 @@ static struct dlm_ctxt *dlm_alloc_ctxt(const char *domain,
goto leave;
}
- dlm->resources = (struct list_head *) __get_free_page(GFP_KERNEL);
- if (!dlm->resources) {
+ dlm->lockres_hash = (struct hlist_head *) __get_free_page(GFP_KERNEL);
+ if (!dlm->lockres_hash) {
mlog_errno(-ENOMEM);
kfree(dlm->name);
kfree(dlm);
dlm = NULL;
goto leave;
}
- memset(dlm->resources, 0, PAGE_SIZE);
- for (i=0; i<DLM_HASH_SIZE; i++)
- INIT_LIST_HEAD(&dlm->resources[i]);
+ for (i=0; i<DLM_HASH_BUCKETS; i++)
+ INIT_HLIST_HEAD(&dlm->lockres_hash[i]);
strcpy(dlm->name, domain);
dlm->key = key;
diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c
index 2e2e95e69499..847dd3cc4cf5 100644
--- a/fs/ocfs2/dlm/dlmmaster.c
+++ b/fs/ocfs2/dlm/dlmmaster.c
@@ -564,7 +564,7 @@ static void dlm_lockres_release(struct kref *kref)
/* By the time we're ready to blow this guy away, we shouldn't
* be on any lists. */
- BUG_ON(!list_empty(&res->list));
+ BUG_ON(!hlist_unhashed(&res->hash_node));
BUG_ON(!list_empty(&res->granted));
BUG_ON(!list_empty(&res->converting));
BUG_ON(!list_empty(&res->blocked));
@@ -605,7 +605,7 @@ static void dlm_init_lockres(struct dlm_ctxt *dlm,
init_waitqueue_head(&res->wq);
spin_lock_init(&res->spinlock);
- INIT_LIST_HEAD(&res->list);
+ INIT_HLIST_NODE(&res->hash_node);
INIT_LIST_HEAD(&res->granted);
INIT_LIST_HEAD(&res->converting);
INIT_LIST_HEAD(&res->blocked);
diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c
index ed76bda1a534..1e232000f3f7 100644
--- a/fs/ocfs2/dlm/dlmrecovery.c
+++ b/fs/ocfs2/dlm/dlmrecovery.c
@@ -1693,7 +1693,10 @@ static void dlm_finish_local_lockres_recovery(struct dlm_ctxt *dlm,
u8 dead_node, u8 new_master)
{
int i;
- struct list_head *iter, *iter2, *bucket;
+ struct list_head *iter, *iter2;
+ struct hlist_node *hash_iter;
+ struct hlist_head *bucket;
+
struct dlm_lock_resource *res;
mlog_entry_void();
@@ -1717,10 +1720,9 @@ static void dlm_finish_local_lockres_recovery(struct dlm_ctxt *dlm,
* for now we need to run the whole hash, clear
* the RECOVERING state and set the owner
* if necessary */
- for (i=0; i<DLM_HASH_SIZE; i++) {
- bucket = &(dlm->resources[i]);
- list_for_each(iter, bucket) {
- res = list_entry (iter, struct dlm_lock_resource, list);
+ for (i = 0; i < DLM_HASH_BUCKETS; i++) {
+ bucket = &(dlm->lockres_hash[i]);
+ hlist_for_each_entry(res, hash_iter, bucket, hash_node) {
if (res->state & DLM_LOCK_RES_RECOVERING) {
if (res->owner == dead_node) {
mlog(0, "(this=%u) res %.*s owner=%u "
@@ -1852,10 +1854,10 @@ static void dlm_free_dead_locks(struct dlm_ctxt *dlm,
static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node)
{
- struct list_head *iter;
+ struct hlist_node *iter;
struct dlm_lock_resource *res;
int i;
- struct list_head *bucket;
+ struct hlist_head *bucket;
struct dlm_lock *lock;
@@ -1876,10 +1878,9 @@ static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node)
* can be kicked again to see if any ASTs or BASTs
* need to be fired as a result.
*/
- for (i=0; i<DLM_HASH_SIZE; i++) {
- bucket = &(dlm->resources[i]);
- list_for_each(iter, bucket) {
- res = list_entry (iter, struct dlm_lock_resource, list);
+ for (i = 0; i < DLM_HASH_BUCKETS; i++) {
+ bucket = &(dlm->lockres_hash[i]);
+ hlist_for_each_entry(res, iter, bucket, hash_node) {
/* always prune any $RECOVERY entries for dead nodes,
* otherwise hangs can occur during later recovery */
if (dlm_is_recovery_lock(res->lockname.name,
diff --git a/fs/ocfs2/extent_map.c b/fs/ocfs2/extent_map.c
index b6ba292e9544..e6f207eebab4 100644
--- a/fs/ocfs2/extent_map.c
+++ b/fs/ocfs2/extent_map.c
@@ -181,6 +181,12 @@ static int ocfs2_extent_map_find_leaf(struct inode *inode,
ret = -EBADR;
if (rec_end > OCFS2_I(inode)->ip_clusters) {
mlog_errno(ret);
+ ocfs2_error(inode->i_sb,
+ "Extent %d at e_blkno %"MLFu64" of inode %"MLFu64" goes past ip_clusters of %u\n",
+ i,
+ le64_to_cpu(rec->e_blkno),
+ OCFS2_I(inode)->ip_blkno,
+ OCFS2_I(inode)->ip_clusters);
goto out_free;
}
@@ -226,6 +232,12 @@ static int ocfs2_extent_map_find_leaf(struct inode *inode,
ret = -EBADR;
if (blkno) {
mlog_errno(ret);
+ ocfs2_error(inode->i_sb,
+ "Multiple extents for (cpos = %u, clusters = %u) on inode %"MLFu64"; e_blkno %"MLFu64" and rec %d at e_blkno %"MLFu64"\n",
+ cpos, clusters,
+ OCFS2_I(inode)->ip_blkno,
+ blkno, i,
+ le64_to_cpu(rec->e_blkno));
goto out_free;
}
@@ -238,6 +250,10 @@ static int ocfs2_extent_map_find_leaf(struct inode *inode,
*/
ret = -EBADR;
if (!blkno) {
+ ocfs2_error(inode->i_sb,
+ "No record found for (cpos = %u, clusters = %u) on inode %"MLFu64"\n",
+ cpos, clusters,
+ OCFS2_I(inode)->ip_blkno);
mlog_errno(ret);
goto out_free;
}
@@ -266,6 +282,20 @@ static int ocfs2_extent_map_find_leaf(struct inode *inode,
for (i = 0; i < le16_to_cpu(el->l_next_free_rec); i++) {
rec = &el->l_recs[i];
+
+ if ((le32_to_cpu(rec->e_cpos) + le32_to_cpu(rec->e_clusters)) >
+ OCFS2_I(inode)->ip_clusters) {
+ ret = -EBADR;
+ mlog_errno(ret);
+ ocfs2_error(inode->i_sb,
+ "Extent %d at e_blkno %"MLFu64" of inode %"MLFu64" goes past ip_clusters of %u\n",
+ i,
+ le64_to_cpu(rec->e_blkno),
+ OCFS2_I(inode)->ip_blkno,
+ OCFS2_I(inode)->ip_clusters);
+ return ret;
+ }
+
ret = ocfs2_extent_map_insert(inode, rec,
le16_to_cpu(el->l_tree_depth));
if (ret) {
@@ -526,6 +556,10 @@ static int ocfs2_extent_map_insert(struct inode *inode,
OCFS2_I(inode)->ip_map.em_clusters) {
ret = -EBADR;
mlog_errno(ret);
+ ocfs2_error(inode->i_sb,
+ "Zero e_clusters on non-tail extent record at e_blkno %"MLFu64" on inode %"MLFu64"\n",
+ le64_to_cpu(rec->e_blkno),
+ OCFS2_I(inode)->ip_blkno);
return ret;
}
@@ -588,12 +622,12 @@ static int ocfs2_extent_map_insert(struct inode *inode,
* Existing record in the extent map:
*
* cpos = 10, len = 10
- * |---------|
+ * |---------|
*
* New Record:
*
* cpos = 10, len = 20
- * |------------------|
+ * |------------------|
*
* The passed record is the new on-disk record. The new_clusters value
* is how many clusters were added to the file. If the append is a
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 1715bc90e705..8a4048b55fdc 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -933,9 +933,6 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
struct file *filp = iocb->ki_filp;
struct inode *inode = filp->f_dentry->d_inode;
loff_t newsize, saved_pos;
-#ifdef OCFS2_ORACORE_WORKAROUNDS
- struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
-#endif
mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", filp, buf,
(unsigned int)count,
@@ -951,14 +948,6 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
return -EIO;
}
-#ifdef OCFS2_ORACORE_WORKAROUNDS
- /* ugh, work around some applications which open everything O_DIRECT +
- * O_APPEND and really don't mean to use O_DIRECT. */
- if (osb->s_mount_opt & OCFS2_MOUNT_COMPAT_OCFS &&
- (filp->f_flags & O_APPEND) && (filp->f_flags & O_DIRECT))
- filp->f_flags &= ~O_DIRECT;
-#endif
-
mutex_lock(&inode->i_mutex);
/* to match setattr's i_mutex -> i_alloc_sem -> rw_lock ordering */
if (filp->f_flags & O_DIRECT) {
@@ -1079,27 +1068,7 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
/* communicate with ocfs2_dio_end_io */
ocfs2_iocb_set_rw_locked(iocb);
-#ifdef OCFS2_ORACORE_WORKAROUNDS
- if (osb->s_mount_opt & OCFS2_MOUNT_COMPAT_OCFS &&
- filp->f_flags & O_DIRECT) {
- unsigned int saved_flags = filp->f_flags;
- int sector_size = 1 << osb->s_sectsize_bits;
-
- if ((saved_pos & (sector_size - 1)) ||
- (count & (sector_size - 1)) ||
- ((unsigned long)buf & (sector_size - 1))) {
- filp->f_flags |= O_SYNC;
- filp->f_flags &= ~O_DIRECT;
- }
-
- ret = generic_file_aio_write_nolock(iocb, &local_iov, 1,
- &iocb->ki_pos);
-
- filp->f_flags = saved_flags;
- } else
-#endif
- ret = generic_file_aio_write_nolock(iocb, &local_iov, 1,
- &iocb->ki_pos);
+ ret = generic_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos);
/* buffered aio wouldn't have proper lock coverage today */
BUG_ON(ret == -EIOCBQUEUED && !(filp->f_flags & O_DIRECT));
@@ -1140,9 +1109,6 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb,
int ret = 0, rw_level = -1, have_alloc_sem = 0;
struct file *filp = iocb->ki_filp;
struct inode *inode = filp->f_dentry->d_inode;
-#ifdef OCFS2_ORACORE_WORKAROUNDS
- struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
-#endif
mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", filp, buf,
(unsigned int)count,
@@ -1155,21 +1121,6 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb,
goto bail;
}
-#ifdef OCFS2_ORACORE_WORKAROUNDS
- if (osb->s_mount_opt & OCFS2_MOUNT_COMPAT_OCFS) {
- if (filp->f_flags & O_DIRECT) {
- int sector_size = 1 << osb->s_sectsize_bits;
-
- if ((pos & (sector_size - 1)) ||
- (count & (sector_size - 1)) ||
- ((unsigned long)buf & (sector_size - 1)) ||
- (i_size_read(inode) & (sector_size -1))) {
- filp->f_flags &= ~O_DIRECT;
- }
- }
- }
-#endif
-
/*
* buffered reads protect themselves in ->readpage(). O_DIRECT reads
* need locks to protect pending reads from racing with truncate.
diff --git a/fs/ocfs2/heartbeat.c b/fs/ocfs2/heartbeat.c
index 0bbd22f46c80..cbfd45a97a63 100644
--- a/fs/ocfs2/heartbeat.c
+++ b/fs/ocfs2/heartbeat.c
@@ -67,6 +67,7 @@ void ocfs2_init_node_maps(struct ocfs2_super *osb)
ocfs2_node_map_init(&osb->mounted_map);
ocfs2_node_map_init(&osb->recovery_map);
ocfs2_node_map_init(&osb->umount_map);
+ ocfs2_node_map_init(&osb->osb_recovering_orphan_dirs);
}
static void ocfs2_do_node_down(int node_num,
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index 8122489c5762..315472a5c192 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -41,6 +41,7 @@
#include "dlmglue.h"
#include "extent_map.h"
#include "file.h"
+#include "heartbeat.h"
#include "inode.h"
#include "journal.h"
#include "namei.h"
@@ -544,6 +545,42 @@ bail:
return status;
}
+/*
+ * Serialize with orphan dir recovery. If the process doing
+ * recovery on this orphan dir does an iget() with the dir
+ * i_mutex held, we'll deadlock here. Instead we detect this
+ * and exit early - recovery will wipe this inode for us.
+ */
+static int ocfs2_check_orphan_recovery_state(struct ocfs2_super *osb,
+ int slot)
+{
+ int ret = 0;
+
+ spin_lock(&osb->osb_lock);
+ if (ocfs2_node_map_test_bit(osb, &osb->osb_recovering_orphan_dirs, slot)) {
+ mlog(0, "Recovery is happening on orphan dir %d, will skip "
+ "this inode\n", slot);
+ ret = -EDEADLK;
+ goto out;
+ }
+ /* This signals to the orphan recovery process that it should
+ * wait for us to handle the wipe. */
+ osb->osb_orphan_wipes[slot]++;
+out:
+ spin_unlock(&osb->osb_lock);
+ return ret;
+}
+
+static void ocfs2_signal_wipe_completion(struct ocfs2_super *osb,
+ int slot)
+{
+ spin_lock(&osb->osb_lock);
+ osb->osb_orphan_wipes[slot]--;
+ spin_unlock(&osb->osb_lock);
+
+ wake_up(&osb->osb_wipe_event);
+}
+
static int ocfs2_wipe_inode(struct inode *inode,
struct buffer_head *di_bh)
{
@@ -555,6 +592,11 @@ static int ocfs2_wipe_inode(struct inode *inode,
/* We've already voted on this so it should be readonly - no
* spinlock needed. */
orphaned_slot = OCFS2_I(inode)->ip_orphaned_slot;
+
+ status = ocfs2_check_orphan_recovery_state(osb, orphaned_slot);
+ if (status)
+ return status;
+
orphan_dir_inode = ocfs2_get_system_file_inode(osb,
ORPHAN_DIR_SYSTEM_INODE,
orphaned_slot);
@@ -597,6 +639,7 @@ bail_unlock_dir:
brelse(orphan_dir_bh);
bail:
iput(orphan_dir_inode);
+ ocfs2_signal_wipe_completion(osb, orphaned_slot);
return status;
}
@@ -822,7 +865,8 @@ void ocfs2_delete_inode(struct inode *inode)
status = ocfs2_wipe_inode(inode, di_bh);
if (status < 0) {
- mlog_errno(status);
+ if (status != -EDEADLK)
+ mlog_errno(status);
goto bail_unlock_inode;
}
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
index d329c9df90ae..4be801f4559b 100644
--- a/fs/ocfs2/journal.c
+++ b/fs/ocfs2/journal.c
@@ -1408,21 +1408,17 @@ bail:
return status;
}
-static int ocfs2_recover_orphans(struct ocfs2_super *osb,
- int slot)
+static int ocfs2_queue_orphans(struct ocfs2_super *osb,
+ int slot,
+ struct inode **head)
{
- int status = 0;
- int have_disk_lock = 0;
- struct inode *inode = NULL;
- struct inode *iter;
+ int status;
struct inode *orphan_dir_inode = NULL;
+ struct inode *iter;
unsigned long offset, blk, local;
struct buffer_head *bh = NULL;
struct ocfs2_dir_entry *de;
struct super_block *sb = osb->sb;
- struct ocfs2_inode_info *oi;
-
- mlog(0, "Recover inodes from orphan dir in slot %d\n", slot);
orphan_dir_inode = ocfs2_get_system_file_inode(osb,
ORPHAN_DIR_SYSTEM_INODE,
@@ -1430,17 +1426,15 @@ static int ocfs2_recover_orphans(struct ocfs2_super *osb,
if (!orphan_dir_inode) {
status = -ENOENT;
mlog_errno(status);
- goto out;
- }
+ return status;
+ }
mutex_lock(&orphan_dir_inode->i_mutex);
status = ocfs2_meta_lock(orphan_dir_inode, NULL, NULL, 0);
if (status < 0) {
- mutex_unlock(&orphan_dir_inode->i_mutex);
mlog_errno(status);
goto out;
}
- have_disk_lock = 1;
offset = 0;
iter = NULL;
@@ -1451,11 +1445,10 @@ static int ocfs2_recover_orphans(struct ocfs2_super *osb,
if (!bh)
status = -EINVAL;
if (status < 0) {
- mutex_unlock(&orphan_dir_inode->i_mutex);
if (bh)
brelse(bh);
mlog_errno(status);
- goto out;
+ goto out_unlock;
}
local = 0;
@@ -1465,11 +1458,10 @@ static int ocfs2_recover_orphans(struct ocfs2_super *osb,
if (!ocfs2_check_dir_entry(orphan_dir_inode,
de, bh, local)) {
- mutex_unlock(&orphan_dir_inode->i_mutex);
status = -EINVAL;
mlog_errno(status);
brelse(bh);
- goto out;
+ goto out_unlock;
}
local += le16_to_cpu(de->rec_len);
@@ -1504,18 +1496,95 @@ static int ocfs2_recover_orphans(struct ocfs2_super *osb,
mlog(0, "queue orphan %"MLFu64"\n",
OCFS2_I(iter)->ip_blkno);
- OCFS2_I(iter)->ip_next_orphan = inode;
- inode = iter;
+ /* No locking is required for the next_orphan
+ * queue as there is only ever a single
+ * process doing orphan recovery. */
+ OCFS2_I(iter)->ip_next_orphan = *head;
+ *head = iter;
}
brelse(bh);
}
- mutex_unlock(&orphan_dir_inode->i_mutex);
+out_unlock:
ocfs2_meta_unlock(orphan_dir_inode, 0);
- have_disk_lock = 0;
-
+out:
+ mutex_unlock(&orphan_dir_inode->i_mutex);
iput(orphan_dir_inode);
- orphan_dir_inode = NULL;
+ return status;
+}
+
+static int ocfs2_orphan_recovery_can_continue(struct ocfs2_super *osb,
+ int slot)
+{
+ int ret;
+
+ spin_lock(&osb->osb_lock);
+ ret = !osb->osb_orphan_wipes[slot];
+ spin_unlock(&osb->osb_lock);
+ return ret;
+}
+
+static void ocfs2_mark_recovering_orphan_dir(struct ocfs2_super *osb,
+ int slot)
+{
+ spin_lock(&osb->osb_lock);
+ /* Mark ourselves such that new processes in delete_inode()
+ * know to quit early. */
+ ocfs2_node_map_set_bit(osb, &osb->osb_recovering_orphan_dirs, slot);
+ while (osb->osb_orphan_wipes[slot]) {
+ /* If any processes are already in the middle of an
+ * orphan wipe on this dir, then we need to wait for
+ * them. */
+ spin_unlock(&osb->osb_lock);
+ wait_event_interruptible(osb->osb_wipe_event,
+ ocfs2_orphan_recovery_can_continue(osb, slot));
+ spin_lock(&osb->osb_lock);
+ }
+ spin_unlock(&osb->osb_lock);
+}
+
+static void ocfs2_clear_recovering_orphan_dir(struct ocfs2_super *osb,
+ int slot)
+{
+ ocfs2_node_map_clear_bit(osb, &osb->osb_recovering_orphan_dirs, slot);
+}
+
+/*
+ * Orphan recovery. Each mounted node has it's own orphan dir which we
+ * must run during recovery. Our strategy here is to build a list of
+ * the inodes in the orphan dir and iget/iput them. The VFS does
+ * (most) of the rest of the work.
+ *
+ * Orphan recovery can happen at any time, not just mount so we have a
+ * couple of extra considerations.
+ *
+ * - We grab as many inodes as we can under the orphan dir lock -
+ * doing iget() outside the orphan dir risks getting a reference on
+ * an invalid inode.
+ * - We must be sure not to deadlock with other processes on the
+ * system wanting to run delete_inode(). This can happen when they go
+ * to lock the orphan dir and the orphan recovery process attempts to
+ * iget() inside the orphan dir lock. This can be avoided by
+ * advertising our state to ocfs2_delete_inode().
+ */
+static int ocfs2_recover_orphans(struct ocfs2_super *osb,
+ int slot)
+{
+ int ret = 0;
+ struct inode *inode = NULL;
+ struct inode *iter;
+ struct ocfs2_inode_info *oi;
+
+ mlog(0, "Recover inodes from orphan dir in slot %d\n", slot);
+
+ ocfs2_mark_recovering_orphan_dir(osb, slot);
+ ret = ocfs2_queue_orphans(osb, slot, &inode);
+ ocfs2_clear_recovering_orphan_dir(osb, slot);
+
+ /* Error here should be noted, but we want to continue with as
+ * many queued inodes as we've got. */
+ if (ret)
+ mlog_errno(ret);
while (inode) {
oi = OCFS2_I(inode);
@@ -1541,14 +1610,7 @@ static int ocfs2_recover_orphans(struct ocfs2_super *osb,
inode = iter;
}
-out:
- if (have_disk_lock)
- ocfs2_meta_unlock(orphan_dir_inode, 0);
-
- if (orphan_dir_inode)
- iput(orphan_dir_inode);
-
- return status;
+ return ret;
}
static int ocfs2_wait_on_mount(struct ocfs2_super *osb)
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h
index 8d8e4779df92..e89de9b6e491 100644
--- a/fs/ocfs2/ocfs2.h
+++ b/fs/ocfs2/ocfs2.h
@@ -174,9 +174,6 @@ enum ocfs2_mount_options
OCFS2_MOUNT_NOINTR = 1 << 2, /* Don't catch signals */
OCFS2_MOUNT_ERRORS_PANIC = 1 << 3, /* Panic on errors */
OCFS2_MOUNT_DATA_WRITEBACK = 1 << 4, /* No data ordering */
-#ifdef OCFS2_ORACORE_WORKAROUNDS
- OCFS2_MOUNT_COMPAT_OCFS = 1 << 30, /* ocfs1 compatibility mode */
-#endif
};
#define OCFS2_OSB_SOFT_RO 0x0001
@@ -290,6 +287,10 @@ struct ocfs2_super
struct inode *osb_tl_inode;
struct buffer_head *osb_tl_bh;
struct work_struct osb_truncate_log_wq;
+
+ struct ocfs2_node_map osb_recovering_orphan_dirs;
+ unsigned int *osb_orphan_wipes;
+ wait_queue_head_t osb_wipe_event;
};
#define OCFS2_SB(sb) ((struct ocfs2_super *)(sb)->s_fs_info)
diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h
index dfb8a5bedfc8..c5b1ac547c15 100644
--- a/fs/ocfs2/ocfs2_fs.h
+++ b/fs/ocfs2/ocfs2_fs.h
@@ -138,7 +138,6 @@
/* Journal limits (in bytes) */
#define OCFS2_MIN_JOURNAL_SIZE (4 * 1024 * 1024)
-#define OCFS2_MAX_JOURNAL_SIZE (500 * 1024 * 1024)
struct ocfs2_system_inode_info {
char *si_name;
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 046824b6b625..09e1c57a86a0 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -959,7 +959,7 @@ static int ocfs2_initialize_mem_caches(void)
ocfs2_lock_cache = kmem_cache_create("ocfs2_lock",
sizeof(struct ocfs2_journal_lock),
0,
- SLAB_NO_REAP|SLAB_HWCACHE_ALIGN,
+ SLAB_HWCACHE_ALIGN,
NULL, NULL);
if (!ocfs2_lock_cache)
return -ENOMEM;
@@ -1325,6 +1325,16 @@ static int ocfs2_initialize_super(struct super_block *sb,
}
mlog(ML_NOTICE, "max_slots for this device: %u\n", osb->max_slots);
+ init_waitqueue_head(&osb->osb_wipe_event);
+ osb->osb_orphan_wipes = kcalloc(osb->max_slots,
+ sizeof(*osb->osb_orphan_wipes),
+ GFP_KERNEL);
+ if (!osb->osb_orphan_wipes) {
+ status = -ENOMEM;
+ mlog_errno(status);
+ goto bail;
+ }
+
osb->s_feature_compat =
le32_to_cpu(OCFS2_RAW_SB(di)->s_feature_compat);
osb->s_feature_ro_compat =
@@ -1638,6 +1648,7 @@ static void ocfs2_delete_osb(struct ocfs2_super *osb)
if (osb->slot_info)
ocfs2_free_slot_info(osb->slot_info);
+ kfree(osb->osb_orphan_wipes);
/* FIXME
* This belongs in journal shutdown, but because we have to
* allocate osb->journal at the start of ocfs2_initalize_osb(),
diff --git a/fs/partitions/ibm.c b/fs/partitions/ibm.c
index 78010ad60e47..1e4a93835fed 100644
--- a/fs/partitions/ibm.c
+++ b/fs/partitions/ibm.c
@@ -52,6 +52,7 @@ int
ibm_partition(struct parsed_partitions *state, struct block_device *bdev)
{
int blocksize, offset, size;
+ loff_t i_size;
dasd_information_t *info;
struct hd_geometry *geo;
char type[5] = {0,};
@@ -63,6 +64,13 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev)
unsigned char *data;
Sector sect;
+ blocksize = bdev_hardsect_size(bdev);
+ if (blocksize <= 0)
+ return 0;
+ i_size = i_size_read(bdev->bd_inode);
+ if (i_size == 0)
+ return 0;
+
if ((info = kmalloc(sizeof(dasd_information_t), GFP_KERNEL)) == NULL)
goto out_noinfo;
if ((geo = kmalloc(sizeof(struct hd_geometry), GFP_KERNEL)) == NULL)
@@ -73,9 +81,6 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev)
if (ioctl_by_bdev(bdev, BIODASDINFO, (unsigned long)info) != 0 ||
ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo) != 0)
goto out_noioctl;
-
- if ((blocksize = bdev_hardsect_size(bdev)) <= 0)
- goto out_badsect;
/*
* Get volume label, extract name and type.
@@ -111,7 +116,7 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev)
} else {
printk("CMS1/%8s:", name);
offset = (info->label_block + 1);
- size = bdev->bd_inode->i_size >> 9;
+ size = i_size >> 9;
}
put_partition(state, 1, offset*(blocksize >> 9),
size-offset*(blocksize >> 9));
@@ -168,7 +173,7 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev)
else
printk("(nonl)/%8s:", name);
offset = (info->label_block + 1);
- size = (bdev->bd_inode->i_size >> 9);
+ size = i_size >> 9;
put_partition(state, 1, offset*(blocksize >> 9),
size-offset*(blocksize >> 9));
}
@@ -180,7 +185,6 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev)
return 1;
out_readerr:
-out_badsect:
out_noioctl:
kfree(label);
out_nolab:
diff --git a/fs/pipe.c b/fs/pipe.c
index d722579df79a..8aada8e426f4 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -605,7 +605,7 @@ struct file_operations rdwr_fifo_fops = {
.fasync = pipe_rdwr_fasync,
};
-struct file_operations read_pipe_fops = {
+static struct file_operations read_pipe_fops = {
.llseek = no_llseek,
.read = pipe_read,
.readv = pipe_readv,
@@ -617,7 +617,7 @@ struct file_operations read_pipe_fops = {
.fasync = pipe_read_fasync,
};
-struct file_operations write_pipe_fops = {
+static struct file_operations write_pipe_fops = {
.llseek = no_llseek,
.read = bad_pipe_r,
.write = pipe_write,
@@ -629,7 +629,7 @@ struct file_operations write_pipe_fops = {
.fasync = pipe_write_fasync,
};
-struct file_operations rdwr_pipe_fops = {
+static struct file_operations rdwr_pipe_fops = {
.llseek = no_llseek,
.read = pipe_read,
.readv = pipe_readv,
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 0eaad41f4658..91b7c15ab373 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -204,7 +204,6 @@ static void smaps_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
{
pte_t *pte, ptent;
spinlock_t *ptl;
- unsigned long pfn;
struct page *page;
pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
@@ -214,12 +213,12 @@ static void smaps_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
continue;
mss->resident += PAGE_SIZE;
- pfn = pte_pfn(ptent);
- if (!pfn_valid(pfn))
+
+ page = vm_normal_page(vma, addr, ptent);
+ if (!page)
continue;
- page = pfn_to_page(pfn);
- if (page_count(page) >= 2) {
+ if (page_mapcount(page) >= 2) {
if (pte_dirty(ptent))
mss->shared_dirty += PAGE_SIZE;
else
@@ -289,7 +288,7 @@ static int show_smap(struct seq_file *m, void *v)
struct mem_size_stats mss;
memset(&mss, 0, sizeof mss);
- if (vma->vm_mm)
+ if (vma->vm_mm && !is_vm_hugetlb_page(vma))
smaps_pgd_range(vma, vma->vm_start, vma->vm_end, &mss);
return show_map_internal(m, v, &mss);
}
diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c
index 3f810acd0bfa..b1ca234068f6 100644
--- a/fs/ramfs/file-nommu.c
+++ b/fs/ramfs/file-nommu.c
@@ -87,8 +87,7 @@ static int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize)
xpages = 1UL << order;
npages = (newsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
- for (loop = 0; loop < npages; loop++)
- set_page_count(pages + loop, 1);
+ split_page(pages, order);
/* trim off any pages we don't actually require */
for (loop = npages; loop < xpages; loop++)
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
index c66bd5e4c05c..14bd2246fb6d 100644
--- a/fs/ramfs/inode.c
+++ b/fs/ramfs/inode.c
@@ -27,6 +27,7 @@
#include <linux/fs.h>
#include <linux/pagemap.h>
#include <linux/highmem.h>
+#include <linux/time.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/smp_lock.h>
@@ -104,6 +105,7 @@ ramfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
d_instantiate(dentry, inode);
dget(dentry); /* Extra count - pin the dentry in core */
error = 0;
+ dir->i_mtime = dir->i_ctime = CURRENT_TIME;
}
return error;
}
@@ -135,6 +137,7 @@ static int ramfs_symlink(struct inode * dir, struct dentry *dentry, const char *
inode->i_gid = dir->i_gid;
d_instantiate(dentry, inode);
dget(dentry);
+ dir->i_mtime = dir->i_ctime = CURRENT_TIME;
} else
iput(inode);
}
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c
index f3473176c83a..be12879bb179 100644
--- a/fs/reiserfs/file.c
+++ b/fs/reiserfs/file.c
@@ -1464,13 +1464,11 @@ static ssize_t reiserfs_file_write(struct file *file, /* the file we are going t
partially overwritten pages, if needed. And lock the pages,
so that nobody else can access these until we are done.
We get number of actual blocks needed as a result. */
- blocks_to_allocate =
- reiserfs_prepare_file_region_for_write(inode, pos,
- num_pages,
- write_bytes,
- prepared_pages);
- if (blocks_to_allocate < 0) {
- res = blocks_to_allocate;
+ res = reiserfs_prepare_file_region_for_write(inode, pos,
+ num_pages,
+ write_bytes,
+ prepared_pages);
+ if (res < 0) {
reiserfs_release_claimed_blocks(inode->i_sb,
num_pages <<
(PAGE_CACHE_SHIFT -
@@ -1478,6 +1476,8 @@ static ssize_t reiserfs_file_write(struct file *file, /* the file we are going t
break;
}
+ blocks_to_allocate = res;
+
/* First we correct our estimate of how many blocks we need */
reiserfs_release_claimed_blocks(inode->i_sb,
(num_pages <<
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index b33d67bba2fd..d60f6238c66a 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -627,11 +627,6 @@ int reiserfs_get_block(struct inode *inode, sector_t block,
reiserfs_write_lock(inode->i_sb);
version = get_inode_item_key_version(inode);
- if (block < 0) {
- reiserfs_write_unlock(inode->i_sb);
- return -EIO;
- }
-
if (!file_capable(inode, block)) {
reiserfs_write_unlock(inode->i_sb);
return -EFBIG;
@@ -934,12 +929,13 @@ int reiserfs_get_block(struct inode *inode, sector_t block,
//pos_in_item * inode->i_sb->s_blocksize,
TYPE_INDIRECT, 3); // key type is unimportant
+ RFALSE(cpu_key_k_offset(&tmp_key) > cpu_key_k_offset(&key),
+ "green-805: invalid offset");
blocks_needed =
1 +
((cpu_key_k_offset(&key) -
cpu_key_k_offset(&tmp_key)) >> inode->i_sb->
s_blocksize_bits);
- RFALSE(blocks_needed < 0, "green-805: invalid offset");
if (blocks_needed == 1) {
un = &unf_single;
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
index b7a179560ab4..5a9d2722fa0a 100644
--- a/fs/reiserfs/journal.c
+++ b/fs/reiserfs/journal.c
@@ -2319,8 +2319,7 @@ static int journal_read(struct super_block *p_s_sb)
return 1;
}
jh = (struct reiserfs_journal_header *)(journal->j_header_bh->b_data);
- if (le32_to_cpu(jh->j_first_unflushed_offset) >= 0 &&
- le32_to_cpu(jh->j_first_unflushed_offset) <
+ if (le32_to_cpu(jh->j_first_unflushed_offset) <
SB_ONDISK_JOURNAL_SIZE(p_s_sb)
&& le32_to_cpu(jh->j_last_flush_trans_id) > 0) {
oldest_start =
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
index c8123308e060..284f7852de8b 100644
--- a/fs/reiserfs/namei.c
+++ b/fs/reiserfs/namei.c
@@ -247,7 +247,7 @@ static int linear_search_in_dir_item(struct cpu_key *key,
/* mark, that this generation number is used */
if (de->de_gen_number_bit_string)
set_bit(GET_GENERATION_NUMBER(deh_offset(deh)),
- (unsigned long *)de->de_gen_number_bit_string);
+ de->de_gen_number_bit_string);
// calculate pointer to name and namelen
de->de_entry_num = i;
@@ -431,7 +431,7 @@ static int reiserfs_add_entry(struct reiserfs_transaction_handle *th,
struct reiserfs_de_head *deh;
INITIALIZE_PATH(path);
struct reiserfs_dir_entry de;
- int bit_string[MAX_GENERATION_NUMBER / (sizeof(int) * 8) + 1];
+ DECLARE_BITMAP(bit_string, MAX_GENERATION_NUMBER + 1);
int gen_number;
char small_buf[32 + DEH_SIZE]; /* 48 bytes now and we avoid kmalloc
if we create file with short name */
@@ -486,7 +486,7 @@ static int reiserfs_add_entry(struct reiserfs_transaction_handle *th,
/* find the proper place for the new entry */
memset(bit_string, 0, sizeof(bit_string));
- de.de_gen_number_bit_string = (char *)bit_string;
+ de.de_gen_number_bit_string = bit_string;
retval = reiserfs_find_entry(dir, name, namelen, &path, &de);
if (retval != NAME_NOT_FOUND) {
if (buffer != small_buf)
@@ -508,7 +508,7 @@ static int reiserfs_add_entry(struct reiserfs_transaction_handle *th,
}
gen_number =
- find_first_zero_bit((unsigned long *)bit_string,
+ find_first_zero_bit(bit_string,
MAX_GENERATION_NUMBER + 1);
if (gen_number > MAX_GENERATION_NUMBER) {
/* there is no free generation number */
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 49bd219275db..9ee956864445 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -50,6 +50,32 @@ static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd,
return sd;
}
+/**
+ *
+ * Return -EEXIST if there is already a sysfs element with the same name for
+ * the same parent.
+ *
+ * called with parent inode's i_mutex held
+ */
+int sysfs_dirent_exist(struct sysfs_dirent *parent_sd,
+ const unsigned char *new)
+{
+ struct sysfs_dirent * sd;
+
+ list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
+ if (sd->s_element) {
+ const unsigned char *existing = sysfs_get_name(sd);
+ if (strcmp(existing, new))
+ continue;
+ else
+ return -EEXIST;
+ }
+ }
+
+ return 0;
+}
+
+
int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry,
void * element, umode_t mode, int type)
{
@@ -102,7 +128,11 @@ static int create_dir(struct kobject * k, struct dentry * p,
mutex_lock(&p->d_inode->i_mutex);
*d = lookup_one_len(n, p, strlen(n));
if (!IS_ERR(*d)) {
- error = sysfs_make_dirent(p->d_fsdata, *d, k, mode, SYSFS_DIR);
+ if (sysfs_dirent_exist(p->d_fsdata, n))
+ error = -EEXIST;
+ else
+ error = sysfs_make_dirent(p->d_fsdata, *d, k, mode,
+ SYSFS_DIR);
if (!error) {
error = sysfs_create(*d, mode, init_dir);
if (!error) {
@@ -302,6 +332,7 @@ void sysfs_remove_dir(struct kobject * kobj)
* Drop reference from dget() on entrance.
*/
dput(dentry);
+ kobj->dentry = NULL;
}
int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
@@ -479,7 +510,3 @@ struct file_operations sysfs_dir_operations = {
.read = generic_read_dir,
.readdir = sysfs_readdir,
};
-
-EXPORT_SYMBOL_GPL(sysfs_create_dir);
-EXPORT_SYMBOL_GPL(sysfs_remove_dir);
-EXPORT_SYMBOL_GPL(sysfs_rename_dir);
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index d0e3d8495165..5e83e7246788 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -301,9 +301,8 @@ static int check_perm(struct inode * inode, struct file * file)
/* No error? Great, allocate a buffer for the file, and store it
* it in file->private_data for easy access.
*/
- buffer = kmalloc(sizeof(struct sysfs_buffer),GFP_KERNEL);
+ buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL);
if (buffer) {
- memset(buffer,0,sizeof(struct sysfs_buffer));
init_MUTEX(&buffer->sem);
buffer->needs_read_fill = 1;
buffer->ops = ops;
@@ -362,10 +361,12 @@ int sysfs_add_file(struct dentry * dir, const struct attribute * attr, int type)
{
struct sysfs_dirent * parent_sd = dir->d_fsdata;
umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG;
- int error = 0;
+ int error = -EEXIST;
mutex_lock(&dir->d_inode->i_mutex);
- error = sysfs_make_dirent(parent_sd, NULL, (void *) attr, mode, type);
+ if (!sysfs_dirent_exist(parent_sd, attr->name))
+ error = sysfs_make_dirent(parent_sd, NULL, (void *)attr,
+ mode, type);
mutex_unlock(&dir->d_inode->i_mutex);
return error;
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index 689f7bcfaf30..4c29ac41ac3e 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -54,11 +54,10 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)
if (!sd_iattr) {
/* setting attributes for the first time, allocate now */
- sd_iattr = kmalloc(sizeof(struct iattr), GFP_KERNEL);
+ sd_iattr = kzalloc(sizeof(struct iattr), GFP_KERNEL);
if (!sd_iattr)
return -ENOMEM;
/* assign default attributes */
- memset(sd_iattr, 0, sizeof(struct iattr));
sd_iattr->ia_mode = sd->s_mode;
sd_iattr->ia_uid = 0;
sd_iattr->ia_gid = 0;
@@ -227,12 +226,16 @@ void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent)
void sysfs_hash_and_remove(struct dentry * dir, const char * name)
{
struct sysfs_dirent * sd;
- struct sysfs_dirent * parent_sd = dir->d_fsdata;
+ struct sysfs_dirent * parent_sd;
+
+ if (!dir)
+ return;
if (dir->d_inode == NULL)
/* no inode means this hasn't been made visible yet */
return;
+ parent_sd = dir->d_fsdata;
mutex_lock(&dir->d_inode->i_mutex);
list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
if (!sd->s_element)
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c
index e38d6338a20d..d2eac3ceed5f 100644
--- a/fs/sysfs/symlink.c
+++ b/fs/sysfs/symlink.c
@@ -66,6 +66,7 @@ static int sysfs_add_link(struct dentry * parent, const char * name, struct kobj
if (!error)
return 0;
+ kobject_put(target);
kfree(sl->link_name);
exit2:
kfree(sl);
@@ -82,12 +83,13 @@ exit1:
int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * name)
{
struct dentry * dentry = kobj->dentry;
- int error = 0;
+ int error = -EEXIST;
BUG_ON(!kobj || !kobj->dentry || !name);
mutex_lock(&dentry->d_inode->i_mutex);
- error = sysfs_add_link(dentry, name, target);
+ if (!sysfs_dirent_exist(dentry->d_fsdata, name))
+ error = sysfs_add_link(dentry, name, target);
mutex_unlock(&dentry->d_inode->i_mutex);
return error;
}
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index 3f8953e0e5d0..cf11d5b789d9 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -5,6 +5,7 @@ extern kmem_cache_t *sysfs_dir_cachep;
extern struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *);
extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *));
+extern int sysfs_dirent_exist(struct sysfs_dirent *, const unsigned char *);
extern int sysfs_make_dirent(struct sysfs_dirent *, struct dentry *, void *,
umode_t, int);
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 395e582ee542..d04cff2273b6 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -1045,10 +1045,14 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
}
inode->i_uid = le32_to_cpu(fe->uid);
- if ( inode->i_uid == -1 ) inode->i_uid = UDF_SB(inode->i_sb)->s_uid;
+ if (inode->i_uid == -1 || UDF_QUERY_FLAG(inode->i_sb,
+ UDF_FLAG_UID_IGNORE))
+ inode->i_uid = UDF_SB(inode->i_sb)->s_uid;
inode->i_gid = le32_to_cpu(fe->gid);
- if ( inode->i_gid == -1 ) inode->i_gid = UDF_SB(inode->i_sb)->s_gid;
+ if (inode->i_gid == -1 || UDF_QUERY_FLAG(inode->i_sb,
+ UDF_FLAG_GID_IGNORE))
+ inode->i_gid = UDF_SB(inode->i_sb)->s_gid;
inode->i_nlink = le16_to_cpu(fe->fileLinkCount);
if (!inode->i_nlink)
@@ -1335,10 +1339,14 @@ udf_update_inode(struct inode *inode, int do_sync)
return err;
}
- if (inode->i_uid != UDF_SB(inode->i_sb)->s_uid)
+ if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_UID_FORGET))
+ fe->uid = cpu_to_le32(-1);
+ else if (inode->i_uid != UDF_SB(inode->i_sb)->s_uid)
fe->uid = cpu_to_le32(inode->i_uid);
- if (inode->i_gid != UDF_SB(inode->i_sb)->s_gid)
+ if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_GID_FORGET))
+ fe->gid = cpu_to_le32(-1);
+ else if (inode->i_gid != UDF_SB(inode->i_sb)->s_gid)
fe->gid = cpu_to_le32(inode->i_gid);
udfperms = ((inode->i_mode & S_IRWXO) ) |
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 4a6f49adc609..368d8f81fe54 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -269,7 +269,7 @@ enum {
Opt_gid, Opt_uid, Opt_umask, Opt_session, Opt_lastblock,
Opt_anchor, Opt_volume, Opt_partition, Opt_fileset,
Opt_rootdir, Opt_utf8, Opt_iocharset,
- Opt_err
+ Opt_err, Opt_uforget, Opt_uignore, Opt_gforget, Opt_gignore
};
static match_table_t tokens = {
@@ -282,6 +282,10 @@ static match_table_t tokens = {
{Opt_adinicb, "adinicb"},
{Opt_shortad, "shortad"},
{Opt_longad, "longad"},
+ {Opt_uforget, "uid=forget"},
+ {Opt_uignore, "uid=ignore"},
+ {Opt_gforget, "gid=forget"},
+ {Opt_gignore, "gid=ignore"},
{Opt_gid, "gid=%u"},
{Opt_uid, "uid=%u"},
{Opt_umask, "umask=%o"},
@@ -414,6 +418,18 @@ udf_parse_options(char *options, struct udf_options *uopt)
uopt->flags |= (1 << UDF_FLAG_NLS_MAP);
break;
#endif
+ case Opt_uignore:
+ uopt->flags |= (1 << UDF_FLAG_UID_IGNORE);
+ break;
+ case Opt_uforget:
+ uopt->flags |= (1 << UDF_FLAG_UID_FORGET);
+ break;
+ case Opt_gignore:
+ uopt->flags |= (1 << UDF_FLAG_GID_IGNORE);
+ break;
+ case Opt_gforget:
+ uopt->flags |= (1 << UDF_FLAG_GID_FORGET);
+ break;
default:
printk(KERN_ERR "udf: bad mount option \"%s\" "
"or missing value\n", p);
diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h
index 663669810be6..110f8d62616f 100644
--- a/fs/udf/udf_sb.h
+++ b/fs/udf/udf_sb.h
@@ -20,6 +20,10 @@
#define UDF_FLAG_VARCONV 8
#define UDF_FLAG_NLS_MAP 9
#define UDF_FLAG_UTF8 10
+#define UDF_FLAG_UID_FORGET 11 /* save -1 for uid to disk */
+#define UDF_FLAG_UID_IGNORE 12 /* use sb uid instead of on disk uid */
+#define UDF_FLAG_GID_FORGET 13
+#define UDF_FLAG_GID_IGNORE 14
#define UDF_PART_FLAG_UNALLOC_BITMAP 0x0001
#define UDF_PART_FLAG_UNALLOC_TABLE 0x0002
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
index 8f2beec526cf..74d8be87f983 100644
--- a/fs/xfs/linux-2.6/xfs_aops.c
+++ b/fs/xfs/linux-2.6/xfs_aops.c
@@ -540,7 +540,7 @@ xfs_probe_cluster(
/* First sum forwards in this page */
do {
- if (mapped != buffer_mapped(bh))
+ if (!buffer_uptodate(bh) || (mapped != buffer_mapped(bh)))
return total;
total += bh->b_size;
} while ((bh = bh->b_this_page) != head);
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c
index bfb4f2917bb6..8cdfa4151659 100644
--- a/fs/xfs/linux-2.6/xfs_buf.c
+++ b/fs/xfs/linux-2.6/xfs_buf.c
@@ -29,6 +29,7 @@
#include <linux/blkdev.h>
#include <linux/hash.h>
#include <linux/kthread.h>
+#include <linux/migrate.h>
#include "xfs_linux.h"
STATIC kmem_zone_t *xfs_buf_zone;
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c
index 53a00fb217fa..7c0e39dc6189 100644
--- a/fs/xfs/quota/xfs_qm.c
+++ b/fs/xfs/quota/xfs_qm.c
@@ -68,6 +68,9 @@ kmem_zone_t *qm_dqzone;
kmem_zone_t *qm_dqtrxzone;
STATIC kmem_shaker_t xfs_qm_shaker;
+STATIC cred_t xfs_zerocr;
+STATIC xfs_inode_t xfs_zeroino;
+
STATIC void xfs_qm_list_init(xfs_dqlist_t *, char *, int);
STATIC void xfs_qm_list_destroy(xfs_dqlist_t *);
@@ -1393,8 +1396,6 @@ xfs_qm_qino_alloc(
xfs_trans_t *tp;
int error;
unsigned long s;
- cred_t zerocr;
- xfs_inode_t zeroino;
int committed;
tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QINOCREATE);
@@ -1406,11 +1407,9 @@ xfs_qm_qino_alloc(
xfs_trans_cancel(tp, 0);
return error;
}
- memset(&zerocr, 0, sizeof(zerocr));
- memset(&zeroino, 0, sizeof(zeroino));
- if ((error = xfs_dir_ialloc(&tp, &zeroino, S_IFREG, 1, 0,
- &zerocr, 0, 1, ip, &committed))) {
+ if ((error = xfs_dir_ialloc(&tp, &xfs_zeroino, S_IFREG, 1, 0,
+ &xfs_zerocr, 0, 1, ip, &committed))) {
xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES |
XFS_TRANS_ABORT);
return error;
diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c
index 06fc061c50fc..5b413946b1c5 100644
--- a/fs/xfs/xfs_rtalloc.c
+++ b/fs/xfs/xfs_rtalloc.c
@@ -130,7 +130,8 @@ xfs_growfs_rt_alloc(
/*
* Lock the inode.
*/
- if ((error = xfs_trans_iget(mp, tp, ino, 0, XFS_ILOCK_EXCL, &ip)))
+ if ((error = xfs_trans_iget(mp, tp, ino, 0,
+ XFS_ILOCK_EXCL, &ip)))
goto error_exit;
XFS_BMAP_INIT(&flist, &firstblock);
/*
@@ -170,8 +171,8 @@ xfs_growfs_rt_alloc(
/*
* Lock the bitmap inode.
*/
- if ((error = xfs_trans_iget(mp, tp, ino, 0, XFS_ILOCK_EXCL,
- &ip)))
+ if ((error = xfs_trans_iget(mp, tp, ino, 0,
+ XFS_ILOCK_EXCL, &ip)))
goto error_exit;
/*
* Get a buffer for the block.
@@ -2023,8 +2024,8 @@ xfs_growfs_rt(
/*
* Lock out other callers by grabbing the bitmap inode lock.
*/
- if ((error = xfs_trans_iget(mp, tp, 0, mp->m_sb.sb_rbmino,
- XFS_ILOCK_EXCL, &ip)))
+ if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0,
+ XFS_ILOCK_EXCL, &ip)))
goto error_exit;
ASSERT(ip == mp->m_rbmip);
/*
@@ -2037,8 +2038,8 @@ xfs_growfs_rt(
/*
* Get the summary inode into the transaction.
*/
- if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rsumino,
- 0, XFS_ILOCK_EXCL, &ip)))
+ if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rsumino, 0,
+ XFS_ILOCK_EXCL, &ip)))
goto error_exit;
ASSERT(ip == mp->m_rsumip);
/*
@@ -2158,10 +2159,9 @@ xfs_rtallocate_extent(
/*
* Lock out other callers by grabbing the bitmap inode lock.
*/
- error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, XFS_ILOCK_EXCL, &ip);
- if (error) {
+ if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0,
+ XFS_ILOCK_EXCL, &ip)))
return error;
- }
sumbp = NULL;
/*
* Allocate by size, or near another block, or exactly at some block.
@@ -2221,10 +2221,9 @@ xfs_rtfree_extent(
/*
* Synchronize by locking the bitmap inode.
*/
- error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, XFS_ILOCK_EXCL, &ip);
- if (error) {
+ if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0,
+ XFS_ILOCK_EXCL, &ip)))
return error;
- }
#if defined(__KERNEL__) && defined(DEBUG)
/*
* Check to see that this whole range is currently allocated.
@@ -2365,8 +2364,8 @@ xfs_rtpick_extent(
__uint64_t seq; /* sequence number of file creation */
__uint64_t *seqp; /* pointer to seqno in inode */
- error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, XFS_ILOCK_EXCL, &ip);
- if (error)
+ if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0,
+ XFS_ILOCK_EXCL, &ip)))
return error;
ASSERT(ip == mp->m_rbmip);
seqp = (__uint64_t *)&ip->i_d.di_atime;