aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/9p/fid.c6
-rw-r--r--fs/9p/v9fs.c2
-rw-r--r--fs/9p/vfs_dentry.c9
-rw-r--r--fs/9p/vfs_inode.c10
-rw-r--r--fs/9p/vfs_super.c4
-rw-r--r--fs/Kconfig39
-rw-r--r--fs/Makefile5
-rw-r--r--fs/affs/inode.c4
-rw-r--r--fs/affs/super.c4
-rw-r--r--fs/afs/proc.c4
-rw-r--r--fs/afs/server.c9
-rw-r--r--fs/aio.c100
-rw-r--r--fs/anon_inodes.c11
-rw-r--r--fs/attr.c4
-rw-r--r--fs/autofs/inode.c4
-rw-r--r--fs/autofs4/dev-ioctl.c3
-rw-r--r--fs/autofs4/inode.c4
-rw-r--r--fs/autofs4/waitq.c4
-rw-r--r--fs/bad_inode.c6
-rw-r--r--fs/befs/linuxvfs.c5
-rw-r--r--fs/bfs/dir.c4
-rw-r--r--fs/binfmt_aout.c2
-rw-r--r--fs/binfmt_elf.c22
-rw-r--r--fs/binfmt_elf_fdpic.c19
-rw-r--r--fs/binfmt_flat.c2
-rw-r--r--fs/binfmt_som.c2
-rw-r--r--fs/bio-integrity.c2
-rw-r--r--fs/bio.c325
-rw-r--r--fs/block_dev.c30
-rw-r--r--fs/buffer.c19
-rw-r--r--fs/cifs/AUTHORS2
-rw-r--r--fs/cifs/CHANGES9
-rw-r--r--fs/cifs/Makefile2
-rw-r--r--fs/cifs/README12
-rw-r--r--fs/cifs/cifs_dfs_ref.c48
-rw-r--r--fs/cifs/cifs_fs_sb.h7
-rw-r--r--fs/cifs/cifs_spnego.c6
-rw-r--r--fs/cifs/cifsencrypt.c30
-rw-r--r--fs/cifs/cifsencrypt.h3
-rw-r--r--fs/cifs/cifsfs.c82
-rw-r--r--fs/cifs/cifsfs.h3
-rw-r--r--fs/cifs/cifsglob.h15
-rw-r--r--fs/cifs/cifspdu.h2
-rw-r--r--fs/cifs/cifsproto.h5
-rw-r--r--fs/cifs/cifssmb.c52
-rw-r--r--fs/cifs/connect.c685
-rw-r--r--fs/cifs/dir.c21
-rw-r--r--fs/cifs/fcntl.c118
-rw-r--r--fs/cifs/file.c25
-rw-r--r--fs/cifs/inode.c66
-rw-r--r--fs/cifs/ioctl.c2
-rw-r--r--fs/cifs/misc.c13
-rw-r--r--fs/cifs/sess.c5
-rw-r--r--fs/cifs/smbdes.c5
-rw-r--r--fs/cifs/smbencrypt.c9
-rw-r--r--fs/cifs/transport.c378
-rw-r--r--fs/coda/cache.c6
-rw-r--r--fs/coda/file.c3
-rw-r--r--fs/coda/upcall.c2
-rw-r--r--fs/compat.c42
-rw-r--r--fs/dcache.c25
-rw-r--r--fs/dcookies.c28
-rw-r--r--fs/devpts/inode.c472
-rw-r--r--fs/dlm/netlink.c2
-rw-r--r--fs/dquot.c4
-rw-r--r--fs/ecryptfs/ecryptfs_kernel.h3
-rw-r--r--fs/ecryptfs/inode.c3
-rw-r--r--fs/ecryptfs/kthread.c9
-rw-r--r--fs/ecryptfs/main.c3
-rw-r--r--fs/ecryptfs/messaging.c27
-rw-r--r--fs/ecryptfs/miscdev.c27
-rw-r--r--fs/exec.c206
-rw-r--r--fs/exportfs/expfs.c8
-rw-r--r--fs/ext2/balloc.c2
-rw-r--r--fs/ext2/ialloc.c10
-rw-r--r--fs/ext2/inode.c7
-rw-r--r--fs/ext2/namei.c15
-rw-r--r--fs/ext3/balloc.c2
-rw-r--r--fs/ext3/ialloc.c10
-rw-r--r--fs/ext3/inode.c7
-rw-r--r--fs/ext3/namei.c15
-rw-r--r--fs/ext4/balloc.c6
-rw-r--r--fs/ext4/ialloc.c10
-rw-r--r--fs/ext4/inode.c7
-rw-r--r--fs/ext4/namei.c14
-rw-r--r--fs/ext4/super.c8
-rw-r--r--fs/fat/dir.c1
-rw-r--r--fs/fat/file.c2
-rw-r--r--fs/fat/inode.c6
-rw-r--r--fs/fat/namei_vfat.c2
-rw-r--r--fs/fcntl.c25
-rw-r--r--fs/file_table.c20
-rw-r--r--fs/freevxfs/vxfs_inode.c4
-rw-r--r--fs/fuse/dev.c4
-rw-r--r--fs/fuse/dir.c23
-rw-r--r--fs/gfs2/inode.c10
-rw-r--r--fs/hfs/inode.c4
-rw-r--r--fs/hfs/super.c4
-rw-r--r--fs/hfsplus/inode.c4
-rw-r--r--fs/hfsplus/options.c4
-rw-r--r--fs/hpfs/namei.c24
-rw-r--r--fs/hpfs/super.c4
-rw-r--r--fs/hppfs/hppfs.c6
-rw-r--r--fs/hugetlbfs/inode.c21
-rw-r--r--fs/inode.c268
-rw-r--r--fs/internal.h6
-rw-r--r--fs/ioctl.c12
-rw-r--r--fs/ioprio.c18
-rw-r--r--fs/jfs/inode.c8
-rw-r--r--fs/jfs/jfs_inode.c33
-rw-r--r--fs/jfs/namei.c24
-rw-r--r--fs/lockd/clntlock.c23
-rw-r--r--fs/lockd/host.c21
-rw-r--r--fs/lockd/mon.c2
-rw-r--r--fs/lockd/svc.c7
-rw-r--r--fs/locks.c2
-rw-r--r--fs/minix/bitmap.c4
-rw-r--r--fs/namei.c125
-rw-r--r--fs/namespace.c4
-rw-r--r--fs/ncpfs/ioctl.c91
-rw-r--r--fs/nfs/callback.c36
-rw-r--r--fs/nfs/client.c95
-rw-r--r--fs/nfs/delegation.c260
-rw-r--r--fs/nfs/delegation.h33
-rw-r--r--fs/nfs/dir.c24
-rw-r--r--fs/nfs/inode.c13
-rw-r--r--fs/nfs/internal.h14
-rw-r--r--fs/nfs/mount_clnt.c34
-rw-r--r--fs/nfs/nfs4_fs.h32
-rw-r--r--fs/nfs/nfs4proc.c431
-rw-r--r--fs/nfs/nfs4renewd.c22
-rw-r--r--fs/nfs/nfs4state.c415
-rw-r--r--fs/nfs/nfs4xdr.c1235
-rw-r--r--fs/nfs/nfsroot.c33
-rw-r--r--fs/nfs/read.c6
-rw-r--r--fs/nfs/super.c50
-rw-r--r--fs/nfs_common/nfsacl.c4
-rw-r--r--fs/nfsctl.c10
-rw-r--r--fs/nfsd/auth.c95
-rw-r--r--fs/nfsd/nfs4callback.c9
-rw-r--r--fs/nfsd/nfs4recover.c72
-rw-r--r--fs/nfsd/nfs4state.c17
-rw-r--r--fs/nfsd/nfsctl.c2
-rw-r--r--fs/nfsd/nfsfh.c11
-rw-r--r--fs/nfsd/vfs.c9
-rw-r--r--fs/notify/Kconfig2
-rw-r--r--fs/notify/Makefile2
-rw-r--r--fs/notify/dnotify/Kconfig10
-rw-r--r--fs/notify/dnotify/Makefile1
-rw-r--r--fs/notify/dnotify/dnotify.c (renamed from fs/dnotify.c)3
-rw-r--r--fs/notify/inotify/Kconfig27
-rw-r--r--fs/notify/inotify/Makefile2
-rw-r--r--fs/notify/inotify/inotify.c (renamed from fs/inotify.c)2
-rw-r--r--fs/notify/inotify/inotify_user.c (renamed from fs/inotify_user.c)4
-rw-r--r--fs/ocfs2/cluster/netdebug.c8
-rw-r--r--fs/ocfs2/cluster/nodemanager.c2
-rw-r--r--fs/ocfs2/cluster/tcp.c29
-rw-r--r--fs/ocfs2/dlm/dlmfs.c8
-rw-r--r--fs/ocfs2/namei.c4
-rw-r--r--fs/ocfs2/ocfs2_fs.h8
-rw-r--r--fs/ocfs2/xattr.c4
-rw-r--r--fs/omfs/inode.c8
-rw-r--r--fs/open.c64
-rw-r--r--fs/pipe.c4
-rw-r--r--fs/posix_acl.c4
-rw-r--r--fs/proc/array.c32
-rw-r--r--fs/proc/base.c38
-rw-r--r--fs/proc/proc_devtree.c3
-rw-r--r--fs/proc/stat.c7
-rw-r--r--fs/proc/task_mmu.c4
-rw-r--r--fs/quota.c4
-rw-r--r--fs/ramfs/inode.c4
-rw-r--r--fs/reiserfs/inode.c15
-rw-r--r--fs/reiserfs/namei.c12
-rw-r--r--fs/seq_file.c24
-rw-r--r--fs/smbfs/dir.c3
-rw-r--r--fs/smbfs/inode.c2
-rw-r--r--fs/smbfs/proc.c2
-rw-r--r--fs/super.c2
-rw-r--r--fs/sysv/ialloc.c4
-rw-r--r--fs/sysv/inode.c6
-rw-r--r--fs/ubifs/budget.c2
-rw-r--r--fs/ubifs/dir.c4
-rw-r--r--fs/udf/ialloc.c4
-rw-r--r--fs/udf/namei.c2
-rw-r--r--fs/ufs/ialloc.c4
-rw-r--r--fs/xfs/Makefile6
-rw-r--r--fs/xfs/linux-2.6/sv.h22
-rw-r--r--fs/xfs/linux-2.6/xfs_aops.c66
-rw-r--r--fs/xfs/linux-2.6/xfs_aops.h3
-rw-r--r--fs/xfs/linux-2.6/xfs_buf.c87
-rw-r--r--fs/xfs/linux-2.6/xfs_buf.h30
-rw-r--r--fs/xfs/linux-2.6/xfs_cred.h12
-rw-r--r--fs/xfs/linux-2.6/xfs_export.c1
-rw-r--r--fs/xfs/linux-2.6/xfs_file.c189
-rw-r--r--fs/xfs/linux-2.6/xfs_fs_subr.c23
-rw-r--r--fs/xfs/linux-2.6/xfs_globals.c8
-rw-r--r--fs/xfs/linux-2.6/xfs_globals.h1
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl.c226
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl.h82
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl32.c849
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl32.h214
-rw-r--r--fs/xfs/linux-2.6/xfs_iops.c122
-rw-r--r--fs/xfs/linux-2.6/xfs_iops.h1
-rw-r--r--fs/xfs/linux-2.6/xfs_linux.h13
-rw-r--r--fs/xfs/linux-2.6/xfs_lrw.c50
-rw-r--r--fs/xfs/linux-2.6/xfs_stats.c6
-rw-r--r--fs/xfs/linux-2.6/xfs_stats.h65
-rw-r--r--fs/xfs/linux-2.6/xfs_super.c884
-rw-r--r--fs/xfs/linux-2.6/xfs_super.h15
-rw-r--r--fs/xfs/linux-2.6/xfs_sync.c762
-rw-r--r--fs/xfs/linux-2.6/xfs_sync.h55
-rw-r--r--fs/xfs/linux-2.6/xfs_sysctl.c11
-rw-r--r--fs/xfs/linux-2.6/xfs_sysctl.h3
-rw-r--r--fs/xfs/linux-2.6/xfs_vfs.h77
-rw-r--r--fs/xfs/linux-2.6/xfs_vnode.c145
-rw-r--r--fs/xfs/linux-2.6/xfs_vnode.h72
-rw-r--r--fs/xfs/quota/xfs_dquot.c39
-rw-r--r--fs/xfs/quota/xfs_dquot.h4
-rw-r--r--fs/xfs/quota/xfs_dquot_item.c45
-rw-r--r--fs/xfs/quota/xfs_qm.c57
-rw-r--r--fs/xfs/quota/xfs_qm.h3
-rw-r--r--fs/xfs/quota/xfs_qm_bhv.c5
-rw-r--r--fs/xfs/quota/xfs_qm_syscalls.c151
-rw-r--r--fs/xfs/support/debug.c39
-rw-r--r--fs/xfs/support/debug.h2
-rw-r--r--fs/xfs/support/ktrace.c9
-rw-r--r--fs/xfs/xfs.h2
-rw-r--r--fs/xfs/xfs_acl.c8
-rw-r--r--fs/xfs/xfs_ag.h15
-rw-r--r--fs/xfs/xfs_alloc.c264
-rw-r--r--fs/xfs/xfs_alloc.h27
-rw-r--r--fs/xfs/xfs_alloc_btree.c2387
-rw-r--r--fs/xfs/xfs_alloc_btree.h107
-rw-r--r--fs/xfs/xfs_arch.h39
-rw-r--r--fs/xfs/xfs_bit.h3
-rw-r--r--fs/xfs/xfs_bmap.c410
-rw-r--r--fs/xfs/xfs_bmap.h72
-rw-r--r--fs/xfs/xfs_bmap_btree.c2617
-rw-r--r--fs/xfs/xfs_bmap_btree.h171
-rw-r--r--fs/xfs/xfs_btree.c3596
-rw-r--r--fs/xfs/xfs_btree.h392
-rw-r--r--fs/xfs/xfs_btree_trace.c249
-rw-r--r--fs/xfs/xfs_btree_trace.h116
-rw-r--r--fs/xfs/xfs_buf_item.c45
-rw-r--r--fs/xfs/xfs_clnt.h105
-rw-r--r--fs/xfs/xfs_da_btree.h24
-rw-r--r--fs/xfs/xfs_dfrag.c8
-rw-r--r--fs/xfs/xfs_dfrag.h2
-rw-r--r--fs/xfs/xfs_dinode.h148
-rw-r--r--fs/xfs/xfs_dir2_sf.h7
-rw-r--r--fs/xfs/xfs_dmops.c5
-rw-r--r--fs/xfs/xfs_error.c15
-rw-r--r--fs/xfs/xfs_error.h12
-rw-r--r--fs/xfs/xfs_extfree_item.c45
-rw-r--r--fs/xfs/xfs_fs.h22
-rw-r--r--fs/xfs/xfs_fsops.c30
-rw-r--r--fs/xfs/xfs_ialloc.c449
-rw-r--r--fs/xfs/xfs_ialloc.h31
-rw-r--r--fs/xfs/xfs_ialloc_btree.c2193
-rw-r--r--fs/xfs/xfs_ialloc_btree.h111
-rw-r--r--fs/xfs/xfs_iget.c735
-rw-r--r--fs/xfs/xfs_imap.h40
-rw-r--r--fs/xfs/xfs_inode.c587
-rw-r--r--fs/xfs/xfs_inode.h377
-rw-r--r--fs/xfs/xfs_inode_item.c45
-rw-r--r--fs/xfs/xfs_inode_item.h41
-rw-r--r--fs/xfs/xfs_iomap.c28
-rw-r--r--fs/xfs/xfs_itable.c102
-rw-r--r--fs/xfs/xfs_itable.h14
-rw-r--r--fs/xfs/xfs_log.c81
-rw-r--r--fs/xfs/xfs_log.h4
-rw-r--r--fs/xfs/xfs_log_priv.h48
-rw-r--r--fs/xfs/xfs_log_recover.c416
-rw-r--r--fs/xfs/xfs_mount.c81
-rw-r--r--fs/xfs/xfs_mount.h73
-rw-r--r--fs/xfs/xfs_qmops.c5
-rw-r--r--fs/xfs/xfs_quota.h8
-rw-r--r--fs/xfs/xfs_rename.c61
-rw-r--r--fs/xfs/xfs_rtalloc.c41
-rw-r--r--fs/xfs/xfs_rw.c2
-rw-r--r--fs/xfs/xfs_sb.h167
-rw-r--r--fs/xfs/xfs_trans.c22
-rw-r--r--fs/xfs/xfs_trans.h322
-rw-r--r--fs/xfs/xfs_trans_ail.c362
-rw-r--r--fs/xfs/xfs_trans_buf.c7
-rw-r--r--fs/xfs/xfs_trans_inode.c30
-rw-r--r--fs/xfs/xfs_trans_item.c10
-rw-r--r--fs/xfs/xfs_trans_priv.h98
-rw-r--r--fs/xfs/xfs_utils.c12
-rw-r--r--fs/xfs/xfs_vfsops.c757
-rw-r--r--fs/xfs/xfs_vfsops.h16
-rw-r--r--fs/xfs/xfs_vnodeops.c354
-rw-r--r--fs/xfs/xfs_vnodeops.h16
294 files changed, 14740 insertions, 15807 deletions
diff --git a/fs/9p/fid.c b/fs/9p/fid.c
index 3031e3233dd..14d94420457 100644
--- a/fs/9p/fid.c
+++ b/fs/9p/fid.c
@@ -45,7 +45,7 @@ int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid)
struct v9fs_dentry *dent;
P9_DPRINTK(P9_DEBUG_VFS, "fid %d dentry %s\n",
- fid->fid, dentry->d_iname);
+ fid->fid, dentry->d_name.name);
dent = dentry->d_fsdata;
if (!dent) {
@@ -79,7 +79,7 @@ static struct p9_fid *v9fs_fid_find(struct dentry *dentry, u32 uid, int any)
struct p9_fid *fid, *ret;
P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p) uid %d any %d\n",
- dentry->d_iname, dentry, uid, any);
+ dentry->d_name.name, dentry, uid, any);
dent = (struct v9fs_dentry *) dentry->d_fsdata;
ret = NULL;
if (dent) {
@@ -120,7 +120,7 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
switch (access) {
case V9FS_ACCESS_SINGLE:
case V9FS_ACCESS_USER:
- uid = current->fsuid;
+ uid = current_fsuid();
any = 0;
break;
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index 24eb01087b6..332b5ff02fe 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -160,7 +160,7 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses)
v9ses->flags |= V9FS_ACCESS_ANY;
else {
v9ses->flags |= V9FS_ACCESS_SINGLE;
- v9ses->uid = simple_strtol(s, &e, 10);
+ v9ses->uid = simple_strtoul(s, &e, 10);
if (*e != '\0')
v9ses->uid = ~0;
}
diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c
index f9534f18df0..06dcc7c4f23 100644
--- a/fs/9p/vfs_dentry.c
+++ b/fs/9p/vfs_dentry.c
@@ -52,7 +52,8 @@
static int v9fs_dentry_delete(struct dentry *dentry)
{
- P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
+ P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_name.name,
+ dentry);
return 1;
}
@@ -69,7 +70,8 @@ static int v9fs_dentry_delete(struct dentry *dentry)
static int v9fs_cached_dentry_delete(struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
- P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
+ P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_name.name,
+ dentry);
if(!inode)
return 1;
@@ -88,7 +90,8 @@ void v9fs_dentry_release(struct dentry *dentry)
struct v9fs_dentry *dent;
struct p9_fid *temp, *current_fid;
- P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
+ P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_name.name,
+ dentry);
dent = dentry->d_fsdata;
if (dent) {
list_for_each_entry_safe(current_fid, temp, &dent->fidlist,
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 8314d3f43b7..81f8bbf12f9 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -215,8 +215,8 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
inode = new_inode(sb);
if (inode) {
inode->i_mode = mode;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
inode->i_blocks = 0;
inode->i_rdev = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
@@ -963,7 +963,8 @@ static int v9fs_vfs_readlink(struct dentry *dentry, char __user * buffer,
if (buflen > PATH_MAX)
buflen = PATH_MAX;
- P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
+ P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_name.name,
+ dentry);
retval = v9fs_readlink(dentry, link, buflen);
@@ -1022,7 +1023,8 @@ v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p)
{
char *s = nd_get_link(nd);
- P9_DPRINTK(P9_DEBUG_VFS, " %s %s\n", dentry->d_name.name, s);
+ P9_DPRINTK(P9_DEBUG_VFS, " %s %s\n", dentry->d_name.name,
+ IS_ERR(s) ? "<error>" : s);
if (!IS_ERR(s))
__putname(s);
}
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index d6cb1a0ca72..93212e40221 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -113,8 +113,8 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
struct v9fs_session_info *v9ses = NULL;
struct p9_wstat *st = NULL;
int mode = S_IRWXUGO | S_ISVTX;
- uid_t uid = current->fsuid;
- gid_t gid = current->fsgid;
+ uid_t uid = current_fsuid();
+ gid_t gid = current_fsgid();
struct p9_fid *fid;
int retval = 0;
diff --git a/fs/Kconfig b/fs/Kconfig
index 522469a7eca..ff0e8198020 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -270,44 +270,7 @@ config OCFS2_COMPAT_JBD
endif # BLOCK
-config DNOTIFY
- bool "Dnotify support"
- default y
- help
- Dnotify is a directory-based per-fd file change notification system
- that uses signals to communicate events to user-space. There exist
- superior alternatives, but some applications may still rely on
- dnotify.
-
- If unsure, say Y.
-
-config INOTIFY
- bool "Inotify file change notification support"
- default y
- ---help---
- Say Y here to enable inotify support. Inotify is a file change
- notification system and a replacement for dnotify. Inotify fixes
- numerous shortcomings in dnotify and introduces several new features
- including multiple file events, one-shot support, and unmount
- notification.
-
- For more information, see <file:Documentation/filesystems/inotify.txt>
-
- If unsure, say Y.
-
-config INOTIFY_USER
- bool "Inotify support for userspace"
- depends on INOTIFY
- default y
- ---help---
- Say Y here to enable inotify support for userspace, including the
- associated system calls. Inotify allows monitoring of both files and
- directories via a single open fd. Events are read from the file
- descriptor, which is also select()- and poll()-able.
-
- For more information, see <file:Documentation/filesystems/inotify.txt>
-
- If unsure, say Y.
+source "fs/notify/Kconfig"
config QUOTA
bool "Quota support"
diff --git a/fs/Makefile b/fs/Makefile
index d9f8afe6f0c..e6f423d1d22 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -20,8 +20,7 @@ obj-y += no-block.o
endif
obj-$(CONFIG_BLK_DEV_INTEGRITY) += bio-integrity.o
-obj-$(CONFIG_INOTIFY) += inotify.o
-obj-$(CONFIG_INOTIFY_USER) += inotify_user.o
+obj-y += notify/
obj-$(CONFIG_EPOLL) += eventpoll.o
obj-$(CONFIG_ANON_INODES) += anon_inodes.o
obj-$(CONFIG_SIGNALFD) += signalfd.o
@@ -57,8 +56,6 @@ obj-$(CONFIG_QFMT_V1) += quota_v1.o
obj-$(CONFIG_QFMT_V2) += quota_v2.o
obj-$(CONFIG_QUOTACTL) += quota.o
-obj-$(CONFIG_DNOTIFY) += dnotify.o
-
obj-$(CONFIG_PROC_FS) += proc/
obj-y += partitions/
obj-$(CONFIG_SYSFS) += sysfs/
diff --git a/fs/affs/inode.c b/fs/affs/inode.c
index a13b334a391..415d9c67ac1 100644
--- a/fs/affs/inode.c
+++ b/fs/affs/inode.c
@@ -293,8 +293,8 @@ affs_new_inode(struct inode *dir)
mark_buffer_dirty_inode(bh, inode);
affs_brelse(bh);
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
inode->i_ino = block;
inode->i_nlink = 1;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
diff --git a/fs/affs/super.c b/fs/affs/super.c
index 8989c93193e..a19d64b582a 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -163,8 +163,8 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, s
/* Fill in defaults */
- *uid = current->uid;
- *gid = current->gid;
+ *uid = current_uid();
+ *gid = current_gid();
*reserved = 2;
*root = -1;
*blocksize = -1;
diff --git a/fs/afs/proc.c b/fs/afs/proc.c
index 9f7d1ae7026..7578c1ab9e0 100644
--- a/fs/afs/proc.c
+++ b/fs/afs/proc.c
@@ -646,7 +646,7 @@ static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
}
/* display one cell per line on subsequent lines */
- seq_printf(m, "%u.%u.%u.%u\n", NIPQUAD(addr->s_addr));
+ seq_printf(m, "%pI4\n", &addr->s_addr);
return 0;
}
@@ -737,7 +737,7 @@ static int afs_proc_cell_servers_show(struct seq_file *m, void *v)
}
/* display one cell per line on subsequent lines */
- sprintf(ipaddr, "%u.%u.%u.%u", NIPQUAD(server->addr));
+ sprintf(ipaddr, "%pI4", &server->addr);
seq_printf(m, "%3d %-15.15s %5d\n",
atomic_read(&server->usage), ipaddr, server->fs_state);
diff --git a/fs/afs/server.c b/fs/afs/server.c
index 28f2451419e..f4909951667 100644
--- a/fs/afs/server.c
+++ b/fs/afs/server.c
@@ -105,7 +105,7 @@ struct afs_server *afs_lookup_server(struct afs_cell *cell,
{
struct afs_server *server, *candidate;
- _enter("%p,"NIPQUAD_FMT, cell, NIPQUAD(addr->s_addr));
+ _enter("%p,%pI4", cell, &addr->s_addr);
/* quick scan of the list to see if we already have the server */
read_lock(&cell->servers_lock);
@@ -168,9 +168,8 @@ found_server:
server_in_two_cells:
write_unlock(&cell->servers_lock);
kfree(candidate);
- printk(KERN_NOTICE "kAFS:"
- " Server "NIPQUAD_FMT" appears to be in two cells\n",
- NIPQUAD(*addr));
+ printk(KERN_NOTICE "kAFS: Server %pI4 appears to be in two cells\n",
+ addr);
_leave(" = -EEXIST");
return ERR_PTR(-EEXIST);
}
@@ -184,7 +183,7 @@ struct afs_server *afs_find_server(const struct in_addr *_addr)
struct rb_node *p;
struct in_addr addr = *_addr;
- _enter(NIPQUAD_FMT, NIPQUAD(addr.s_addr));
+ _enter("%pI4", &addr.s_addr);
read_lock(&afs_servers_lock);
diff --git a/fs/aio.c b/fs/aio.c
index f658441d566..d6f89d3c15e 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -191,6 +191,20 @@ static int aio_setup_ring(struct kioctx *ctx)
kunmap_atomic((void *)((unsigned long)__event & PAGE_MASK), km); \
} while(0)
+static void ctx_rcu_free(struct rcu_head *head)
+{
+ struct kioctx *ctx = container_of(head, struct kioctx, rcu_head);
+ unsigned nr_events = ctx->max_reqs;
+
+ kmem_cache_free(kioctx_cachep, ctx);
+
+ if (nr_events) {
+ spin_lock(&aio_nr_lock);
+ BUG_ON(aio_nr - nr_events > aio_nr);
+ aio_nr -= nr_events;
+ spin_unlock(&aio_nr_lock);
+ }
+}
/* __put_ioctx
* Called when the last user of an aio context has gone away,
@@ -198,8 +212,6 @@ static int aio_setup_ring(struct kioctx *ctx)
*/
static void __put_ioctx(struct kioctx *ctx)
{
- unsigned nr_events = ctx->max_reqs;
-
BUG_ON(ctx->reqs_active);
cancel_delayed_work(&ctx->wq);
@@ -208,14 +220,7 @@ static void __put_ioctx(struct kioctx *ctx)
mmdrop(ctx->mm);
ctx->mm = NULL;
pr_debug("__put_ioctx: freeing %p\n", ctx);
- kmem_cache_free(kioctx_cachep, ctx);
-
- if (nr_events) {
- spin_lock(&aio_nr_lock);
- BUG_ON(aio_nr - nr_events > aio_nr);
- aio_nr -= nr_events;
- spin_unlock(&aio_nr_lock);
- }
+ call_rcu(&ctx->rcu_head, ctx_rcu_free);
}
#define get_ioctx(kioctx) do { \
@@ -235,6 +240,7 @@ static struct kioctx *ioctx_alloc(unsigned nr_events)
{
struct mm_struct *mm;
struct kioctx *ctx;
+ int did_sync = 0;
/* Prevent overflows */
if ((nr_events > (0x10000000U / sizeof(struct io_event))) ||
@@ -267,21 +273,30 @@ static struct kioctx *ioctx_alloc(unsigned nr_events)
goto out_freectx;
/* limit the number of system wide aios */
- spin_lock(&aio_nr_lock);
- if (aio_nr + ctx->max_reqs > aio_max_nr ||
- aio_nr + ctx->max_reqs < aio_nr)
- ctx->max_reqs = 0;
- else
- aio_nr += ctx->max_reqs;
- spin_unlock(&aio_nr_lock);
+ do {
+ spin_lock_bh(&aio_nr_lock);
+ if (aio_nr + nr_events > aio_max_nr ||
+ aio_nr + nr_events < aio_nr)
+ ctx->max_reqs = 0;
+ else
+ aio_nr += ctx->max_reqs;
+ spin_unlock_bh(&aio_nr_lock);
+ if (ctx->max_reqs || did_sync)
+ break;
+
+ /* wait for rcu callbacks to have completed before giving up */
+ synchronize_rcu();
+ did_sync = 1;
+ ctx->max_reqs = nr_events;
+ } while (1);
+
if (ctx->max_reqs == 0)
goto out_cleanup;
/* now link into global list. */
- write_lock(&mm->ioctx_list_lock);
- ctx->next = mm->ioctx_list;
- mm->ioctx_list = ctx;
- write_unlock(&mm->ioctx_list_lock);
+ spin_lock(&mm->ioctx_lock);
+ hlist_add_head_rcu(&ctx->list, &mm->ioctx_list);
+ spin_unlock(&mm->ioctx_lock);
dprintk("aio: allocated ioctx %p[%ld]: mm=%p mask=0x%x\n",
ctx, ctx->user_id, current->mm, ctx->ring_info.nr);
@@ -375,11 +390,12 @@ ssize_t wait_on_sync_kiocb(struct kiocb *iocb)
*/
void exit_aio(struct mm_struct *mm)
{
- struct kioctx *ctx = mm->ioctx_list;
- mm->ioctx_list = NULL;
- while (ctx) {
- struct kioctx *next = ctx->next;
- ctx->next = NULL;
+ struct kioctx *ctx;
+
+ while (!hlist_empty(&mm->ioctx_list)) {
+ ctx = hlist_entry(mm->ioctx_list.first, struct kioctx, list);
+ hlist_del_rcu(&ctx->list);
+
aio_cancel_all(ctx);
wait_for_all_aios(ctx);
@@ -394,7 +410,6 @@ void exit_aio(struct mm_struct *mm)
atomic_read(&ctx->users), ctx->dead,
ctx->reqs_active);
put_ioctx(ctx);
- ctx = next;
}
}
@@ -555,19 +570,21 @@ int aio_put_req(struct kiocb *req)
static struct kioctx *lookup_ioctx(unsigned long ctx_id)
{
- struct kioctx *ioctx;
- struct mm_struct *mm;
+ struct mm_struct *mm = current->mm;
+ struct kioctx *ctx = NULL;
+ struct hlist_node *n;
- mm = current->mm;
- read_lock(&mm->ioctx_list_lock);
- for (ioctx = mm->ioctx_list; ioctx; ioctx = ioctx->next)
- if (likely(ioctx->user_id == ctx_id && !ioctx->dead)) {
- get_ioctx(ioctx);
+ rcu_read_lock();
+
+ hlist_for_each_entry_rcu(ctx, n, &mm->ioctx_list, list) {
+ if (ctx->user_id == ctx_id && !ctx->dead) {
+ get_ioctx(ctx);
break;
}
- read_unlock(&mm->ioctx_list_lock);
+ }
- return ioctx;
+ rcu_read_unlock();
+ return ctx;
}
/*
@@ -1215,19 +1232,14 @@ out:
static void io_destroy(struct kioctx *ioctx)
{
struct mm_struct *mm = current->mm;
- struct kioctx **tmp;
int was_dead;
/* delete the entry from the list is someone else hasn't already */
- write_lock(&mm->ioctx_list_lock);
+ spin_lock(&mm->ioctx_lock);
was_dead = ioctx->dead;
ioctx->dead = 1;
- for (tmp = &mm->ioctx_list; *tmp && *tmp != ioctx;
- tmp = &(*tmp)->next)
- ;
- if (*tmp)
- *tmp = ioctx->next;
- write_unlock(&mm->ioctx_list_lock);
+ hlist_del_rcu(&ioctx->list);
+ spin_unlock(&mm->ioctx_lock);
dprintk("aio_release(%p)\n", ioctx);
if (likely(!was_dead))
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
index 3662dd44896..3bbdb9d0237 100644
--- a/fs/anon_inodes.c
+++ b/fs/anon_inodes.c
@@ -79,9 +79,12 @@ int anon_inode_getfd(const char *name, const struct file_operations *fops,
if (IS_ERR(anon_inode_inode))
return -ENODEV;
+ if (fops->owner && !try_module_get(fops->owner))
+ return -ENOENT;
+
error = get_unused_fd_flags(flags);
if (error < 0)
- return error;
+ goto err_module;
fd = error;
/*
@@ -128,6 +131,8 @@ err_dput:
dput(dentry);
err_put_unused_fd:
put_unused_fd(fd);
+err_module:
+ module_put(fops->owner);
return error;
}
EXPORT_SYMBOL_GPL(anon_inode_getfd);
@@ -154,8 +159,8 @@ static struct inode *anon_inode_mkinode(void)
*/
inode->i_state = I_DIRTY;
inode->i_mode = S_IRUSR | S_IWUSR;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
return inode;
}
diff --git a/fs/attr.c b/fs/attr.c
index 7a83819f6ba..f4360192a93 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -29,13 +29,13 @@ int inode_change_ok(struct inode *inode, struct iattr *attr)
/* Make sure a caller can chown. */
if ((ia_valid & ATTR_UID) &&
- (current->fsuid != inode->i_uid ||
+ (current_fsuid() != inode->i_uid ||
attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN))
goto error;
/* Make sure caller can chgrp. */
if ((ia_valid & ATTR_GID) &&
- (current->fsuid != inode->i_uid ||
+ (current_fsuid() != inode->i_uid ||
(!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)) &&
!capable(CAP_CHOWN))
goto error;
diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c
index b70eea1e8c5..c773680d5c6 100644
--- a/fs/autofs/inode.c
+++ b/fs/autofs/inode.c
@@ -76,8 +76,8 @@ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid,
substring_t args[MAX_OPT_ARGS];
int option;
- *uid = current->uid;
- *gid = current->gid;
+ *uid = current_uid();
+ *gid = current_gid();
*pgrp = task_pgrp_nr(current);
*minproto = *maxproto = AUTOFS_PROTO_VERSION;
diff --git a/fs/autofs4/dev-ioctl.c b/fs/autofs4/dev-ioctl.c
index 33bf8cbfd05..63b7c7afe8d 100644
--- a/fs/autofs4/dev-ioctl.c
+++ b/fs/autofs4/dev-ioctl.c
@@ -308,7 +308,8 @@ static int autofs_dev_ioctl_open_mountpoint(const char *path, dev_t devid)
goto out;
}
- filp = dentry_open(nd.path.dentry, nd.path.mnt, O_RDONLY);
+ filp = dentry_open(nd.path.dentry, nd.path.mnt, O_RDONLY,
+ current_cred());
if (IS_ERR(filp)) {
err = PTR_ERR(filp);
goto out;
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index c7e65bb30ba..7b19802cfef 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -235,8 +235,8 @@ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid,
substring_t args[MAX_OPT_ARGS];
int option;
- *uid = current->uid;
- *gid = current->gid;
+ *uid = current_uid();
+ *gid = current_gid();
*pgrp = task_pgrp_nr(current);
*minproto = AUTOFS_MIN_PROTO_VERSION;
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index 4b67c2a2d77..e02cc8ae5eb 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -391,8 +391,8 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
memcpy(&wq->name, &qstr, sizeof(struct qstr));
wq->dev = autofs4_get_dev(sbi);
wq->ino = autofs4_get_ino(sbi);
- wq->uid = current->uid;
- wq->gid = current->gid;
+ wq->uid = current_uid();
+ wq->gid = current_gid();
wq->pid = current->pid;
wq->tgid = current->tgid;
wq->status = -EINTR; /* Status return if interrupted */
diff --git a/fs/bad_inode.c b/fs/bad_inode.c
index 5f1538c03b1..a05287a23f6 100644
--- a/fs/bad_inode.c
+++ b/fs/bad_inode.c
@@ -132,11 +132,6 @@ static int bad_file_check_flags(int flags)
return -EIO;
}
-static int bad_file_dir_notify(struct file *file, unsigned long arg)
-{
- return -EIO;
-}
-
static int bad_file_flock(struct file *filp, int cmd, struct file_lock *fl)
{
return -EIO;
@@ -179,7 +174,6 @@ static const struct file_operations bad_file_ops =
.sendpage = bad_file_sendpage,
.get_unmapped_area = bad_file_get_unmapped_area,
.check_flags = bad_file_check_flags,
- .dir_notify = bad_file_dir_notify,
.flock = bad_file_flock,
.splice_write = bad_file_splice_write,
.splice_read = bad_file_splice_read,
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index b6dfee37c7b..d06cb023ad0 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -378,7 +378,8 @@ static struct inode *befs_iget(struct super_block *sb, unsigned long ino)
inode->i_size = 0;
inode->i_blocks = befs_sb->block_size / VFS_BLOCK_SIZE;
strncpy(befs_ino->i_data.symlink, raw_inode->data.symlink,
- BEFS_SYMLINK_LEN);
+ BEFS_SYMLINK_LEN - 1);
+ befs_ino->i_data.symlink[BEFS_SYMLINK_LEN - 1] = '\0';
} else {
int num_blks;
@@ -477,6 +478,8 @@ befs_follow_link(struct dentry *dentry, struct nameidata *nd)
kfree(link);
befs_error(sb, "Failed to read entire long symlink");
link = ERR_PTR(-EIO);
+ } else {
+ link[len - 1] = '\0';
}
} else {
link = befs_ino->i_data.symlink;
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
index daae463068e..4dd1b623f93 100644
--- a/fs/bfs/dir.c
+++ b/fs/bfs/dir.c
@@ -106,8 +106,8 @@ static int bfs_create(struct inode *dir, struct dentry *dentry, int mode,
}
set_bit(ino, info->si_imap);
info->si_freei--;
- inode->i_uid = current->fsuid;
- inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current_fsgid();
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
inode->i_blocks = 0;
inode->i_op = &bfs_file_inops;
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index 204cfd1d767..f1f3f4192a6 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -320,7 +320,7 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
current->mm->free_area_cache = current->mm->mmap_base;
current->mm->cached_hole_size = 0;
- compute_creds(bprm);
+ install_exec_creds(bprm);
current->flags &= ~PF_FORKNOEXEC;
#ifdef __sparc__
if (N_MAGIC(ex) == NMAGIC) {
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 8fcfa398d35..c41fa2af767 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -157,7 +157,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
int items;
elf_addr_t *elf_info;
int ei_index = 0;
- struct task_struct *tsk = current;
+ const struct cred *cred = current_cred();
struct vm_area_struct *vma;
/*
@@ -223,10 +223,10 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
NEW_AUX_ENT(AT_BASE, interp_load_addr);
NEW_AUX_ENT(AT_FLAGS, 0);
NEW_AUX_ENT(AT_ENTRY, exec->e_entry);
- NEW_AUX_ENT(AT_UID, tsk->uid);
- NEW_AUX_ENT(AT_EUID, tsk->euid);
- NEW_AUX_ENT(AT_GID, tsk->gid);
- NEW_AUX_ENT(AT_EGID, tsk->egid);
+ NEW_AUX_ENT(AT_UID, cred->uid);
+ NEW_AUX_ENT(AT_EUID, cred->euid);
+ NEW_AUX_ENT(AT_GID, cred->gid);
+ NEW_AUX_ENT(AT_EGID, cred->egid);
NEW_AUX_ENT(AT_SECURE, security_bprm_secureexec(bprm));
NEW_AUX_ENT(AT_EXECFN, bprm->exec);
if (k_platform) {
@@ -949,14 +949,14 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
set_binfmt(&elf_format);
#ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES
- retval = arch_setup_additional_pages(bprm, executable_stack);
+ retval = arch_setup_additional_pages(bprm, !!elf_interpreter);
if (retval < 0) {
send_sig(SIGKILL, current, 0);
goto out;
}
#endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */
- compute_creds(bprm);
+ install_exec_creds(bprm);
current->flags &= ~PF_FORKNOEXEC;
retval = create_elf_tables(bprm, &loc->elf_ex,
load_addr, interp_load_addr);
@@ -1361,6 +1361,7 @@ static void fill_prstatus(struct elf_prstatus *prstatus,
static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
struct mm_struct *mm)
{
+ const struct cred *cred;
unsigned int i, len;
/* first copy the parameters from user space */
@@ -1388,8 +1389,11 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
psinfo->pr_zomb = psinfo->pr_sname == 'Z';
psinfo->pr_nice = task_nice(p);
psinfo->pr_flag = p->flags;
- SET_UID(psinfo->pr_uid, p->uid);
- SET_GID(psinfo->pr_gid, p->gid);
+ rcu_read_lock();
+ cred = __task_cred(p);
+ SET_UID(psinfo->pr_uid, cred->uid);
+ SET_GID(psinfo->pr_gid, cred->gid);
+ rcu_read_unlock();
strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname));
return 0;
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index 5b5424cb339..aa5b43205e3 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -404,7 +404,7 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm,
current->mm->start_stack = current->mm->start_brk + stack_size;
#endif
- compute_creds(bprm);
+ install_exec_creds(bprm);
current->flags &= ~PF_FORKNOEXEC;
if (create_elf_fdpic_tables(bprm, current->mm,
&exec_params, &interp_params) < 0)
@@ -475,6 +475,7 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
struct elf_fdpic_params *exec_params,
struct elf_fdpic_params *interp_params)
{
+ const struct cred *cred = current_cred();
unsigned long sp, csp, nitems;
elf_caddr_t __user *argv, *envp;
size_t platform_len = 0, len;
@@ -623,10 +624,10 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
NEW_AUX_ENT(AT_BASE, interp_params->elfhdr_addr);
NEW_AUX_ENT(AT_FLAGS, 0);
NEW_AUX_ENT(AT_ENTRY, exec_params->entry_addr);
- NEW_AUX_ENT(AT_UID, (elf_addr_t) current->uid);
- NEW_AUX_ENT(AT_EUID, (elf_addr_t) current->euid);
- NEW_AUX_ENT(AT_GID, (elf_addr_t) current->gid);
- NEW_AUX_ENT(AT_EGID, (elf_addr_t) current->egid);
+ NEW_AUX_ENT(AT_UID, (elf_addr_t) cred->uid);
+ NEW_AUX_ENT(AT_EUID, (elf_addr_t) cred->euid);
+ NEW_AUX_ENT(AT_GID, (elf_addr_t) cred->gid);
+ NEW_AUX_ENT(AT_EGID, (elf_addr_t) cred->egid);
NEW_AUX_ENT(AT_SECURE, security_bprm_secureexec(bprm));
NEW_AUX_ENT(AT_EXECFN, bprm->exec);
@@ -1413,6 +1414,7 @@ static void fill_prstatus(struct elf_prstatus *prstatus,
static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
struct mm_struct *mm)
{
+ const struct cred *cred;
unsigned int i, len;
/* first copy the parameters from user space */
@@ -1440,8 +1442,11 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
psinfo->pr_zomb = psinfo->pr_sname == 'Z';
psinfo->pr_nice = task_nice(p);
psinfo->pr_flag = p->flags;
- SET_UID(psinfo->pr_uid, p->uid);
- SET_GID(psinfo->pr_gid, p->gid);
+ rcu_read_lock();
+ cred = __task_cred(p);
+ SET_UID(psinfo->pr_uid, cred->uid);
+ SET_GID(psinfo->pr_gid, cred->gid);
+ rcu_read_unlock();
strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname));
return 0;
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c
index ccb781a6a80..7bbd5c6b372 100644
--- a/fs/binfmt_flat.c
+++ b/fs/binfmt_flat.c
@@ -880,7 +880,7 @@ static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs)
(libinfo.lib_list[j].loaded)?
libinfo.lib_list[j].start_data:UNLOADED_LIB;
- compute_creds(bprm);
+ install_exec_creds(bprm);
current->flags &= ~PF_FORKNOEXEC;
set_binfmt(&flat_format);
diff --git a/fs/binfmt_som.c b/fs/binfmt_som.c
index 74e587a5279..08644a61616 100644
--- a/fs/binfmt_som.c
+++ b/fs/binfmt_som.c
@@ -255,7 +255,7 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
kfree(hpuxhdr);
set_binfmt(&som_format);
- compute_creds(bprm);
+ install_exec_creds(bprm);
setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT);
create_som_tables(bprm);
diff --git a/fs/bio-integrity.c b/fs/bio-integrity.c
index 19caf7c962a..77ebc3c263d 100644
--- a/fs/bio-integrity.c
+++ b/fs/bio-integrity.c
@@ -111,7 +111,7 @@ void bio_integrity_free(struct bio *bio, struct bio_set *bs)
&& bip->bip_buf != NULL)
kfree(bip->bip_buf);
- mempool_free(bip->bip_vec, bs->bvec_pools[bip->bip_pool]);
+ bvec_free_bs(bs, bip->bip_vec, bip->bip_pool);
mempool_free(bip, bs->bio_integrity_pool);
bio->bi_integrity = NULL;
diff --git a/fs/bio.c b/fs/bio.c
index 77a55bcceed..711cee10360 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -26,9 +26,16 @@
#include <linux/mempool.h>
#include <linux/workqueue.h>
#include <linux/blktrace_api.h>
+#include <trace/block.h>
#include <scsi/sg.h> /* for struct sg_iovec */
-static struct kmem_cache *bio_slab __read_mostly;
+DEFINE_TRACE(block_split);
+
+/*
+ * Test patch to inline a certain number of bi_io_vec's inside the bio
+ * itself, to shrink a bio data allocation from two mempool calls to one
+ */
+#define BIO_INLINE_VECS 4
static mempool_t *bio_split_pool __read_mostly;
@@ -37,9 +44,8 @@ static mempool_t *bio_split_pool __read_mostly;
* break badly! cannot be bigger than what you can fit into an
* unsigned short
*/
-
#define BV(x) { .nr_vecs = x, .name = "biovec-"__stringify(x) }
-static struct biovec_slab bvec_slabs[BIOVEC_NR_POOLS] __read_mostly = {
+struct biovec_slab bvec_slabs[BIOVEC_NR_POOLS] __read_mostly = {
BV(1), BV(4), BV(16), BV(64), BV(128), BV(BIO_MAX_PAGES),
};
#undef BV
@@ -50,12 +56,121 @@ static struct biovec_slab bvec_slabs[BIOVEC_NR_POOLS] __read_mostly = {
*/
struct bio_set *fs_bio_set;
+/*
+ * Our slab pool management
+ */
+struct bio_slab {
+ struct kmem_cache *slab;
+ unsigned int slab_ref;
+ unsigned int slab_size;
+ char name[8];
+};
+static DEFINE_MUTEX(bio_slab_lock);
+static struct bio_slab *bio_slabs;
+static unsigned int bio_slab_nr, bio_slab_max;
+
+static struct kmem_cache *bio_find_or_create_slab(unsigned int extra_size)
+{
+ unsigned int sz = sizeof(struct bio) + extra_size;
+ struct kmem_cache *slab = NULL;
+ struct bio_slab *bslab;
+ unsigned int i, entry = -1;
+
+ mutex_lock(&bio_slab_lock);
+
+ i = 0;
+ while (i < bio_slab_nr) {
+ struct bio_slab *bslab = &bio_slabs[i];
+
+ if (!bslab->slab && entry == -1)
+ entry = i;
+ else if (bslab->slab_size == sz) {
+ slab = bslab->slab;
+ bslab->slab_ref++;
+ break;
+ }
+ i++;
+ }
+
+ if (slab)
+ goto out_unlock;
+
+ if (bio_slab_nr == bio_slab_max && entry == -1) {
+ bio_slab_max <<= 1;
+ bio_slabs = krealloc(bio_slabs,
+ bio_slab_max * sizeof(struct bio_slab),
+ GFP_KERNEL);
+ if (!bio_slabs)
+ goto out_unlock;
+ }
+ if (entry == -1)
+ entry = bio_slab_nr++;
+
+ bslab = &bio_slabs[entry];
+
+ snprintf(bslab->name, sizeof(bslab->name), "bio-%d", entry);
+ slab = kmem_cache_create(bslab->name, sz, 0, SLAB_HWCACHE_ALIGN, NULL);
+ if (!slab)
+ goto out_unlock;
+
+ printk("bio: create slab <%s> at %d\n", bslab->name, entry);
+ bslab->slab = slab;
+ bslab->slab_ref = 1;
+ bslab->slab_size = sz;
+out_unlock:
+ mutex_unlock(&bio_slab_lock);
+ return slab;
+}
+
+static void bio_put_slab(struct bio_set *bs)
+{
+ struct bio_slab *bslab = NULL;
+ unsigned int i;
+
+ mutex_lock(&bio_slab_lock);
+
+ for (i = 0; i < bio_slab_nr; i++) {
+ if (bs->bio_slab == bio_slabs[i].slab) {
+ bslab = &bio_slabs[i];
+ break;
+ }
+ }
+
+ if (WARN(!bslab, KERN_ERR "bio: unable to find slab!\n"))
+ goto out;
+
+ WARN_ON(!bslab->slab_ref);
+
+ if (--bslab->slab_ref)
+ goto out;
+
+ kmem_cache_destroy(bslab->slab);
+ bslab->slab = NULL;
+
+out:
+ mutex_unlock(&bio_slab_lock);
+}
+
unsigned int bvec_nr_vecs(unsigned short idx)
{
return bvec_slabs[idx].nr_vecs;
}
-struct bio_vec *bvec_alloc_bs(gfp_t gfp_mask, int nr, unsigned long *idx, struct bio_set *bs)
+void bvec_free_bs(struct bio_set *bs, struct bio_vec *bv, unsigned int idx)
+{
+ BIO_BUG_ON(idx >= BIOVEC_NR_POOLS);
+
+ if (idx == BIOVEC_MAX_IDX)
+ mempool_free(bv, bs->bvec_pool);
+ else {
+ struct biovec_slab *bvs = bvec_slabs + idx;
+
+ kmem_cache_free(bvs->slab, bv);
+ }
+}
+
+struct bio_vec *bvec_alloc_bs(gfp_t gfp_mask, int nr, unsigned long *idx,
+ struct bio_set *bs)
{
struct bio_vec *bvl;
@@ -64,60 +179,85 @@ struct bio_vec *bvec_alloc_bs(gfp_t gfp_mask, int nr, unsigned long *idx, struct
* If not, this is a bio_kmalloc() allocation and just do a
* kzalloc() for the exact number of vecs right away.
*/
- if (bs) {
+ if (!bs)
+ bvl = kmalloc(nr * sizeof(struct bio_vec), gfp_mask);
+
+ /*
+ * see comment near bvec_array define!
+ */
+ switch (nr) {
+ case 1:
+ *idx = 0;
+ break;
+ case 2 ... 4:
+ *idx = 1;
+ break;
+ case 5 ... 16:
+ *idx = 2;
+ break;
+ case 17 ... 64:
+ *idx = 3;
+ break;
+ case 65 ... 128:
+ *idx = 4;
+ break;
+ case 129 ... BIO_MAX_PAGES:
+ *idx = 5;
+ break;
+ default:
+ return NULL;
+ }
+
+ /*
+ * idx now points to the pool we want to allocate from. only the
+ * 1-vec entry pool is mempool backed.
+ */
+ if (*idx == BIOVEC_MAX_IDX) {
+fallback:
+ bvl = mempool_alloc(bs->bvec_pool, gfp_mask);
+ } else {
+ struct biovec_slab *bvs = bvec_slabs + *idx;
+ gfp_t __gfp_mask = gfp_mask & ~(__GFP_WAIT | __GFP_IO);
+
/*
- * see comment near bvec_array define!
+ * Make this allocation restricted and don't dump info on
+ * allocation failures, since we'll fallback to the mempool
+ * in case of failure.
*/
- switch (nr) {
- case 1:
- *idx = 0;
- break;
- case 2 ... 4:
- *idx = 1;
- break;
- case 5 ... 16:
- *idx = 2;
- break;
- case 17 ... 64:
- *idx = 3;
- break;
- case 65 ... 128:
- *idx = 4;
- break;
- case 129 ... BIO_MAX_PAGES:
- *idx = 5;
- break;
- default:
- return NULL;
- }
+ __gfp_mask |= __GFP_NOMEMALLOC | __GFP_NORETRY | __GFP_NOWARN;
/*
- * idx now points to the pool we want to allocate from
+ * Try a slab allocation. If this fails and __GFP_WAIT
+ * is set, retry with the 1-entry mempool
*/
- bvl = mempool_alloc(bs->bvec_pools[*idx], gfp_mask);
- if (bvl)
- memset(bvl, 0,
- bvec_nr_vecs(*idx) * sizeof(struct bio_vec));
- } else
- bvl = kzalloc(nr * sizeof(struct bio_vec), gfp_mask);
+ bvl = kmem_cache_alloc(bvs->slab, __gfp_mask);
+ if (unlikely(!bvl && (gfp_mask & __GFP_WAIT))) {
+ *idx = BIOVEC_MAX_IDX;
+ goto fallback;
+ }
+ }
return bvl;
}
-void bio_free(struct bio *bio, struct bio_set *bio_set)
+void bio_free(struct bio *bio, struct bio_set *bs)
{
- if (bio->bi_io_vec) {
- const int pool_idx = BIO_POOL_IDX(bio);
+ void *p;
- BIO_BUG_ON(pool_idx >= BIOVEC_NR_POOLS);
-
- mempool_free(bio->bi_io_vec, bio_set->bvec_pools[pool_idx]);
- }
+ if (bio_has_allocated_vec(bio))
+ bvec_free_bs(bs, bio->bi_io_vec, BIO_POOL_IDX(bio));
if (bio_integrity(bio))
- bio_integrity_free(bio, bio_set);
+ bio_integrity_free(bio, bs);
+
+ /*
+ * If we have front padding, adjust the bio pointer before freeing
+ */
+ p = bio;
+ if (bs->front_pad)
+ p -= bs->front_pad;
- mempool_free(bio, bio_set->bio_pool);
+ mempool_free(p, bs->bio_pool);
}
/*
@@ -130,7 +270,8 @@ static void bio_fs_destructor(struct bio *bio)
static void bio_kmalloc_destructor(struct bio *bio)
{
- kfree(bio->bi_io_vec);
+ if (bio_has_allocated_vec(bio))
+ kfree(bio->bi_io_vec);
kfree(bio);
}
@@ -154,16 +295,20 @@ void bio_init(struct bio *bio)
* for a &struct bio to become free. If a %NULL @bs is passed in, we will
* fall back to just using @kmalloc to allocate the required memory.
*
- * allocate bio and iovecs from the memory pools specified by the
- * bio_set structure, or @kmalloc if none given.
+ * Note that the caller must set ->bi_destructor on succesful return
+ * of a bio, to do the appropriate freeing of the bio once the reference
+ * count drops to zero.
**/
struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
{
- struct bio *bio;
+ struct bio *bio = NULL;
+
+ if (bs) {
+ void *p = mempool_alloc(bs->bio_pool, gfp_mask);
- if (bs)
- bio = mempool_alloc(bs->bio_pool, gfp_mask);
- else
+ if (p)
+ bio = p + bs->front_pad;
+ } else
bio = kmalloc(sizeof(*bio), gfp_mask);
if (likely(bio)) {
@@ -173,7 +318,15 @@ struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
if (likely(nr_iovecs)) {
unsigned long uninitialized_var(idx);
- bvl = bvec_alloc_bs(gfp_mask, nr_iovecs, &idx, bs);
+ if (nr_iovecs <= BIO_INLINE_VECS) {
+ idx = 0;
+ bvl = bio->bi_inline_vecs;
+ nr_iovecs = BIO_INLINE_VECS;
+ } else {
+ bvl = bvec_alloc_bs(gfp_mask, nr_iovecs, &idx,
+ bs);
+ nr_iovecs = bvec_nr_vecs(idx);
+ }
if (unlikely(!bvl)) {
if (bs)
mempool_free(bio, bs->bio_pool);
@@ -183,7 +336,7 @@ struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
goto out;
}
bio->bi_flags |= idx << BIO_POOL_OFFSET;
- bio->bi_max_vecs = bvec_nr_vecs(idx);
+ bio->bi_max_vecs = nr_iovecs;
}
bio->bi_io_vec = bvl;
}
@@ -1263,7 +1416,7 @@ struct bio_pair *bio_split(struct bio *bi, int first_sectors)
if (!bp)
return bp;
- blk_add_trace_pdu_int(bdev_get_queue(bi->bi_bdev), BLK_TA_SPLIT, bi,
+ trace_block_split(bdev_get_queue(bi->bi_bdev), bi,
bi->bi_sector + first_sectors);
BUG_ON(bi->bi_vcnt != 1);
@@ -1343,30 +1496,18 @@ EXPORT_SYMBOL(bio_sector_offset);
*/
static int biovec_create_pools(struct bio_set *bs, int pool_entries)
{
- int i;
+ struct biovec_slab *bp = bvec_slabs + BIOVEC_MAX_IDX;
- for (i = 0; i < BIOVEC_NR_POOLS; i++) {
- struct biovec_slab *bp = bvec_slabs + i;
- mempool_t **bvp = bs->bvec_pools + i;
+ bs->bvec_pool = mempool_create_slab_pool(pool_entries, bp->slab);
+ if (!bs->bvec_pool)
+ return -ENOMEM;
- *bvp = mempool_create_slab_pool(pool_entries, bp->slab);
- if (!*bvp)
- return -ENOMEM;
- }
return 0;
}
static void biovec_free_pools(struct bio_set *bs)
{
- int i;
-
- for (i = 0; i < BIOVEC_NR_POOLS; i++) {
- mempool_t *bvp = bs->bvec_pools[i];
-
- if (bvp)
- mempool_destroy(bvp);
- }
-
+ mempool_destroy(bs->bvec_pool);
}
void bioset_free(struct bio_set *bs)
@@ -1376,25 +1517,49 @@ void bioset_free(struct bio_set *bs)
bioset_integrity_free(bs);
biovec_free_pools(bs);
+ bio_put_slab(bs);
kfree(bs);
}
-struct bio_set *bioset_create(int bio_pool_size, int bvec_pool_size)
+/**
+ * bioset_create - Create a bio_set
+ * @pool_size: Number of bio and bio_vecs to cache in the mempool
+ * @front_pad: Number of bytes to allocate in front of the returned bio
+ *
+ * Description:
+ * Set up a bio_set to be used with @bio_alloc_bioset. Allows the caller
+ * to ask for a number of bytes to be allocated in front of the bio.
+ * Front pad allocation is useful for embedding the bio inside
+ * another structure, to avoid allocating extra data to go with the bio.
+ * Note that the bio must be embedded at the END of that structure always,
+ * or things will break badly.
+ */
+struct bio_set *bioset_create(unsigned int pool_size, unsigned int front_pad)
{
- struct bio_set *bs = kzalloc(sizeof(*bs), GFP_KERNEL);
+ unsigned int back_pad = BIO_INLINE_VECS * sizeof(struct bio_vec);
+ struct bio_set *bs;
+ bs = kzalloc(sizeof(*bs), GFP_KERNEL);
if (!bs)
return NULL;
- bs->bio_pool = mempool_create_slab_pool(bio_pool_size, bio_slab);
+ bs->front_pad = front_pad;
+
+ bs->bio_slab = bio_find_or_create_slab(front_pad + back_pad);
+ if (!bs->bio_slab) {
+ kfree(bs);
+ return NULL;
+ }
+
+ bs->bio_pool = mempool_create_slab_pool(pool_size, bs->bio_slab);
if (!bs->bio_pool)
goto bad;
- if (bioset_integrity_create(bs, bio_pool_size))
+ if (bioset_integrity_create(bs, pool_size))
goto bad;
- if (!biovec_create_pools(bs, bvec_pool_size))
+ if (!biovec_create_pools(bs, pool_size))
return bs;
bad:
@@ -1418,12 +1583,16 @@ static void __init biovec_init_slabs(void)
static int __init init_bio(void)
{
- bio_slab = KMEM_CACHE(bio, SLAB_HWCACHE_ALIGN|SLAB_PANIC);
+ bio_slab_max = 2;
+ bio_slab_nr = 0;
+ bio_slabs = kzalloc(bio_slab_max * sizeof(struct bio_slab), GFP_KERNEL);
+ if (!bio_slabs)
+ panic("bio: can't allocate bios\n");
bio_integrity_init_slab();
biovec_init_slabs();
- fs_bio_set = bioset_create(BIO_POOL_SIZE, 2);
+ fs_bio_set = bioset_create(BIO_POOL_SIZE, 0);
if (!fs_bio_set)
panic("bio: can't allocate bios\n");
diff --git a/fs/block_dev.c b/fs/block_dev.c
index db831efbdbb..349a26c1000 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -326,12 +326,13 @@ static struct file_system_type bd_type = {
.kill_sb = kill_anon_super,
};
-static struct vfsmount *bd_mnt __read_mostly;
-struct super_block *blockdev_superblock;
+struct super_block *blockdev_superblock __read_mostly;
void __init bdev_cache_init(void)
{
int err;
+ struct vfsmount *bd_mnt;
+
bdev_cachep = kmem_cache_create("bdev_cache", sizeof(struct bdev_inode),
0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD|SLAB_PANIC),
@@ -373,7 +374,7 @@ struct block_device *bdget(dev_t dev)
struct block_device *bdev;
struct inode *inode;
- inode = iget5_locked(bd_mnt->mnt_sb, hash(dev),
+ inode = iget5_locked(blockdev_superblock, hash(dev),
bdev_test, bdev_set, &dev);
if (!inode)
@@ -463,7 +464,7 @@ void bd_forget(struct inode *inode)
spin_lock(&bdev_lock);
if (inode->i_bdev) {
- if (inode->i_sb != blockdev_superblock)
+ if (!sb_is_blkdev_sb(inode->i_sb))
bdev = inode->i_bdev;
__bd_forget(inode);
}
@@ -1135,12 +1136,15 @@ static int blkdev_open(struct inode * inode, struct file * filp)
if (res)
return res;
- if (!(filp->f_mode & FMODE_EXCL))
- return 0;
+ if (filp->f_mode & FMODE_EXCL) {
+ res = bd_claim(bdev, filp);
+ if (res)
+ goto out_blkdev_put;
+ }
- if (!(res = bd_claim(bdev, filp)))
- return 0;
+ return 0;
+ out_blkdev_put:
blkdev_put(bdev, filp->f_mode);
return res;
}
@@ -1203,8 +1207,16 @@ static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg)
{
struct block_device *bdev = I_BDEV(file->f_mapping->host);
fmode_t mode = file->f_mode;
+
+ /*
+ * O_NDELAY can be altered using fcntl(.., F_SETFL, ..), so we have
+ * to updated it before every ioctl.
+ */
if (file->f_flags & O_NDELAY)
- mode |= FMODE_NDELAY_NOW;
+ mode |= FMODE_NDELAY;
+ else
+ mode &= ~FMODE_NDELAY;
+
return blkdev_ioctl(bdev, mode, cmd, arg);
}
diff --git a/fs/buffer.c b/fs/buffer.c
index 10179cfa115..776ae091d3b 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -99,10 +99,18 @@ __clear_page_buffers(struct page *page)
page_cache_release(page);
}
+
+static int quiet_error(struct buffer_head *bh)
+{
+ if (!test_bit(BH_Quiet, &bh->b_state) && printk_ratelimit())
+ return 0;
+ return 1;
+}
+
+
static void buffer_io_error(struct buffer_head *bh)
{
char b[BDEVNAME_SIZE];
-
printk(KERN_ERR "Buffer I/O error on device %s, logical block %Lu\n",
bdevname(bh->b_bdev, b),
(unsigned long long)bh->b_blocknr);
@@ -144,7 +152,7 @@ void end_buffer_write_sync(struct buffer_head *bh, int uptodate)
if (uptodate) {
set_buffer_uptodate(bh);
} else {
- if (!buffer_eopnotsupp(bh) && printk_ratelimit()) {
+ if (!buffer_eopnotsupp(bh) && !quiet_error(bh)) {
buffer_io_error(bh);
printk(KERN_WARNING "lost page write due to "
"I/O error on %s\n",
@@ -394,7 +402,7 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
set_buffer_uptodate(bh);
} else {
clear_buffer_uptodate(bh);
- if (printk_ratelimit())
+ if (!quiet_error(bh))
buffer_io_error(bh);
SetPageError(page);
}
@@ -455,7 +463,7 @@ static void end_buffer_async_write(struct buffer_head *bh, int uptodate)
if (uptodate) {
set_buffer_uptodate(bh);
} else {
- if (printk_ratelimit()) {
+ if (!quiet_error(bh)) {
buffer_io_error(bh);
printk(KERN_WARNING "lost page write due to "
"I/O error on %s\n",
@@ -2913,6 +2921,9 @@ static void end_bio_bh_io_sync(struct bio *bio, int err)
set_bit(BH_Eopnotsupp, &bh->b_state);
}
+ if (unlikely (test_bit(BIO_QUIET,&bio->bi_flags)))
+ set_bit(BH_Quiet, &bh->b_state);
+
bh->b_end_io(bh, test_bit(BIO_UPTODATE, &bio->bi_flags));
bio_put(bio);
}
diff --git a/fs/cifs/AUTHORS b/fs/cifs/AUTHORS
index 9c136d7803d..7f7fa3c302a 100644
--- a/fs/cifs/AUTHORS
+++ b/fs/cifs/AUTHORS
@@ -36,7 +36,9 @@ Miklos Szeredi
Kazeon team for various fixes especially for 2.4 version.
Asser Ferno (Change Notify support)
Shaggy (Dave Kleikamp) for inumerable small fs suggestions and some good cleanup
+Gunter Kukkukk (testing and suggestions for support of old servers)
Igor Mammedov (DFS support)
+Jeff Layton (many, many fixes, as well as great work on the cifs Kerberos code)
Test case and Bug Report contributors
-------------------------------------
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index e078b7aea14..080703a15f4 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,3 +1,12 @@
+Version 1.56
+------------
+Add "forcemandatorylock" mount option to allow user to use mandatory
+rather than posix (advisory) byte range locks, even though server would
+support posix byte range locks. Fix query of root inode when prefixpath
+specified and user does not have access to query information about the
+top of the share. Fix problem in 2.6.28 resolving DFS paths to
+Samba servers (worked to Windows).
+
Version 1.55
------------
Various fixes to make delete of open files behavior more predictable
diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile
index 6ba43fb346f..9948c0030e8 100644
--- a/fs/cifs/Makefile
+++ b/fs/cifs/Makefile
@@ -5,7 +5,7 @@ obj-$(CONFIG_CIFS) += cifs.o
cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \
link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o \
- md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o \
+ md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o \
readdir.o ioctl.o sess.o export.o cifsacl.o
cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
diff --git a/fs/cifs/README b/fs/cifs/README
index a439dc1739b..da4515e3be2 100644
--- a/fs/cifs/README
+++ b/fs/cifs/README
@@ -463,9 +463,19 @@ A partial list of the supported mount options follows:
with cifs style mandatory byte range locks (and most
cifs servers do not yet support requesting advisory
byte range locks).
+ forcemandatorylock Even if the server supports posix (advisory) byte range
+ locking, send only mandatory lock requests. For some
+ (presumably rare) applications, originally coded for
+ DOS/Windows, which require Windows style mandatory byte range
+ locking, they may be able to take advantage of this option,
+ forcing the cifs client to only send mandatory locks
+ even if the cifs server would support posix advisory locks.
+ "forcemand" is accepted as a shorter form of this mount
+ option.
nodfs Disable DFS (global name space support) even if the
server claims to support it. This can help work around
- a problem with parsing of DFS paths with Samba 3.0.24 server.
+ a problem with parsing of DFS paths with Samba server
+ versions 3.0.24 and 3.0.25.
remount remount the share (often used to change from ro to rw mounts
or vice versa)
cifsacl Report mode bits (e.g. on stat) based on the Windows ACL for
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c
index e1c18362ba4..85c0a74d034 100644
--- a/fs/cifs/cifs_dfs_ref.c
+++ b/fs/cifs/cifs_dfs_ref.c
@@ -122,7 +122,7 @@ static char *compose_mount_options(const char *sb_mountdata,
char **devname)
{
int rc;
- char *mountdata;
+ char *mountdata = NULL;
int md_len;
char *tkn_e;
char *srvIP = NULL;
@@ -136,10 +136,9 @@ static char *compose_mount_options(const char *sb_mountdata,
*devname = cifs_get_share_name(ref->node_name);
rc = dns_resolve_server_name_to_ip(*devname, &srvIP);
if (rc != 0) {
- cERROR(1, ("%s: Failed to resolve server part of %s to IP",
- __func__, *devname));
- mountdata = ERR_PTR(rc);
- goto compose_mount_options_out;
+ cERROR(1, ("%s: Failed to resolve server part of %s to IP: %d",
+ __func__, *devname, rc));;
+ goto compose_mount_options_err;
}
/* md_len = strlen(...) + 12 for 'sep+prefixpath='
* assuming that we have 'unc=' and 'ip=' in
@@ -149,8 +148,8 @@ static char *compose_mount_options(const char *sb_mountdata,
strlen(ref->node_name) + 12;
mountdata = kzalloc(md_len+1, GFP_KERNEL);
if (mountdata == NULL) {
- mountdata = ERR_PTR(-ENOMEM);
- goto compose_mount_options_out;
+ rc = -ENOMEM;
+ goto compose_mount_options_err;
}
/* copy all options except of unc,ip,prefixpath */
@@ -197,18 +196,32 @@ static char *compose_mount_options(const char *sb_mountdata,
/* find & copy prefixpath */
tkn_e = strchr(ref->node_name + 2, '\\');
- if (tkn_e == NULL) /* invalid unc, missing share name*/
- goto compose_mount_options_out;
+ if (tkn_e == NULL) {
+ /* invalid unc, missing share name*/
+ rc = -EINVAL;
+ goto compose_mount_options_err;
+ }
+ /*
+ * this function gives us a path with a double backslash prefix. We
+ * require a single backslash for DFS. Temporarily increment fullpath
+ * to put it in the proper form and decrement before freeing it.
+ */
fullpath = build_path_from_dentry(dentry);
+ if (!fullpath) {
+ rc = -ENOMEM;
+ goto compose_mount_options_err;
+ }
+ ++fullpath;
tkn_e = strchr(tkn_e + 1, '\\');
- if (tkn_e || strlen(fullpath) - (ref->path_consumed)) {
+ if (tkn_e || (strlen(fullpath) - ref->path_consumed)) {
strncat(mountdata, &sep, 1);
strcat(mountdata, "prefixpath=");
if (tkn_e)
strcat(mountdata, tkn_e + 1);
- strcat(mountdata, fullpath + (ref->path_consumed));
+ strcat(mountdata, fullpath + ref->path_consumed);
}
+ --fullpath;
kfree(fullpath);
/*cFYI(1,("%s: parent mountdata: %s", __func__,sb_mountdata));*/
@@ -217,6 +230,11 @@ static char *compose_mount_options(const char *sb_mountdata,
compose_mount_options_out:
kfree(srvIP);
return mountdata;
+
+compose_mount_options_err:
+ kfree(mountdata);
+ mountdata = ERR_PTR(rc);
+ goto compose_mount_options_out;
}
@@ -309,13 +327,19 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
goto out_err;
}
+ /*
+ * The MSDFS spec states that paths in DFS referral requests and
+ * responses must be prefixed by a single '\' character instead of
+ * the double backslashes usually used in the UNC. This function
+ * gives us the latter, so we must adjust the result.
+ */
full_path = build_path_from_dentry(dentry);
if (full_path == NULL) {
rc = -ENOMEM;
goto out_err;
}
- rc = get_dfs_path(xid, ses , full_path, cifs_sb->local_nls,
+ rc = get_dfs_path(xid, ses , full_path + 1, cifs_sb->local_nls,
&num_referrals, &referrals,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index 877c85409f1..c4c306f7b06 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -19,8 +19,8 @@
#define _CIFS_FS_SB_H
#define CIFS_MOUNT_NO_PERM 1 /* do not do client vfs_perm check */
-#define CIFS_MOUNT_SET_UID 2 /* set current->euid in create etc. */
-#define CIFS_MOUNT_SERVER_INUM 4 /* inode numbers from uniqueid from server */
+#define CIFS_MOUNT_SET_UID 2 /* set current's euid in create etc. */
+#define CIFS_MOUNT_SERVER_INUM 4 /* inode numbers from uniqueid from server */
#define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */
#define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */
#define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */
@@ -30,7 +30,8 @@
#define CIFS_MOUNT_CIFS_ACL 0x200 /* send ACL requests to non-POSIX srv */
#define CIFS_MOUNT_OVERR_UID 0x400 /* override uid returned from server */
#define CIFS_MOUNT_OVERR_GID 0x800 /* override gid returned from server */
-#define CIFS_MOUNT_DYNPERM 0x1000 /* allow in-memory only mode setting */
+#define CIFS_MOUNT_DYNPERM 0x1000 /* allow in-memory only mode setting */
+#define CIFS_MOUNT_NOPOSIXBRL 0x2000 /* mandatory not posix byte range lock */
struct cifs_sb_info {
struct cifsTconInfo *tcon; /* primary mount */
diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c
index 0ab2fb5afef..3fd3a9df043 100644
--- a/fs/cifs/cifs_spnego.c
+++ b/fs/cifs/cifs_spnego.c
@@ -121,11 +121,9 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
/* add the server address */
if (server->addr.sockAddr.sin_family == AF_INET)
- sprintf(dp, "ip4=" NIPQUAD_FMT,
- NIPQUAD(server->addr.sockAddr.sin_addr));
+ sprintf(dp, "ip4=%pI4", &server->addr.sockAddr.sin_addr);
else if (server->addr.sockAddr.sin_family == AF_INET6)
- sprintf(dp, "ip6=" NIP6_SEQFMT,
- NIP6(server->addr.sockAddr6.sin6_addr));
+ sprintf(dp, "ip6=%pi6", &server->addr.sockAddr6.sin6_addr);
else
goto out;
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index bd5f13d3845..d4839cf0cb2 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -37,7 +37,7 @@
extern void mdfour(unsigned char *out, unsigned char *in, int n);
extern void E_md4hash(const unsigned char *passwd, unsigned char *p16);
-extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
+extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8,
unsigned char *p24);
static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu,
@@ -280,25 +280,22 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *ses,
}
#ifdef CONFIG_CIFS_WEAK_PW_HASH
-void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key)
+void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt,
+ char *lnm_session_key)
{
int i;
char password_with_pad[CIFS_ENCPWD_SIZE];
- if (ses->server == NULL)
- return;
-
memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
- if (ses->password)
- strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE);
-
- if ((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0)
- if (extended_security & CIFSSEC_MAY_PLNTXT) {
- memset(lnm_session_key, 0, CIFS_SESS_KEY_SIZE);
- memcpy(lnm_session_key, password_with_pad,
- CIFS_ENCPWD_SIZE);
- return;
- }
+ if (password)
+ strncpy(password_with_pad, password, CIFS_ENCPWD_SIZE);
+
+ if (!encrypt && extended_security & CIFSSEC_MAY_PLNTXT) {
+ memset(lnm_session_key, 0, CIFS_SESS_KEY_SIZE);
+ memcpy(lnm_session_key, password_with_pad,
+ CIFS_ENCPWD_SIZE);
+ return;
+ }
/* calculate old style session key */
/* calling toupper is less broken than repeatedly
@@ -314,7 +311,8 @@ void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key)
for (i = 0; i < CIFS_ENCPWD_SIZE; i++)
password_with_pad[i] = toupper(password_with_pad[i]);
- SMBencrypt(password_with_pad, ses->server->cryptKey, lnm_session_key);
+ SMBencrypt(password_with_pad, cryptkey, lnm_session_key);
+
/* clear password before we return/free memory */
memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
}
diff --git a/fs/cifs/cifsencrypt.h b/fs/cifs/cifsencrypt.h
index 152fa2dcfc6..15d2ec00647 100644
--- a/fs/cifs/cifsencrypt.h
+++ b/fs/cifs/cifsencrypt.h
@@ -26,7 +26,8 @@
extern void mdfour(unsigned char *out, unsigned char *in, int n);
/* smbdes.c */
extern void E_P16(unsigned char *p14, unsigned char *p16);
-extern void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24);
+extern void E_P24(unsigned char *p21, const unsigned char *c8,
+ unsigned char *p24);
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index d9cf467309e..13ea53251dc 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -66,7 +66,9 @@ unsigned int sign_CIFS_PDUs = 1;
extern struct task_struct *oplockThread; /* remove sparse warning */
struct task_struct *oplockThread = NULL;
/* extern struct task_struct * dnotifyThread; remove sparse warning */
+#ifdef CONFIG_CIFS_EXPERIMENTAL
static struct task_struct *dnotifyThread = NULL;
+#endif
static const struct super_operations cifs_super_ops;
unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
module_param(CIFSMaxBufSize, int, 0);
@@ -337,39 +339,58 @@ static int
cifs_show_options(struct seq_file *s, struct vfsmount *m)
{
struct cifs_sb_info *cifs_sb;
+ struct cifsTconInfo *tcon;
+ struct TCP_Server_Info *server;
cifs_sb = CIFS_SB(m->mnt_sb);
if (cifs_sb) {
- if (cifs_sb->tcon) {
-/* BB add prepath to mount options displayed */
+ tcon = cifs_sb->tcon;
+ if (tcon) {
seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName);
- if (cifs_sb->tcon->ses) {
- if (cifs_sb->tcon->ses->userName)
+ if (tcon->ses) {
+ if (tcon->ses->userName)
seq_printf(s, ",username=%s",
- cifs_sb->tcon->ses->userName);
- if (cifs_sb->tcon->ses->domainName)
+ tcon->ses->userName);
+ if (tcon->ses->domainName)
seq_printf(s, ",domain=%s",
- cifs_sb->tcon->ses->domainName);
+ tcon->ses->domainName);
+ server = tcon->ses->server;
+ if (server) {
+ seq_printf(s, ",addr=");
+ switch (server->addr.sockAddr6.
+ sin6_family) {
+ case AF_INET6:
+ seq_printf(s, "%pI6",
+ &server->addr.sockAddr6.sin6_addr);
+ break;
+ case AF_INET:
+ seq_printf(s, "%pI4",
+ &server->addr.sockAddr.sin_addr.s_addr);
+ break;
+ }
+ }
}
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) ||
- !(cifs_sb->tcon->unix_ext))
+ !(tcon->unix_ext))
seq_printf(s, ",uid=%d", cifs_sb->mnt_uid);
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) ||
- !(cifs_sb->tcon->unix_ext))
+ !(tcon->unix_ext))
seq_printf(s, ",gid=%d", cifs_sb->mnt_gid);
- if (!cifs_sb->tcon->unix_ext) {
+ if (!tcon->unix_ext) {
seq_printf(s, ",file_mode=0%o,dir_mode=0%o",
cifs_sb->mnt_file_mode,
cifs_sb->mnt_dir_mode);
}
- if (cifs_sb->tcon->seal)
+ if (tcon->seal)
seq_printf(s, ",seal");
- if (cifs_sb->tcon->nocase)
+ if (tcon->nocase)
seq_printf(s, ",nocase");
- if (cifs_sb->tcon->retry)
+ if (tcon->retry)
seq_printf(s, ",hard");
}
+ if (cifs_sb->prepath)
+ seq_printf(s, ",prepath=%s", cifs_sb->prepath);
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
seq_printf(s, ",posixpaths");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)
@@ -417,9 +438,8 @@ int cifs_xquota_set(struct super_block *sb, int quota_type, qid_t qid,
xid = GetXid();
if (pTcon) {
cFYI(1, ("set type: 0x%x id: %d", quota_type, qid));
- } else {
+ } else
rc = -EIO;
- }
FreeXid(xid);
return rc;
@@ -441,9 +461,8 @@ int cifs_xquota_get(struct super_block *sb, int quota_type, qid_t qid,
xid = GetXid();
if (pTcon) {
cFYI(1, ("set type: 0x%x id: %d", quota_type, qid));
- } else {
+ } else
rc = -EIO;
- }
FreeXid(xid);
return rc;
@@ -464,9 +483,8 @@ int cifs_xstate_set(struct super_block *sb, unsigned int flags, int operation)
xid = GetXid();
if (pTcon) {
cFYI(1, ("flags: 0x%x operation: 0x%x", flags, operation));
- } else {
+ } else
rc = -EIO;
- }
FreeXid(xid);
return rc;
@@ -479,17 +497,16 @@ int cifs_xstate_get(struct super_block *sb, struct fs_quota_stat *qstats)
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifsTconInfo *pTcon;
- if (cifs_sb) {
+ if (cifs_sb)
pTcon = cifs_sb->tcon;
- } else {
+ else
return -EIO;
- }
+
xid = GetXid();
if (pTcon) {
cFYI(1, ("pqstats %p", qstats));
- } else {
+ } else
rc = -EIO;
- }
FreeXid(xid);
return rc;
@@ -730,7 +747,6 @@ const struct file_operations cifs_file_ops = {
#endif /* CONFIG_CIFS_POSIX */
#ifdef CONFIG_CIFS_EXPERIMENTAL
- .dir_notify = cifs_dir_notify,
.setlease = cifs_setlease,
#endif /* CONFIG_CIFS_EXPERIMENTAL */
};
@@ -751,7 +767,6 @@ const struct file_operations cifs_file_direct_ops = {
#endif /* CONFIG_CIFS_POSIX */
.llseek = cifs_llseek,
#ifdef CONFIG_CIFS_EXPERIMENTAL
- .dir_notify = cifs_dir_notify,
.setlease = cifs_setlease,
#endif /* CONFIG_CIFS_EXPERIMENTAL */
};
@@ -772,7 +787,6 @@ const struct file_operations cifs_file_nobrl_ops = {
#endif /* CONFIG_CIFS_POSIX */
#ifdef CONFIG_CIFS_EXPERIMENTAL
- .dir_notify = cifs_dir_notify,
.setlease = cifs_setlease,
#endif /* CONFIG_CIFS_EXPERIMENTAL */
};
@@ -792,7 +806,6 @@ const struct file_operations cifs_file_direct_nobrl_ops = {
#endif /* CONFIG_CIFS_POSIX */
.llseek = cifs_llseek,
#ifdef CONFIG_CIFS_EXPERIMENTAL
- .dir_notify = cifs_dir_notify,
.setlease = cifs_setlease,
#endif /* CONFIG_CIFS_EXPERIMENTAL */
};
@@ -801,9 +814,6 @@ const struct file_operations cifs_dir_ops = {
.readdir = cifs_readdir,
.release = cifs_closedir,
.read = generic_read_dir,
-#ifdef CONFIG_CIFS_EXPERIMENTAL
- .dir_notify = cifs_dir_notify,
-#endif /* CONFIG_CIFS_EXPERIMENTAL */
.unlocked_ioctl = cifs_ioctl,
.llseek = generic_file_llseek,
};
@@ -1029,6 +1039,7 @@ static int cifs_oplock_thread(void *dummyarg)
return 0;
}
+#ifdef CONFIG_CIFS_EXPERIMENTAL
static int cifs_dnotify_thread(void *dummyarg)
{
struct list_head *tmp;
@@ -1054,6 +1065,7 @@ static int cifs_dnotify_thread(void *dummyarg)
return 0;
}
+#endif
static int __init
init_cifs(void)
@@ -1131,16 +1143,20 @@ init_cifs(void)
goto out_unregister_dfs_key_type;
}
+#ifdef CONFIG_CIFS_EXPERIMENTAL
dnotifyThread = kthread_run(cifs_dnotify_thread, NULL, "cifsdnotifyd");
if (IS_ERR(dnotifyThread)) {
rc = PTR_ERR(dnotifyThread);
cERROR(1, ("error %d create dnotify thread", rc));
goto out_stop_oplock_thread;
}
+#endif
return 0;
+#ifdef CONFIG_CIFS_EXPERIMENTAL
out_stop_oplock_thread:
+#endif
kthread_stop(oplockThread);
out_unregister_dfs_key_type:
#ifdef CONFIG_CIFS_DFS_UPCALL
@@ -1179,8 +1195,10 @@ exit_cifs(void)
cifs_destroy_inodecache();
cifs_destroy_mids();
cifs_destroy_request_bufs();
- kthread_stop(oplockThread);
+#ifdef CONFIG_CIFS_EXPERIMENTAL
kthread_stop(dnotifyThread);
+#endif
+ kthread_stop(oplockThread);
}
MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>");
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 074de0b5064..7ac481841f8 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -76,7 +76,6 @@ extern int cifs_file_mmap(struct file * , struct vm_area_struct *);
extern const struct file_operations cifs_dir_ops;
extern int cifs_dir_open(struct inode *inode, struct file *file);
extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir);
-extern int cifs_dir_notify(struct file *, unsigned long arg);
/* Functions related to dir entries */
extern struct dentry_operations cifs_dentry_ops;
@@ -101,5 +100,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
extern const struct export_operations cifs_export_ops;
#endif /* EXPERIMENTAL */
-#define CIFS_VERSION "1.55"
+#define CIFS_VERSION "1.56"
#endif /* _CIFSFS_H */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index c57c0565547..94c1ca0ec95 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -47,7 +47,11 @@
*/
#define CIFS_MAX_REQ 50
-#define SERVER_NAME_LENGTH 15
+#define RFC1001_NAME_LEN 15
+#define RFC1001_NAME_LEN_WITH_NULL (RFC1001_NAME_LEN + 1)
+
+/* currently length of NIP6_FMT */
+#define SERVER_NAME_LENGTH 40
#define SERVER_NAME_LEN_WITH_NULL (SERVER_NAME_LENGTH + 1)
/* used to define string lengths for reversing unicode strings */
@@ -125,8 +129,7 @@ struct TCP_Server_Info {
struct list_head smb_ses_list;
int srv_count; /* reference counter */
/* 15 character server name + 0x20 16th byte indicating type = srv */
- char server_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
- char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2];
+ char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
char *hostname; /* hostname portion of UNC string */
struct socket *ssocket;
union {
@@ -151,7 +154,7 @@ struct TCP_Server_Info {
atomic_t num_waiters; /* blocked waiting to get in sendrecv */
#endif
enum statusEnum tcpStatus; /* what we think the status is */
- struct semaphore tcpSem;
+ struct mutex srv_mutex;
struct task_struct *tsk;
char server_GUID[16];
char secMode;
@@ -171,7 +174,7 @@ struct TCP_Server_Info {
__u16 CurrentMid; /* multiplex id - rotating counter */
char cryptKey[CIFS_CRYPTO_KEY_SIZE];
/* 16th byte of RFC1001 workstation name is always null */
- char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
+ char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
__u32 sequence_number; /* needed for CIFS PDU signature */
struct mac_key mac_signing_key;
char ntlmv2_hash[16];
@@ -239,6 +242,7 @@ struct cifsTconInfo {
struct cifsSesInfo *ses; /* pointer to session associated with */
char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */
char *nativeFileSystem;
+ char *password; /* for share-level security */
__u16 tid; /* The 2 byte tree id */
__u16 Flags; /* optional support bits */
enum statusEnum tidStatus;
@@ -422,7 +426,6 @@ struct mid_q_entry {
unsigned long when_sent; /* time when smb send finished */
unsigned long when_received; /* when demux complete (taken off wire) */
#endif
- struct cifsSesInfo *ses; /* smb was sent to this server */
struct task_struct *tsk; /* task waiting for response */
struct smb_hdr *resp_buf; /* response buffer */
int midState; /* wish this were enum but can not pass to wait_event */
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index d2a073edd1b..b4e2e9f0ee3 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -1922,7 +1922,7 @@ typedef struct smb_com_transaction2_get_dfs_refer_req {
/* DFS server target type */
#define DFS_TYPE_LINK 0x0000 /* also for sysvol targets */
#define DFS_TYPE_ROOT 0x0001
-
+
/* Referral Entry Flags */
#define DFS_NAME_LIST_REF 0x0200
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 6f21ecb85ce..06f6779988b 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -39,7 +39,7 @@ extern int smb_send(struct socket *, struct smb_hdr *,
unsigned int /* length */ , struct sockaddr *, bool);
extern unsigned int _GetXid(void);
extern void _FreeXid(unsigned int);
-#define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__func__, xid,current->fsuid));
+#define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__func__, xid,current_fsuid()));
#define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__func__,curr_xid,(int)rc));}
extern char *build_path_from_dentry(struct dentry *);
extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
@@ -330,7 +330,8 @@ extern void CalcNTLMv2_response(const struct cifsSesInfo *, char *);
extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *,
const struct nls_table *);
#ifdef CONFIG_CIFS_WEAK_PW_HASH
-extern void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key);
+extern void calc_lanman_hash(const char *password, const char *cryptkey,
+ bool encrypt, char *lnm_session_key);
#endif /* CIFS_WEAK_PW_HASH */
extern int CIFSSMBCopy(int xid,
struct cifsTconInfo *source_tcon,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 2af8626ced4..552642a507c 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1382,13 +1382,13 @@ openRetry:
if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
*pOplock |= CIFS_CREATE_ACTION;
if (pfile_info) {
- memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
- 36 /* CreationTime to Attributes */);
- /* the file_info buf is endian converted by caller */
- pfile_info->AllocationSize = pSMBr->AllocationSize;
- pfile_info->EndOfFile = pSMBr->EndOfFile;
- pfile_info->NumberOfLinks = cpu_to_le32(1);
- pfile_info->DeletePending = 0;
+ memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
+ 36 /* CreationTime to Attributes */);
+ /* the file_info buf is endian converted by caller */
+ pfile_info->AllocationSize = pSMBr->AllocationSize;
+ pfile_info->EndOfFile = pSMBr->EndOfFile;
+ pfile_info->NumberOfLinks = cpu_to_le32(1);
+ pfile_info->DeletePending = 0;
}
}
@@ -1414,8 +1414,13 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
if (tcon->ses->capabilities & CAP_LARGE_FILES)
wct = 12;
- else
+ else {
wct = 10; /* old style read */
+ if ((lseek >> 32) > 0) {
+ /* can not handle this big offset for old */
+ return -EIO;
+ }
+ }
*nbytes = 0;
rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
@@ -1431,8 +1436,6 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
if (wct == 12)
pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
- else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
- return -EIO;
pSMB->Remaining = 0;
pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
@@ -1519,8 +1522,13 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
if (tcon->ses->capabilities & CAP_LARGE_FILES)
wct = 14;
- else
+ else {
wct = 12;
+ if ((offset >> 32) > 0) {
+ /* can not handle big offset for old srv */
+ return -EIO;
+ }
+ }
rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
(void **) &pSMBr);
@@ -1535,8 +1543,6 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
if (wct == 14)
pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
- else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
- return -EIO;
pSMB->Reserved = 0xFFFFFFFF;
pSMB->WriteMode = 0;
@@ -1558,7 +1564,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
pSMB->DataOffset =
cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
if (buf)
- memcpy(pSMB->Data, buf, bytes_sent);
+ memcpy(pSMB->Data, buf, bytes_sent);
else if (ubuf) {
if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
cifs_buf_release(pSMB);
@@ -1621,10 +1627,15 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
- if (tcon->ses->capabilities & CAP_LARGE_FILES)
+ if (tcon->ses->capabilities & CAP_LARGE_FILES) {
wct = 14;
- else
+ } else {
wct = 12;
+ if ((offset >> 32) > 0) {
+ /* can not handle big offset for old srv */
+ return -EIO;
+ }
+ }
rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
if (rc)
return rc;
@@ -1637,8 +1648,6 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
if (wct == 14)
pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
- else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
- return -EIO;
pSMB->Reserved = 0xFFFFFFFF;
pSMB->WriteMode = 0;
pSMB->Remaining = 0;
@@ -1862,10 +1871,6 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
rc = -EIO; /* bad smb */
goto plk_err_exit;
}
- if (pLockData == NULL) {
- rc = -EINVAL;
- goto plk_err_exit;
- }
data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
data_count = le16_to_cpu(pSMBr->t2.DataCount);
if (data_count < sizeof(struct cifs_posix_lock)) {
@@ -3983,7 +3988,8 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
node->flags = le16_to_cpu(pSMBr->DFSFlags);
if (is_unicode) {
- __le16 *tmp = kmalloc(strlen(searchName)*2, GFP_KERNEL);
+ __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
+ GFP_KERNEL);
cifsConvertToUCS((__le16 *) tmp, searchName,
PATH_MAX, nls_codepage, remap);
node->path_consumed = hostlen_fromUCS(tmp,
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index c7d34171458..e9ea394ee07 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -89,6 +89,7 @@ struct smb_vol {
bool nullauth:1; /* attempt to authenticate with null user */
bool nocase:1; /* request case insensitive filenames */
bool nobrl:1; /* disable sending byte range locks to srv */
+ bool mand_lock:1; /* send mandatory not posix byte range lock reqs */
bool seal:1; /* request transport encryption on share */
bool nodfs:1; /* Do not request DFS, even if available */
bool local_lease:1; /* check leases only on local system, not remote */
@@ -101,25 +102,17 @@ struct smb_vol {
char *prepath;
};
-static int ipv4_connect(struct sockaddr_in *psin_server,
- struct socket **csocket,
- char *netb_name,
- char *server_netb_name,
- bool noblocksnd,
- bool nosndbuf); /* ipv6 never set sndbuf size */
-static int ipv6_connect(struct sockaddr_in6 *psin_server,
- struct socket **csocket, bool noblocksnd);
-
-
- /*
- * cifs tcp session reconnection
- *
- * mark tcp session as reconnecting so temporarily locked
- * mark all smb sessions as reconnecting for tcp session
- * reconnect tcp session
- * wake up waiters on reconnection? - (not needed currently)
- */
+static int ipv4_connect(struct TCP_Server_Info *server);
+static int ipv6_connect(struct TCP_Server_Info *server);
+/*
+ * cifs tcp session reconnection
+ *
+ * mark tcp session as reconnecting so temporarily locked
+ * mark all smb sessions as reconnecting for tcp session
+ * reconnect tcp session
+ * wake up waiters on reconnection? - (not needed currently)
+ */
static int
cifs_reconnect(struct TCP_Server_Info *server)
{
@@ -156,7 +149,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
}
read_unlock(&cifs_tcp_ses_lock);
/* do not want to be sending data on a socket we are freeing */
- down(&server->tcpSem);
+ mutex_lock(&server->srv_mutex);
if (server->ssocket) {
cFYI(1, ("State: 0x%x Flags: 0x%lx", server->ssocket->state,
server->ssocket->flags));
@@ -182,21 +175,15 @@ cifs_reconnect(struct TCP_Server_Info *server)
}
}
spin_unlock(&GlobalMid_Lock);
- up(&server->tcpSem);
+ mutex_unlock(&server->srv_mutex);
while ((server->tcpStatus != CifsExiting) &&
(server->tcpStatus != CifsGood)) {
try_to_freeze();
- if (server->addr.sockAddr6.sin6_family == AF_INET6) {
- rc = ipv6_connect(&server->addr.sockAddr6,
- &server->ssocket, server->noautotune);
- } else {
- rc = ipv4_connect(&server->addr.sockAddr,
- &server->ssocket,
- server->workstation_RFC1001_name,
- server->server_RFC1001_name,
- server->noblocksnd, server->noautotune);
- }
+ if (server->addr.sockAddr6.sin6_family == AF_INET6)
+ rc = ipv6_connect(server);
+ else
+ rc = ipv4_connect(server);
if (rc) {
cFYI(1, ("reconnect error %d", rc));
msleep(3000);
@@ -776,7 +763,7 @@ multi_t2_fnd:
set_current_state(TASK_RUNNING);
}
- return 0;
+ module_put_and_exit(0);
}
/* extract the host portion of the UNC string */
@@ -836,8 +823,8 @@ cifs_parse_mount_options(char *options, const char *devname,
/* null target name indicates to use *SMBSERVR default called name
if we end up sending RFC1001 session initialize */
vol->target_rfc1001_name[0] = 0;
- vol->linux_uid = current->uid; /* current->euid instead? */
- vol->linux_gid = current->gid;
+ vol->linux_uid = current_uid(); /* use current_euid() instead? */
+ vol->linux_gid = current_gid();
vol->dir_mode = S_IRWXUGO;
/* 2767 perms indicate mandatory locking support */
vol->file_mode = (S_IRWXUGO | S_ISGID) & (~S_IXGRP);
@@ -1260,6 +1247,17 @@ cifs_parse_mount_options(char *options, const char *devname,
if (vol->file_mode ==
(S_IALLUGO & ~(S_ISUID | S_IXGRP)))
vol->file_mode = S_IALLUGO;
+ } else if (strnicmp(data, "forcemandatorylock", 9) == 0) {
+ /* will take the shorter form "forcemand" as well */
+ /* This mount option will force use of mandatory
+ (DOS/Windows style) byte range locks, instead of
+ using posix advisory byte range locks, even if the
+ Unix extensions are available and posix locks would
+ be supported otherwise. If Unix extensions are not
+ negotiated this has no effect since mandatory locks
+ would be used (mandatory locks is all that those
+ those servers support) */
+ vol->mand_lock = 1;
} else if (strnicmp(data, "setuids", 7) == 0) {
vol->setuids = 1;
} else if (strnicmp(data, "nosetuids", 9) == 0) {
@@ -1417,6 +1415,143 @@ cifs_put_tcp_session(struct TCP_Server_Info *server)
force_sig(SIGKILL, task);
}
+static struct TCP_Server_Info *
+cifs_get_tcp_session(struct smb_vol *volume_info)
+{
+ struct TCP_Server_Info *tcp_ses = NULL;
+ struct sockaddr addr;
+ struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr;
+ struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr;
+ int rc;
+
+ memset(&addr, 0, sizeof(struct sockaddr));
+
+ if (volume_info->UNCip && volume_info->UNC) {
+ rc = cifs_inet_pton(AF_INET, volume_info->UNCip,
+ &sin_server->sin_addr.s_addr);
+
+ if (rc <= 0) {
+ /* not ipv4 address, try ipv6 */
+ rc = cifs_inet_pton(AF_INET6, volume_info->UNCip,
+ &sin_server6->sin6_addr.in6_u);
+ if (rc > 0)
+ addr.sa_family = AF_INET6;
+ } else {
+ addr.sa_family = AF_INET;
+ }
+
+ if (rc <= 0) {
+ /* we failed translating address */
+ rc = -EINVAL;
+ goto out_err;
+ }
+
+ cFYI(1, ("UNC: %s ip: %s", volume_info->UNC,
+ volume_info->UNCip));
+ } else if (volume_info->UNCip) {
+ /* BB using ip addr as tcp_ses name to connect to the
+ DFS root below */
+ cERROR(1, ("Connecting to DFS root not implemented yet"));
+ rc = -EINVAL;
+ goto out_err;
+ } else /* which tcp_sess DFS root would we conect to */ {
+ cERROR(1,
+ ("CIFS mount error: No UNC path (e.g. -o "
+ "unc=//192.168.1.100/public) specified"));
+ rc = -EINVAL;
+ goto out_err;
+ }
+
+ /* see if we already have a matching tcp_ses */
+ tcp_ses = cifs_find_tcp_session(&addr);
+ if (tcp_ses)
+ return tcp_ses;
+
+ tcp_ses = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
+ if (!tcp_ses) {
+ rc = -ENOMEM;
+ goto out_err;
+ }
+
+ tcp_ses->hostname = extract_hostname(volume_info->UNC);
+ if (IS_ERR(tcp_ses->hostname)) {
+ rc = PTR_ERR(tcp_ses->hostname);
+ goto out_err;
+ }
+
+ tcp_ses->noblocksnd = volume_info->noblocksnd;
+ tcp_ses->noautotune = volume_info->noautotune;
+ atomic_set(&tcp_ses->inFlight, 0);
+ init_waitqueue_head(&tcp_ses->response_q);
+ init_waitqueue_head(&tcp_ses->request_q);
+ INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
+ mutex_init(&tcp_ses->srv_mutex);
+ memcpy(tcp_ses->workstation_RFC1001_name,
+ volume_info->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
+ memcpy(tcp_ses->server_RFC1001_name,
+ volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
+ tcp_ses->sequence_number = 0;
+ INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
+ INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
+
+ /*
+ * at this point we are the only ones with the pointer
+ * to the struct since the kernel thread not created yet
+ * no need to spinlock this init of tcpStatus or srv_count
+ */
+ tcp_ses->tcpStatus = CifsNew;
+ ++tcp_ses->srv_count;
+
+ if (addr.sa_family == AF_INET6) {
+ cFYI(1, ("attempting ipv6 connect"));
+ /* BB should we allow ipv6 on port 139? */
+ /* other OS never observed in Wild doing 139 with v6 */
+ memcpy(&tcp_ses->addr.sockAddr6, sin_server6,
+ sizeof(struct sockaddr_in6));
+ sin_server6->sin6_port = htons(volume_info->port);
+ rc = ipv6_connect(tcp_ses);
+ } else {
+ memcpy(&tcp_ses->addr.sockAddr, sin_server,
+ sizeof(struct sockaddr_in));
+ sin_server->sin_port = htons(volume_info->port);
+ rc = ipv4_connect(tcp_ses);
+ }
+ if (rc < 0) {
+ cERROR(1, ("Error connecting to socket. Aborting operation"));
+ goto out_err;
+ }
+
+ /*
+ * since we're in a cifs function already, we know that
+ * this will succeed. No need for try_module_get().
+ */
+ __module_get(THIS_MODULE);
+ tcp_ses->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread,
+ tcp_ses, "cifsd");
+ if (IS_ERR(tcp_ses->tsk)) {
+ rc = PTR_ERR(tcp_ses->tsk);
+ cERROR(1, ("error %d create cifsd thread", rc));
+ module_put(THIS_MODULE);
+ goto out_err;
+ }
+
+ /* thread spawned, put it on the list */
+ write_lock(&cifs_tcp_ses_lock);
+ list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
+ write_unlock(&cifs_tcp_ses_lock);
+
+ return tcp_ses;
+
+out_err:
+ if (tcp_ses) {
+ kfree(tcp_ses->hostname);
+ if (tcp_ses->ssocket)
+ sock_release(tcp_ses->ssocket);
+ kfree(tcp_ses);
+ }
+ return ERR_PTR(rc);
+}
+
static struct cifsSesInfo *
cifs_find_smb_ses(struct TCP_Server_Info *server, char *username)
{
@@ -1593,93 +1728,96 @@ static void rfc1002mangle(char *target, char *source, unsigned int length)
static int
-ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
- char *netbios_name, char *target_name,
- bool noblocksnd, bool noautotune)
+ipv4_connect(struct TCP_Server_Info *server)
{
int rc = 0;
- int connected = 0;
+ bool connected = false;
__be16 orig_port = 0;
+ struct socket *socket = server->ssocket;
- if (*csocket == NULL) {
+ if (socket == NULL) {
rc = sock_create_kern(PF_INET, SOCK_STREAM,
- IPPROTO_TCP, csocket);
+ IPPROTO_TCP, &socket);
if (rc < 0) {
cERROR(1, ("Error %d creating socket", rc));
- *csocket = NULL;
return rc;
- } else {
- /* BB other socket options to set KEEPALIVE, NODELAY? */
- cFYI(1, ("Socket created"));
- (*csocket)->sk->sk_allocation = GFP_NOFS;
- cifs_reclassify_socket4(*csocket);
}
+
+ /* BB other socket options to set KEEPALIVE, NODELAY? */
+ cFYI(1, ("Socket created"));
+ server->ssocket = socket;
+ socket->sk->sk_allocation = GFP_NOFS;
+ cifs_reclassify_socket4(socket);
}
- psin_server->sin_family = AF_INET;
- if (psin_server->sin_port) { /* user overrode default port */
- rc = (*csocket)->ops->connect(*csocket,
- (struct sockaddr *) psin_server,
- sizeof(struct sockaddr_in), 0);
+ /* user overrode default port */
+ if (server->addr.sockAddr.sin_port) {
+ rc = socket->ops->connect(socket, (struct sockaddr *)
+ &server->addr.sockAddr,
+ sizeof(struct sockaddr_in), 0);
if (rc >= 0)
- connected = 1;
+ connected = true;
}
if (!connected) {
/* save original port so we can retry user specified port
later if fall back ports fail this time */
- orig_port = psin_server->sin_port;
+ orig_port = server->addr.sockAddr.sin_port;
/* do not retry on the same port we just failed on */
- if (psin_server->sin_port != htons(CIFS_PORT)) {
- psin_server->sin_port = htons(CIFS_PORT);
-
- rc = (*csocket)->ops->connect(*csocket,
- (struct sockaddr *) psin_server,
- sizeof(struct sockaddr_in), 0);
+ if (server->addr.sockAddr.sin_port != htons(CIFS_PORT)) {
+ server->addr.sockAddr.sin_port = htons(CIFS_PORT);
+ rc = socket->ops->connect(socket,
+ (struct sockaddr *)
+ &server->addr.sockAddr,
+ sizeof(struct sockaddr_in), 0);
if (rc >= 0)
- connected = 1;
+ connected = true;
}
}
if (!connected) {
- psin_server->sin_port = htons(RFC1001_PORT);
- rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
- psin_server,
+ server->addr.sockAddr.sin_port = htons(RFC1001_PORT);
+ rc = socket->ops->connect(socket, (struct sockaddr *)
+ &server->addr.sockAddr,
sizeof(struct sockaddr_in), 0);
if (rc >= 0)
- connected = 1;
+ connected = true;
}
/* give up here - unless we want to retry on different
protocol families some day */
if (!connected) {
if (orig_port)
- psin_server->sin_port = orig_port;
+ server->addr.sockAddr.sin_port = orig_port;
cFYI(1, ("Error %d connecting to server via ipv4", rc));
- sock_release(*csocket);
- *csocket = NULL;
+ sock_release(socket);
+ server->ssocket = NULL;
return rc;
}
- /* Eventually check for other socket options to change from
- the default. sock_setsockopt not used because it expects
- user space buffer */
- cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
- (*csocket)->sk->sk_sndbuf,
- (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
- (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
- if (!noblocksnd)
- (*csocket)->sk->sk_sndtimeo = 3 * HZ;
+
+
+ /*
+ * Eventually check for other socket options to change from
+ * the default. sock_setsockopt not used because it expects
+ * user space buffer
+ */
+ socket->sk->sk_rcvtimeo = 7 * HZ;
+ socket->sk->sk_sndtimeo = 3 * HZ;
/* make the bufsizes depend on wsize/rsize and max requests */
- if (noautotune) {
- if ((*csocket)->sk->sk_sndbuf < (200 * 1024))
- (*csocket)->sk->sk_sndbuf = 200 * 1024;
- if ((*csocket)->sk->sk_rcvbuf < (140 * 1024))
- (*csocket)->sk->sk_rcvbuf = 140 * 1024;
+ if (server->noautotune) {
+ if (socket->sk->sk_sndbuf < (200 * 1024))
+ socket->sk->sk_sndbuf = 200 * 1024;
+ if (socket->sk->sk_rcvbuf < (140 * 1024))
+ socket->sk->sk_rcvbuf = 140 * 1024;
}
+ cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
+ socket->sk->sk_sndbuf,
+ socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo));
+
/* send RFC1001 sessinit */
- if (psin_server->sin_port == htons(RFC1001_PORT)) {
+ if (server->addr.sockAddr.sin_port == htons(RFC1001_PORT)) {
/* some servers require RFC1001 sessinit before sending
negprot - BB check reconnection in case where second
sessinit is sent but no second negprot */
@@ -1689,31 +1827,42 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
GFP_KERNEL);
if (ses_init_buf) {
ses_init_buf->trailer.session_req.called_len = 32;
- if (target_name && (target_name[0] != 0)) {
- rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
- target_name, 16);
- } else {
- rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
- DEFAULT_CIFS_CALLED_NAME, 16);
- }
+ if (server->server_RFC1001_name &&
+ server->server_RFC1001_name[0] != 0)
+ rfc1002mangle(ses_init_buf->trailer.
+ session_req.called_name,
+ server->server_RFC1001_name,
+ RFC1001_NAME_LEN_WITH_NULL);
+ else
+ rfc1002mangle(ses_init_buf->trailer.
+ session_req.called_name,
+ DEFAULT_CIFS_CALLED_NAME,
+ RFC1001_NAME_LEN_WITH_NULL);
ses_init_buf->trailer.session_req.calling_len = 32;
+
/* calling name ends in null (byte 16) from old smb
convention. */
- if (netbios_name && (netbios_name[0] != 0)) {
- rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
- netbios_name, 16);
- } else {
- rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
- "LINUX_CIFS_CLNT", 16);
- }
+ if (server->workstation_RFC1001_name &&
+ server->workstation_RFC1001_name[0] != 0)
+ rfc1002mangle(ses_init_buf->trailer.
+ session_req.calling_name,
+ server->workstation_RFC1001_name,
+ RFC1001_NAME_LEN_WITH_NULL);
+ else
+ rfc1002mangle(ses_init_buf->trailer.
+ session_req.calling_name,
+ "LINUX_CIFS_CLNT",
+ RFC1001_NAME_LEN_WITH_NULL);
+
ses_init_buf->trailer.session_req.scope1 = 0;
ses_init_buf->trailer.session_req.scope2 = 0;
smb_buf = (struct smb_hdr *)ses_init_buf;
/* sizeof RFC1002_SESSION_REQUEST with no scope */
smb_buf->smb_buf_length = 0x81000044;
- rc = smb_send(*csocket, smb_buf, 0x44,
- (struct sockaddr *)psin_server, noblocksnd);
+ rc = smb_send(socket, smb_buf, 0x44,
+ (struct sockaddr *) &server->addr.sockAddr,
+ server->noblocksnd);
kfree(ses_init_buf);
msleep(1); /* RFC1001 layer in at least one server
requires very short break before negprot
@@ -1733,79 +1882,81 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
}
static int
-ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket,
- bool noblocksnd)
+ipv6_connect(struct TCP_Server_Info *server)
{
int rc = 0;
- int connected = 0;
+ bool connected = false;
__be16 orig_port = 0;
+ struct socket *socket = server->ssocket;
- if (*csocket == NULL) {
+ if (socket == NULL) {
rc = sock_create_kern(PF_INET6, SOCK_STREAM,
- IPPROTO_TCP, csocket);
+ IPPROTO_TCP, &socket);
if (rc < 0) {
cERROR(1, ("Error %d creating ipv6 socket", rc));
- *csocket = NULL;
+ socket = NULL;
return rc;
- } else {
- /* BB other socket options to set KEEPALIVE, NODELAY? */
- cFYI(1, ("ipv6 Socket created"));
- (*csocket)->sk->sk_allocation = GFP_NOFS;
- cifs_reclassify_socket6(*csocket);
}
- }
- psin_server->sin6_family = AF_INET6;
+ /* BB other socket options to set KEEPALIVE, NODELAY? */
+ cFYI(1, ("ipv6 Socket created"));
+ server->ssocket = socket;
+ socket->sk->sk_allocation = GFP_NOFS;
+ cifs_reclassify_socket6(socket);
+ }
- if (psin_server->sin6_port) { /* user overrode default port */
- rc = (*csocket)->ops->connect(*csocket,
- (struct sockaddr *) psin_server,
+ /* user overrode default port */
+ if (server->addr.sockAddr6.sin6_port) {
+ rc = socket->ops->connect(socket,
+ (struct sockaddr *) &server->addr.sockAddr6,
sizeof(struct sockaddr_in6), 0);
if (rc >= 0)
- connected = 1;
+ connected = true;
}
if (!connected) {
/* save original port so we can retry user specified port
later if fall back ports fail this time */
- orig_port = psin_server->sin6_port;
+ orig_port = server->addr.sockAddr6.sin6_port;
/* do not retry on the same port we just failed on */
- if (psin_server->sin6_port != htons(CIFS_PORT)) {
- psin_server->sin6_port = htons(CIFS_PORT);
-
- rc = (*csocket)->ops->connect(*csocket,
- (struct sockaddr *) psin_server,
+ if (server->addr.sockAddr6.sin6_port != htons(CIFS_PORT)) {
+ server->addr.sockAddr6.sin6_port = htons(CIFS_PORT);
+ rc = socket->ops->connect(socket, (struct sockaddr *)
+ &server->addr.sockAddr6,
sizeof(struct sockaddr_in6), 0);
if (rc >= 0)
- connected = 1;
+ connected = true;
}
}
if (!connected) {
- psin_server->sin6_port = htons(RFC1001_PORT);
- rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
- psin_server, sizeof(struct sockaddr_in6), 0);
+ server->addr.sockAddr6.sin6_port = htons(RFC1001_PORT);
+ rc = socket->ops->connect(socket, (struct sockaddr *)
+ &server->addr.sockAddr6,
+ sizeof(struct sockaddr_in6), 0);
if (rc >= 0)
- connected = 1;
+ connected = true;
}
/* give up here - unless we want to retry on different
protocol families some day */
if (!connected) {
if (orig_port)
- psin_server->sin6_port = orig_port;
+ server->addr.sockAddr6.sin6_port = orig_port;
cFYI(1, ("Error %d connecting to server via ipv6", rc));
- sock_release(*csocket);
- *csocket = NULL;
+ sock_release(socket);
+ server->ssocket = NULL;
return rc;
}
- /* Eventually check for other socket options to change from
- the default. sock_setsockopt not used because it expects
- user space buffer */
- (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
- if (!noblocksnd)
- (*csocket)->sk->sk_sndtimeo = 3 * HZ;
+ /*
+ * Eventually check for other socket options to change from
+ * the default. sock_setsockopt not used because it expects
+ * user space buffer
+ */
+ socket->sk->sk_rcvtimeo = 7 * HZ;
+ socket->sk->sk_sndtimeo = 3 * HZ;
+ server->ssocket = socket;
return rc;
}
@@ -2011,6 +2162,8 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info,
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
if (pvolume_info->nobrl)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
+ if (pvolume_info->mand_lock)
+ cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL;
if (pvolume_info->cifs_acl)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
if (pvolume_info->override_uid)
@@ -2035,32 +2188,30 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
{
int rc = 0;
int xid;
- struct socket *csocket = NULL;
- struct sockaddr addr;
- struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr;
- struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr;
- struct smb_vol volume_info;
+ struct smb_vol *volume_info;
struct cifsSesInfo *pSesInfo = NULL;
struct cifsTconInfo *tcon = NULL;
struct TCP_Server_Info *srvTcp = NULL;
xid = GetXid();
-/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
+ volume_info = kzalloc(sizeof(struct smb_vol), GFP_KERNEL);
+ if (!volume_info) {
+ rc = -ENOMEM;
+ goto out;
+ }
- memset(&addr, 0, sizeof(struct sockaddr));
- memset(&volume_info, 0, sizeof(struct smb_vol));
- if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
+ if (cifs_parse_mount_options(mount_data, devname, volume_info)) {
rc = -EINVAL;
goto out;
}
- if (volume_info.nullauth) {
+ if (volume_info->nullauth) {
cFYI(1, ("null user"));
- volume_info.username = "";
- } else if (volume_info.username) {
+ volume_info->username = "";
+ } else if (volume_info->username) {
/* BB fixme parse for domain name here */
- cFYI(1, ("Username: %s", volume_info.username));
+ cFYI(1, ("Username: %s", volume_info->username));
} else {
cifserror("No username specified");
/* In userspace mount helper we can get user name from alternate
@@ -2069,139 +2220,29 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
goto out;
}
- if (volume_info.UNCip && volume_info.UNC) {
- rc = cifs_inet_pton(AF_INET, volume_info.UNCip,
- &sin_server->sin_addr.s_addr);
-
- if (rc <= 0) {
- /* not ipv4 address, try ipv6 */
- rc = cifs_inet_pton(AF_INET6, volume_info.UNCip,
- &sin_server6->sin6_addr.in6_u);
- if (rc > 0)
- addr.sa_family = AF_INET6;
- } else {
- addr.sa_family = AF_INET;
- }
-
- if (rc <= 0) {
- /* we failed translating address */
- rc = -EINVAL;
- goto out;
- }
-
- cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
- /* success */
- rc = 0;
- } else if (volume_info.UNCip) {
- /* BB using ip addr as server name to connect to the
- DFS root below */
- cERROR(1, ("Connecting to DFS root not implemented yet"));
- rc = -EINVAL;
- goto out;
- } else /* which servers DFS root would we conect to */ {
- cERROR(1,
- ("CIFS mount error: No UNC path (e.g. -o "
- "unc=//192.168.1.100/public) specified"));
- rc = -EINVAL;
- goto out;
- }
/* this is needed for ASCII cp to Unicode converts */
- if (volume_info.iocharset == NULL) {
+ if (volume_info->iocharset == NULL) {
cifs_sb->local_nls = load_nls_default();
/* load_nls_default can not return null */
} else {
- cifs_sb->local_nls = load_nls(volume_info.iocharset);
+ cifs_sb->local_nls = load_nls(volume_info->iocharset);
if (cifs_sb->local_nls == NULL) {
cERROR(1, ("CIFS mount error: iocharset %s not found",
- volume_info.iocharset));
+ volume_info->iocharset));
rc = -ELIBACC;
goto out;
}
}
- srvTcp = cifs_find_tcp_session(&addr);
- if (!srvTcp) { /* create socket */
- if (addr.sa_family == AF_INET6) {
- cFYI(1, ("attempting ipv6 connect"));
- /* BB should we allow ipv6 on port 139? */
- /* other OS never observed in Wild doing 139 with v6 */
- sin_server6->sin6_port = htons(volume_info.port);
- rc = ipv6_connect(sin_server6, &csocket,
- volume_info.noblocksnd);
- } else {
- sin_server->sin_port = htons(volume_info.port);
- rc = ipv4_connect(sin_server, &csocket,
- volume_info.source_rfc1001_name,
- volume_info.target_rfc1001_name,
- volume_info.noblocksnd,
- volume_info.noautotune);
- }
- if (rc < 0) {
- cERROR(1, ("Error connecting to socket. "
- "Aborting operation"));
- if (csocket != NULL)
- sock_release(csocket);
- goto out;
- }
-
- srvTcp = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
- if (!srvTcp) {
- rc = -ENOMEM;
- sock_release(csocket);
- goto out;
- } else {
- srvTcp->noblocksnd = volume_info.noblocksnd;
- srvTcp->noautotune = volume_info.noautotune;
- if (addr.sa_family == AF_INET6)
- memcpy(&srvTcp->addr.sockAddr6, sin_server6,
- sizeof(struct sockaddr_in6));
- else
- memcpy(&srvTcp->addr.sockAddr, sin_server,
- sizeof(struct sockaddr_in));
- atomic_set(&srvTcp->inFlight, 0);
- /* BB Add code for ipv6 case too */
- srvTcp->ssocket = csocket;
- srvTcp->hostname = extract_hostname(volume_info.UNC);
- if (IS_ERR(srvTcp->hostname)) {
- rc = PTR_ERR(srvTcp->hostname);
- sock_release(csocket);
- goto out;
- }
- init_waitqueue_head(&srvTcp->response_q);
- init_waitqueue_head(&srvTcp->request_q);
- INIT_LIST_HEAD(&srvTcp->pending_mid_q);
- /* at this point we are the only ones with the pointer
- to the struct since the kernel thread not created yet
- so no need to spinlock this init of tcpStatus */
- srvTcp->tcpStatus = CifsNew;
- init_MUTEX(&srvTcp->tcpSem);
- srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
- if (IS_ERR(srvTcp->tsk)) {
- rc = PTR_ERR(srvTcp->tsk);
- cERROR(1, ("error %d create cifsd thread", rc));
- srvTcp->tsk = NULL;
- sock_release(csocket);
- kfree(srvTcp->hostname);
- goto out;
- }
- rc = 0;
- memcpy(srvTcp->workstation_RFC1001_name,
- volume_info.source_rfc1001_name, 16);
- memcpy(srvTcp->server_RFC1001_name,
- volume_info.target_rfc1001_name, 16);
- srvTcp->sequence_number = 0;
- INIT_LIST_HEAD(&srvTcp->tcp_ses_list);
- INIT_LIST_HEAD(&srvTcp->smb_ses_list);
- ++srvTcp->srv_count;
- write_lock(&cifs_tcp_ses_lock);
- list_add(&srvTcp->tcp_ses_list,
- &cifs_tcp_ses_list);
- write_unlock(&cifs_tcp_ses_lock);
- }
+ /* get a reference to a tcp session */
+ srvTcp = cifs_get_tcp_session(volume_info);
+ if (IS_ERR(srvTcp)) {
+ rc = PTR_ERR(srvTcp);
+ goto out;
}
- pSesInfo = cifs_find_smb_ses(srvTcp, volume_info.username);
+ pSesInfo = cifs_find_smb_ses(srvTcp, volume_info->username);
if (pSesInfo) {
cFYI(1, ("Existing smb sess found (status=%d)",
pSesInfo->status));
@@ -2228,31 +2269,38 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
/* new SMB session uses our srvTcp ref */
pSesInfo->server = srvTcp;
- sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
- NIPQUAD(sin_server->sin_addr.s_addr));
+ if (srvTcp->addr.sockAddr6.sin6_family == AF_INET6)
+ sprintf(pSesInfo->serverName, "%pI6",
+ &srvTcp->addr.sockAddr6.sin6_addr);
+ else
+ sprintf(pSesInfo->serverName, "%pI4",
+ &srvTcp->addr.sockAddr.sin_addr.s_addr);
write_lock(&cifs_tcp_ses_lock);
list_add(&pSesInfo->smb_ses_list, &srvTcp->smb_ses_list);
write_unlock(&cifs_tcp_ses_lock);
- /* volume_info.password freed at unmount */
- if (volume_info.password) {
- pSesInfo->password = volume_info.password;
- /* set to NULL to prevent freeing on exit */
- volume_info.password = NULL;
+ /* volume_info->password freed at unmount */
+ if (volume_info->password) {
+ pSesInfo->password = kstrdup(volume_info->password,
+ GFP_KERNEL);
+ if (!pSesInfo->password) {
+ rc = -ENOMEM;
+ goto mount_fail_check;
+ }
}
- if (volume_info.username)
- strncpy(pSesInfo->userName, volume_info.username,
+ if (volume_info->username)
+ strncpy(pSesInfo->userName, volume_info->username,
MAX_USERNAME_SIZE);
- if (volume_info.domainname) {
- int len = strlen(volume_info.domainname);
+ if (volume_info->domainname) {
+ int len = strlen(volume_info->domainname);
pSesInfo->domainName = kmalloc(len + 1, GFP_KERNEL);
if (pSesInfo->domainName)
strcpy(pSesInfo->domainName,
- volume_info.domainname);
+ volume_info->domainname);
}
- pSesInfo->linux_uid = volume_info.linux_uid;
- pSesInfo->overrideSecFlg = volume_info.secFlg;
+ pSesInfo->linux_uid = volume_info->linux_uid;
+ pSesInfo->overrideSecFlg = volume_info->secFlg;
down(&pSesInfo->sesSem);
/* BB FIXME need to pass vol->secFlgs BB */
@@ -2263,14 +2311,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
/* search for existing tcon to this server share */
if (!rc) {
- setup_cifs_sb(&volume_info, cifs_sb);
+ setup_cifs_sb(volume_info, cifs_sb);
- tcon = cifs_find_tcon(pSesInfo, volume_info.UNC);
+ tcon = cifs_find_tcon(pSesInfo, volume_info->UNC);
if (tcon) {
cFYI(1, ("Found match on UNC path"));
/* existing tcon already has a reference */
cifs_put_smb_ses(pSesInfo);
- if (tcon->seal != volume_info.seal)
+ if (tcon->seal != volume_info->seal)
cERROR(1, ("transport encryption setting "
"conflicts with existing tid"));
} else {
@@ -2279,11 +2327,20 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
rc = -ENOMEM;
goto mount_fail_check;
}
+
tcon->ses = pSesInfo;
+ if (volume_info->password) {
+ tcon->password = kstrdup(volume_info->password,
+ GFP_KERNEL);
+ if (!tcon->password) {
+ rc = -ENOMEM;
+ goto mount_fail_check;
+ }
+ }
/* check for null share name ie connect to dfs root */
- if ((strchr(volume_info.UNC + 3, '\\') == NULL)
- && (strchr(volume_info.UNC + 3, '/') == NULL)) {
+ if ((strchr(volume_info->UNC + 3, '\\') == NULL)
+ && (strchr(volume_info->UNC + 3, '/') == NULL)) {
/* rc = connect_to_dfs_path(...) */
cFYI(1, ("DFS root not supported"));
rc = -ENODEV;
@@ -2292,10 +2349,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
/* BB Do we need to wrap sesSem around
* this TCon call and Unix SetFS as
* we do on SessSetup and reconnect? */
- rc = CIFSTCon(xid, pSesInfo, volume_info.UNC,
+ rc = CIFSTCon(xid, pSesInfo, volume_info->UNC,
tcon, cifs_sb->local_nls);
cFYI(1, ("CIFS Tcon rc = %d", rc));
- if (volume_info.nodfs) {
+ if (volume_info->nodfs) {
tcon->Flags &= ~SMB_SHARE_IS_IN_DFS;
cFYI(1, ("DFS disabled (%d)",
tcon->Flags));
@@ -2303,7 +2360,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
}
if (rc)
goto mount_fail_check;
- tcon->seal = volume_info.seal;
+ tcon->seal = volume_info->seal;
write_lock(&cifs_tcp_ses_lock);
list_add(&tcon->tcon_list, &pSesInfo->tcon_list);
write_unlock(&cifs_tcp_ses_lock);
@@ -2313,9 +2370,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
to a share so for resources mounted more than once
to the same server share the last value passed in
for the retry flag is used */
- tcon->retry = volume_info.retry;
- tcon->nocase = volume_info.nocase;
- tcon->local_lease = volume_info.local_lease;
+ tcon->retry = volume_info->retry;
+ tcon->nocase = volume_info->nocase;
+ tcon->local_lease = volume_info->local_lease;
}
if (pSesInfo) {
if (pSesInfo->capabilities & CAP_LARGE_FILES) {
@@ -2352,7 +2409,7 @@ mount_fail_check:
if (tcon->ses->capabilities & CAP_UNIX)
/* reset of caps checks mount to see if unix extensions
disabled for just this mount */
- reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
+ reset_cifs_unix_caps(xid, tcon, sb, volume_info);
else
tcon->unix_ext = 0; /* server does not support them */
@@ -2371,18 +2428,22 @@ mount_fail_check:
cifs_sb->rsize = min(cifs_sb->rsize,
(tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
- /* volume_info.password is freed above when existing session found
+ /* volume_info->password is freed above when existing session found
(in which case it is not needed anymore) but when new sesion is created
the password ptr is put in the new session structure (in which case the
password will be freed at unmount time) */
out:
/* zero out password before freeing */
- if (volume_info.password != NULL) {
- memset(volume_info.password, 0, strlen(volume_info.password));
- kfree(volume_info.password);
+ if (volume_info) {
+ if (volume_info->password != NULL) {
+ memset(volume_info->password, 0,
+ strlen(volume_info->password));
+ kfree(volume_info->password);
+ }
+ kfree(volume_info->UNC);
+ kfree(volume_info->prepath);
+ kfree(volume_info);
}
- kfree(volume_info.UNC);
- kfree(volume_info.prepath);
FreeXid(xid);
return rc;
}
@@ -2533,7 +2594,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
__u16 action = le16_to_cpu(pSMBr->resp.Action);
__u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
if (action & GUEST_LOGIN)
- cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
+ cFYI(1, ("Guest login")); /* BB mark SesInfo struct? */
ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
(little endian) */
cFYI(1, ("UID = %d ", ses->Suid));
@@ -2679,13 +2740,11 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
len));
}
} else {
- cERROR(1,
- (" Security Blob Length extends beyond "
+ cERROR(1, ("Security Blob Length extends beyond "
"end of SMB"));
}
} else {
- cERROR(1,
- (" Invalid Word count %d: ",
+ cERROR(1, ("Invalid Word count %d: ",
smb_buffer_response->WordCount));
rc = -EIO;
}
@@ -2843,7 +2902,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
__u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
if (action & GUEST_LOGIN)
- cFYI(1, (" Guest login"));
+ cFYI(1, ("Guest login"));
/* Do we want to set anything in SesInfo struct when guest login? */
bcc_ptr = pByteArea(smb_buffer_response);
@@ -2851,8 +2910,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
if (SecurityBlob2->MessageType != NtLmChallenge) {
- cFYI(1,
- ("Unexpected NTLMSSP message type received %d",
+ cFYI(1, ("Unexpected NTLMSSP message type received %d",
SecurityBlob2->MessageType));
} else if (ses) {
ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
@@ -3024,8 +3082,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
cERROR(1, ("No session structure passed in."));
}
} else {
- cERROR(1,
- (" Invalid Word count %d:",
+ cERROR(1, ("Invalid Word count %d:",
smb_buffer_response->WordCount));
rc = -EIO;
}
@@ -3264,7 +3321,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
__u16 action = le16_to_cpu(pSMBr->resp.Action);
__u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
if (action & GUEST_LOGIN)
- cFYI(1, (" Guest login")); /* BB Should we set anything
+ cFYI(1, ("Guest login")); /* BB Should we set anything
in SesInfo struct ? */
/* if (SecurityBlob2->MessageType != NtLm??) {
cFYI("Unexpected message type on auth response is %d"));
@@ -3487,12 +3544,14 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
NTLMv2 password here) */
#ifdef CONFIG_CIFS_WEAK_PW_HASH
if ((extended_security & CIFSSEC_MAY_LANMAN) &&
- (ses->server->secType == LANMAN))
- calc_lanman_hash(ses, bcc_ptr);
+ (ses->server->secType == LANMAN))
+ calc_lanman_hash(tcon->password, ses->server->cryptKey,
+ ses->server->secMode &
+ SECMODE_PW_ENCRYPT ? true : false,
+ bcc_ptr);
else
#endif /* CIFS_WEAK_PW_HASH */
- SMBNTencrypt(ses->password,
- ses->server->cryptKey,
+ SMBNTencrypt(tcon->password, ses->server->cryptKey,
bcc_ptr);
bcc_ptr += CIFS_SESS_KEY_SIZE;
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index e962e75e6f7..838d9c720a5 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -235,11 +235,11 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
};
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
- args.uid = (__u64) current->fsuid;
+ args.uid = (__u64) current_fsuid();
if (inode->i_mode & S_ISGID)
args.gid = (__u64) inode->i_gid;
else
- args.gid = (__u64) current->fsgid;
+ args.gid = (__u64) current_fsgid();
} else {
args.uid = NO_CHANGE_64;
args.gid = NO_CHANGE_64;
@@ -271,13 +271,13 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
if ((oplock & CIFS_CREATE_ACTION) &&
(cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_SET_UID)) {
- newinode->i_uid = current->fsuid;
+ newinode->i_uid = current_fsuid();
if (inode->i_mode & S_ISGID)
newinode->i_gid =
inode->i_gid;
else
newinode->i_gid =
- current->fsgid;
+ current_fsgid();
}
}
}
@@ -375,8 +375,8 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
.device = device_number,
};
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
- args.uid = (__u64) current->fsuid;
- args.gid = (__u64) current->fsgid;
+ args.uid = (__u64) current_fsuid();
+ args.gid = (__u64) current_fsgid();
} else {
args.uid = NO_CHANGE_64;
args.gid = NO_CHANGE_64;
@@ -483,7 +483,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
xid = GetXid();
- cFYI(1, (" parent inode = 0x%p name is: %s and dentry = 0x%p",
+ cFYI(1, ("parent inode = 0x%p name is: %s and dentry = 0x%p",
parent_dir_inode, direntry->d_name.name, direntry));
/* check whether path exists */
@@ -515,12 +515,11 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
}
if (direntry->d_inode != NULL) {
- cFYI(1, (" non-NULL inode in lookup"));
+ cFYI(1, ("non-NULL inode in lookup"));
} else {
- cFYI(1, (" NULL inode in lookup"));
+ cFYI(1, ("NULL inode in lookup"));
}
- cFYI(1,
- (" Full path: %s inode = 0x%p", full_path, direntry->d_inode));
+ cFYI(1, ("Full path: %s inode = 0x%p", full_path, direntry->d_inode));
if (pTcon->unix_ext)
rc = cifs_get_inode_info_unix(&newInode, full_path,
diff --git a/fs/cifs/fcntl.c b/fs/cifs/fcntl.c
deleted file mode 100644
index 5a57581eb4b..00000000000
--- a/fs/cifs/fcntl.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * fs/cifs/fcntl.c
- *
- * vfs operations that deal with the file control API
- *
- * Copyright (C) International Business Machines Corp., 2003,2004
- * Author(s): Steve French (sfrench@us.ibm.com)
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- * the GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <linux/fs.h>
-#include <linux/stat.h>
-#include <linux/fcntl.h>
-#include "cifsglob.h"
-#include "cifsproto.h"
-#include "cifs_unicode.h"
-#include "cifs_debug.h"
-#include "cifsfs.h"
-
-static __u32 convert_to_cifs_notify_flags(unsigned long fcntl_notify_flags)
-{
- __u32 cifs_ntfy_flags = 0;
-
- /* No way on Linux VFS to ask to monitor xattr
- changes (and no stream support either */
- if (fcntl_notify_flags & DN_ACCESS)
- cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
- if (fcntl_notify_flags & DN_MODIFY) {
- /* What does this mean on directories? */
- cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_LAST_WRITE |
- FILE_NOTIFY_CHANGE_SIZE;
- }
- if (fcntl_notify_flags & DN_CREATE) {
- cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_CREATION |
- FILE_NOTIFY_CHANGE_LAST_WRITE;
- }
- if (fcntl_notify_flags & DN_DELETE)
- cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_LAST_WRITE;
- if (fcntl_notify_flags & DN_RENAME) {
- /* BB review this - checking various server behaviors */
- cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_DIR_NAME |
- FILE_NOTIFY_CHANGE_FILE_NAME;
- }
- if (fcntl_notify_flags & DN_ATTRIB) {
- cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_SECURITY |
- FILE_NOTIFY_CHANGE_ATTRIBUTES;
- }
-/* if (fcntl_notify_flags & DN_MULTISHOT) {
- cifs_ntfy_flags |= ;
- } */ /* BB fixme - not sure how to handle this with CIFS yet */
-
- return cifs_ntfy_flags;
-}
-
-int cifs_dir_notify(struct file *file, unsigned long arg)
-{
- int xid;
- int rc = -EINVAL;
- int oplock = 0;
- struct cifs_sb_info *cifs_sb;
- struct cifsTconInfo *pTcon;
- char *full_path = NULL;
- __u32 filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES;
- __u16 netfid;
-
- if (experimEnabled == 0)
- return 0;
-
- xid = GetXid();
- cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
- pTcon = cifs_sb->tcon;
-
- full_path = build_path_from_dentry(file->f_path.dentry);
-
- if (full_path == NULL) {
- rc = -ENOMEM;
- } else {
- cFYI(1, ("dir notify on file %s Arg 0x%lx", full_path, arg));
- rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
- GENERIC_READ | SYNCHRONIZE, 0 /* create options */,
- &netfid, &oplock, NULL, cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
- /* BB fixme - add this handle to a notify handle list */
- if (rc) {
- cFYI(1, ("Could not open directory for notify"));
- } else {
- filter = convert_to_cifs_notify_flags(arg);
- if (filter != 0) {
- rc = CIFSSMBNotify(xid, pTcon,
- 0 /* no subdirs */, netfid,
- filter, file, arg & DN_MULTISHOT,
- cifs_sb->local_nls);
- } else {
- rc = -EINVAL;
- }
- /* BB add code to close file eventually (at unmount
- it would close automatically but may be a way
- to do it easily when inode freed or when
- notify info is cleared/changed */
- cFYI(1, ("notify rc %d", rc));
- }
- }
-
- FreeXid(xid);
- return rc;
-}
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index f0a81e631ae..b1e1fc6a6e6 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -644,10 +644,10 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
__u64 length;
bool wait_flag = false;
struct cifs_sb_info *cifs_sb;
- struct cifsTconInfo *pTcon;
+ struct cifsTconInfo *tcon;
__u16 netfid;
__u8 lockType = LOCKING_ANDX_LARGE_FILES;
- bool posix_locking;
+ bool posix_locking = 0;
length = 1 + pfLock->fl_end - pfLock->fl_start;
rc = -EACCES;
@@ -698,7 +698,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
cFYI(1, ("Unknown type of lock"));
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
- pTcon = cifs_sb->tcon;
+ tcon = cifs_sb->tcon;
if (file->private_data == NULL) {
FreeXid(xid);
@@ -706,9 +706,10 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
}
netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
- posix_locking = (cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
- (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability));
-
+ if ((tcon->ses->capabilities & CAP_UNIX) &&
+ (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
+ ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
+ posix_locking = 1;
/* BB add code here to normalize offset and length to
account for negative length which we can not accept over the
wire */
@@ -719,7 +720,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
posix_lock_type = CIFS_RDLCK;
else
posix_lock_type = CIFS_WRLCK;
- rc = CIFSSMBPosixLock(xid, pTcon, netfid, 1 /* get */,
+ rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
length, pfLock,
posix_lock_type, wait_flag);
FreeXid(xid);
@@ -727,10 +728,10 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
}
/* BB we could chain these into one lock request BB */
- rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
+ rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
0, 1, lockType, 0 /* wait flag */ );
if (rc == 0) {
- rc = CIFSSMBLock(xid, pTcon, netfid, length,
+ rc = CIFSSMBLock(xid, tcon, netfid, length,
pfLock->fl_start, 1 /* numUnlock */ ,
0 /* numLock */ , lockType,
0 /* wait flag */ );
@@ -767,7 +768,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
if (numUnlock == 1)
posix_lock_type = CIFS_UNLCK;
- rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */,
+ rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */,
length, pfLock,
posix_lock_type, wait_flag);
} else {
@@ -775,7 +776,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
(struct cifsFileInfo *)file->private_data;
if (numLock) {
- rc = CIFSSMBLock(xid, pTcon, netfid, length,
+ rc = CIFSSMBLock(xid, tcon, netfid, length,
pfLock->fl_start,
0, numLock, lockType, wait_flag);
@@ -796,7 +797,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
if (pfLock->fl_start <= li->offset &&
(pfLock->fl_start + length) >=
(li->offset + li->length)) {
- stored_rc = CIFSSMBLock(xid, pTcon,
+ stored_rc = CIFSSMBLock(xid, tcon,
netfid,
li->length, li->offset,
1, 0, li->type, false);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index ff8c68de4a9..f247da9f4ed 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1,7 +1,7 @@
/*
* fs/cifs/inode.c
*
- * Copyright (C) International Business Machines Corp., 2002,2007
+ * Copyright (C) International Business Machines Corp., 2002,2008
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
@@ -621,6 +621,47 @@ static const struct inode_operations cifs_ipc_inode_ops = {
.lookup = cifs_lookup,
};
+static char *build_path_to_root(struct cifs_sb_info *cifs_sb)
+{
+ int pplen = cifs_sb->prepathlen;
+ int dfsplen;
+ char *full_path = NULL;
+
+ /* if no prefix path, simply set path to the root of share to "" */
+ if (pplen == 0) {
+ full_path = kmalloc(1, GFP_KERNEL);
+ if (full_path)
+ full_path[0] = 0;
+ return full_path;
+ }
+
+ if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS))
+ dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1);
+ else
+ dfsplen = 0;
+
+ full_path = kmalloc(dfsplen + pplen + 1, GFP_KERNEL);
+ if (full_path == NULL)
+ return full_path;
+
+ if (dfsplen) {
+ strncpy(full_path, cifs_sb->tcon->treeName, dfsplen);
+ /* switch slash direction in prepath depending on whether
+ * windows or posix style path names
+ */
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
+ int i;
+ for (i = 0; i < dfsplen; i++) {
+ if (full_path[i] == '\\')
+ full_path[i] = '/';
+ }
+ }
+ }
+ strncpy(full_path + dfsplen, cifs_sb->prepath, pplen);
+ full_path[dfsplen + pplen] = 0; /* add trailing null */
+ return full_path;
+}
+
/* gets root inode */
struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
{
@@ -628,6 +669,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
struct cifs_sb_info *cifs_sb;
struct inode *inode;
long rc;
+ char *full_path;
inode = iget_locked(sb, ino);
if (!inode)
@@ -636,13 +678,17 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
return inode;
cifs_sb = CIFS_SB(inode->i_sb);
- xid = GetXid();
+ full_path = build_path_to_root(cifs_sb);
+ if (full_path == NULL)
+ return ERR_PTR(-ENOMEM);
+ xid = GetXid();
if (cifs_sb->tcon->unix_ext)
- rc = cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid);
+ rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb,
+ xid);
else
- rc = cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid,
- NULL);
+ rc = cifs_get_inode_info(&inode, full_path, NULL, inode->i_sb,
+ xid, NULL);
if (rc && cifs_sb->tcon->ipc) {
cFYI(1, ("ipc connection - fake read inode"));
inode->i_mode |= S_IFDIR;
@@ -652,6 +698,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
inode->i_uid = cifs_sb->mnt_uid;
inode->i_gid = cifs_sb->mnt_gid;
} else if (rc) {
+ kfree(full_path);
_FreeXid(xid);
iget_failed(inode);
return ERR_PTR(rc);
@@ -659,6 +706,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
unlock_new_inode(inode);
+ kfree(full_path);
/* can not call macro FreeXid here since in a void func
* TODO: This is no longer true
*/
@@ -1143,11 +1191,11 @@ mkdir_get_info:
.device = 0,
};
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
- args.uid = (__u64)current->fsuid;
+ args.uid = (__u64)current_fsuid();
if (inode->i_mode & S_ISGID)
args.gid = (__u64)inode->i_gid;
else
- args.gid = (__u64)current->fsgid;
+ args.gid = (__u64)current_fsgid();
} else {
args.uid = NO_CHANGE_64;
args.gid = NO_CHANGE_64;
@@ -1184,13 +1232,13 @@ mkdir_get_info:
if (cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_SET_UID) {
direntry->d_inode->i_uid =
- current->fsuid;
+ current_fsuid();
if (inode->i_mode & S_ISGID)
direntry->d_inode->i_gid =
inode->i_gid;
else
direntry->d_inode->i_gid =
- current->fsgid;
+ current_fsgid();
}
}
}
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
index 0088a5b5256..f94650683a0 100644
--- a/fs/cifs/ioctl.c
+++ b/fs/cifs/ioctl.c
@@ -65,7 +65,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
switch (command) {
case CIFS_IOC_CHECKUMOUNT:
cFYI(1, ("User unmount attempted"));
- if (cifs_sb->mnt_uid == current->uid)
+ if (cifs_sb->mnt_uid == current_uid())
rc = 0;
else {
rc = -EACCES;
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 9ee3f689c2b..4c89c572891 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -97,7 +97,10 @@ sesInfoFree(struct cifsSesInfo *buf_to_free)
kfree(buf_to_free->serverOS);
kfree(buf_to_free->serverDomain);
kfree(buf_to_free->serverNOS);
- kfree(buf_to_free->password);
+ if (buf_to_free->password) {
+ memset(buf_to_free->password, 0, strlen(buf_to_free->password));
+ kfree(buf_to_free->password);
+ }
kfree(buf_to_free->domainName);
kfree(buf_to_free);
}
@@ -129,6 +132,10 @@ tconInfoFree(struct cifsTconInfo *buf_to_free)
}
atomic_dec(&tconInfoAllocCount);
kfree(buf_to_free->nativeFileSystem);
+ if (buf_to_free->password) {
+ memset(buf_to_free->password, 0, strlen(buf_to_free->password));
+ kfree(buf_to_free->password);
+ }
kfree(buf_to_free);
}
@@ -338,13 +345,13 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
/* BB Add support for establishing new tCon and SMB Session */
/* with userid/password pairs found on the smb session */
/* for other target tcp/ip addresses BB */
- if (current->fsuid != treeCon->ses->linux_uid) {
+ if (current_fsuid() != treeCon->ses->linux_uid) {
cFYI(1, ("Multiuser mode and UID "
"did not match tcon uid"));
read_lock(&cifs_tcp_ses_lock);
list_for_each(temp_item, &treeCon->ses->server->smb_ses_list) {
ses = list_entry(temp_item, struct cifsSesInfo, smb_ses_list);
- if (ses->linux_uid == current->fsuid) {
+ if (ses->linux_uid == current_fsuid()) {
if (ses->server == treeCon->ses->server) {
cFYI(1, ("found matching uid substitute right smb_uid"));
buffer->Uid = ses->Suid;
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index 2851d5da0c8..5f22de7b79a 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -417,7 +417,10 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
/* BB calculate hash with password */
/* and copy into bcc */
- calc_lanman_hash(ses, lnm_session_key);
+ calc_lanman_hash(ses->password, ses->server->cryptKey,
+ ses->server->secMode & SECMODE_PW_ENCRYPT ?
+ true : false, lnm_session_key);
+
ses->flags |= CIFS_SES_LANMAN;
memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESS_KEY_SIZE);
bcc_ptr += CIFS_SESS_KEY_SIZE;
diff --git a/fs/cifs/smbdes.c b/fs/cifs/smbdes.c
index 04943c976f9..224a1f47896 100644
--- a/fs/cifs/smbdes.c
+++ b/fs/cifs/smbdes.c
@@ -318,7 +318,8 @@ str_to_key(unsigned char *str, unsigned char *key)
}
static void
-smbhash(unsigned char *out, unsigned char *in, unsigned char *key, int forw)
+smbhash(unsigned char *out, const unsigned char *in, unsigned char *key,
+ int forw)
{
int i;
char *outb; /* outb[64] */
@@ -363,7 +364,7 @@ E_P16(unsigned char *p14, unsigned char *p16)
}
void
-E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24)
+E_P24(unsigned char *p21, const unsigned char *c8, unsigned char *p24)
{
smbhash(p24, c8, p21, 1);
smbhash(p24 + 8, c8, p21 + 7, 1);
diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c
index ff3232fa101..93fb09a99c6 100644
--- a/fs/cifs/smbencrypt.c
+++ b/fs/cifs/smbencrypt.c
@@ -49,9 +49,10 @@
/*The following definitions come from libsmb/smbencrypt.c */
-void SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
+void SMBencrypt(unsigned char *passwd, const unsigned char *c8,
+ unsigned char *p24);
void E_md4hash(const unsigned char *passwd, unsigned char *p16);
-static void SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8,
+static void SMBOWFencrypt(unsigned char passwd[16], const unsigned char *c8,
unsigned char p24[24]);
void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
@@ -61,7 +62,7 @@ void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
encrypted password into p24 */
/* Note that password must be uppercased and null terminated */
void
-SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24)
+SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24)
{
unsigned char p14[15], p21[21];
@@ -212,7 +213,7 @@ ntv2_owf_gen(const unsigned char owf[16], const char *user_n,
/* Does the des encryption from the NT or LM MD4 hash. */
static void
-SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8,
+SMBOWFencrypt(unsigned char passwd[16], const unsigned char *c8,
unsigned char p24[24])
{
unsigned char p21[21];
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index ff8243a8fe3..7ebe6599ed3 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -37,15 +37,11 @@ extern mempool_t *cifs_mid_poolp;
extern struct kmem_cache *cifs_oplock_cachep;
static struct mid_q_entry *
-AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
+AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
{
struct mid_q_entry *temp;
- if (ses == NULL) {
- cERROR(1, ("Null session passed in to AllocMidQEntry"));
- return NULL;
- }
- if (ses->server == NULL) {
+ if (server == NULL) {
cERROR(1, ("Null TCP session in AllocMidQEntry"));
return NULL;
}
@@ -62,12 +58,11 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
/* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
/* when mid allocated can be before when sent */
temp->when_alloc = jiffies;
- temp->ses = ses;
temp->tsk = current;
}
spin_lock(&GlobalMid_Lock);
- list_add_tail(&temp->qhead, &ses->server->pending_mid_q);
+ list_add_tail(&temp->qhead, &server->pending_mid_q);
atomic_inc(&midCount);
temp->midState = MID_REQUEST_ALLOCATED;
spin_unlock(&GlobalMid_Lock);
@@ -349,37 +344,38 @@ static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
if (long_op == CIFS_ASYNC_OP) {
/* oplock breaks must not be held up */
atomic_inc(&ses->server->inFlight);
- } else {
- spin_lock(&GlobalMid_Lock);
- while (1) {
- if (atomic_read(&ses->server->inFlight) >=
- cifs_max_pending){
- spin_unlock(&GlobalMid_Lock);
+ return 0;
+ }
+
+ spin_lock(&GlobalMid_Lock);
+ while (1) {
+ if (atomic_read(&ses->server->inFlight) >=
+ cifs_max_pending){
+ spin_unlock(&GlobalMid_Lock);
#ifdef CONFIG_CIFS_STATS2
- atomic_inc(&ses->server->num_waiters);
+ atomic_inc(&ses->server->num_waiters);
#endif
- wait_event(ses->server->request_q,
- atomic_read(&ses->server->inFlight)
- < cifs_max_pending);
+ wait_event(ses->server->request_q,
+ atomic_read(&ses->server->inFlight)
+ < cifs_max_pending);
#ifdef CONFIG_CIFS_STATS2
- atomic_dec(&ses->server->num_waiters);
+ atomic_dec(&ses->server->num_waiters);
#endif
- spin_lock(&GlobalMid_Lock);
- } else {
- if (ses->server->tcpStatus == CifsExiting) {
- spin_unlock(&GlobalMid_Lock);
- return -ENOENT;
- }
-
- /* can not count locking commands against total
- as they are allowed to block on server */
-
- /* update # of requests on the wire to server */
- if (long_op != CIFS_BLOCKING_OP)
- atomic_inc(&ses->server->inFlight);
+ spin_lock(&GlobalMid_Lock);
+ } else {
+ if (ses->server->tcpStatus == CifsExiting) {
spin_unlock(&GlobalMid_Lock);
- break;
+ return -ENOENT;
}
+
+ /* can not count locking commands against total
+ as they are allowed to block on server */
+
+ /* update # of requests on the wire to server */
+ if (long_op != CIFS_BLOCKING_OP)
+ atomic_inc(&ses->server->inFlight);
+ spin_unlock(&GlobalMid_Lock);
+ break;
}
}
return 0;
@@ -390,17 +386,21 @@ static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
{
if (ses->server->tcpStatus == CifsExiting) {
return -ENOENT;
- } else if (ses->server->tcpStatus == CifsNeedReconnect) {
+ }
+
+ if (ses->server->tcpStatus == CifsNeedReconnect) {
cFYI(1, ("tcp session dead - return to caller to retry"));
return -EAGAIN;
- } else if (ses->status != CifsGood) {
+ }
+
+ if (ses->status != CifsGood) {
/* check if SMB session is bad because we are setting it up */
if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
(in_buf->Command != SMB_COM_NEGOTIATE))
return -EAGAIN;
/* else ok - we are setting up session */
}
- *ppmidQ = AllocMidQEntry(in_buf, ses);
+ *ppmidQ = AllocMidQEntry(in_buf, ses->server);
if (*ppmidQ == NULL)
return -ENOMEM;
return 0;
@@ -415,11 +415,8 @@ static int wait_for_response(struct cifsSesInfo *ses,
for (;;) {
curr_timeout = timeout + jiffies;
- wait_event(ses->server->response_q,
- (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
- time_after(jiffies, curr_timeout) ||
- ((ses->server->tcpStatus != CifsGood) &&
- (ses->server->tcpStatus != CifsNew)));
+ wait_event_timeout(ses->server->response_q,
+ midQ->midState != MID_REQUEST_SUBMITTED, timeout);
if (time_after(jiffies, curr_timeout) &&
(midQ->midState == MID_REQUEST_SUBMITTED) &&
@@ -521,11 +518,11 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
and avoid races inside tcp sendmsg code that could cause corruption
of smb data */
- down(&ses->server->tcpSem);
+ mutex_lock(&ses->server->srv_mutex);
rc = allocate_mid(ses, in_buf, &midQ);
if (rc) {
- up(&ses->server->tcpSem);
+ mutex_unlock(&ses->server->srv_mutex);
cifs_small_buf_release(in_buf);
/* Update # of requests on wire to server */
atomic_dec(&ses->server->inFlight);
@@ -533,6 +530,11 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
return rc;
}
rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
+ if (rc) {
+ mutex_unlock(&ses->server->srv_mutex);
+ cifs_small_buf_release(in_buf);
+ goto out;
+ }
midQ->midState = MID_REQUEST_SUBMITTED;
#ifdef CONFIG_CIFS_STATS2
@@ -546,7 +548,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
midQ->when_sent = jiffies;
#endif
- up(&ses->server->tcpSem);
+ mutex_unlock(&ses->server->srv_mutex);
cifs_small_buf_release(in_buf);
if (rc < 0)
@@ -581,10 +583,8 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
wait_for_response(ses, midQ, timeout, 10 * HZ);
spin_lock(&GlobalMid_Lock);
- if (midQ->resp_buf) {
- spin_unlock(&GlobalMid_Lock);
- receive_len = midQ->resp_buf->smb_buf_length;
- } else {
+
+ if (midQ->resp_buf == NULL) {
cERROR(1, ("No response to cmd %d mid %d",
midQ->command, midQ->mid));
if (midQ->midState == MID_REQUEST_SUBMITTED) {
@@ -612,53 +612,59 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
return rc;
}
+ spin_unlock(&GlobalMid_Lock);
+ receive_len = midQ->resp_buf->smb_buf_length;
+
if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
cERROR(1, ("Frame too large received. Length: %d Xid: %d",
receive_len, xid));
rc = -EIO;
- } else { /* rcvd frame is ok */
- if (midQ->resp_buf &&
- (midQ->midState == MID_RESPONSE_RECEIVED)) {
-
- iov[0].iov_base = (char *)midQ->resp_buf;
- if (midQ->largeBuf)
- *pRespBufType = CIFS_LARGE_BUFFER;
- else
- *pRespBufType = CIFS_SMALL_BUFFER;
- iov[0].iov_len = receive_len + 4;
-
- dump_smb(midQ->resp_buf, 80);
- /* convert the length into a more usable form */
- if ((receive_len > 24) &&
- (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
- SECMODE_SIGN_ENABLED))) {
- rc = cifs_verify_signature(midQ->resp_buf,
+ goto out;
+ }
+
+ /* rcvd frame is ok */
+
+ if (midQ->resp_buf &&
+ (midQ->midState == MID_RESPONSE_RECEIVED)) {
+
+ iov[0].iov_base = (char *)midQ->resp_buf;
+ if (midQ->largeBuf)
+ *pRespBufType = CIFS_LARGE_BUFFER;
+ else
+ *pRespBufType = CIFS_SMALL_BUFFER;
+ iov[0].iov_len = receive_len + 4;
+
+ dump_smb(midQ->resp_buf, 80);
+ /* convert the length into a more usable form */
+ if ((receive_len > 24) &&
+ (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
+ SECMODE_SIGN_ENABLED))) {
+ rc = cifs_verify_signature(midQ->resp_buf,
&ses->server->mac_signing_key,
midQ->sequence_number+1);
- if (rc) {
- cERROR(1, ("Unexpected SMB signature"));
- /* BB FIXME add code to kill session */
- }
+ if (rc) {
+ cERROR(1, ("Unexpected SMB signature"));
+ /* BB FIXME add code to kill session */
}
-
- /* BB special case reconnect tid and uid here? */
- rc = map_smb_to_linux_error(midQ->resp_buf,
- flags & CIFS_LOG_ERROR);
-
- /* convert ByteCount if necessary */
- if (receive_len >= sizeof(struct smb_hdr) - 4
- /* do not count RFC1001 header */ +
- (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
- BCC(midQ->resp_buf) =
- le16_to_cpu(BCC_LE(midQ->resp_buf));
- if ((flags & CIFS_NO_RESP) == 0)
- midQ->resp_buf = NULL; /* mark it so buf will
- not be freed by
- DeleteMidQEntry */
- } else {
- rc = -EIO;
- cFYI(1, ("Bad MID state?"));
}
+
+ /* BB special case reconnect tid and uid here? */
+ rc = map_smb_to_linux_error(midQ->resp_buf,
+ flags & CIFS_LOG_ERROR);
+
+ /* convert ByteCount if necessary */
+ if (receive_len >= sizeof(struct smb_hdr) - 4
+ /* do not count RFC1001 header */ +
+ (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
+ BCC(midQ->resp_buf) =
+ le16_to_cpu(BCC_LE(midQ->resp_buf));
+ if ((flags & CIFS_NO_RESP) == 0)
+ midQ->resp_buf = NULL; /* mark it so buf will
+ not be freed by
+ DeleteMidQEntry */
+ } else {
+ rc = -EIO;
+ cFYI(1, ("Bad MID state?"));
}
out:
@@ -695,6 +701,12 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
to the same server. We may make this configurable later or
use ses->maxReq */
+ if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
+ cERROR(1, ("Illegal length, greater than maximum frame, %d",
+ in_buf->smb_buf_length));
+ return -EIO;
+ }
+
rc = wait_for_free_request(ses, long_op);
if (rc)
return rc;
@@ -703,29 +715,22 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
and avoid races inside tcp sendmsg code that could cause corruption
of smb data */
- down(&ses->server->tcpSem);
+ mutex_lock(&ses->server->srv_mutex);
rc = allocate_mid(ses, in_buf, &midQ);
if (rc) {
- up(&ses->server->tcpSem);
+ mutex_unlock(&ses->server->srv_mutex);
/* Update # of requests on wire to server */
atomic_dec(&ses->server->inFlight);
wake_up(&ses->server->request_q);
return rc;
}
- if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
- cERROR(1, ("Illegal length, greater than maximum frame, %d",
- in_buf->smb_buf_length));
- DeleteMidQEntry(midQ);
- up(&ses->server->tcpSem);
- /* Update # of requests on wire to server */
- atomic_dec(&ses->server->inFlight);
- wake_up(&ses->server->request_q);
- return -EIO;
- }
-
rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
+ if (rc) {
+ mutex_unlock(&ses->server->srv_mutex);
+ goto out;
+ }
midQ->midState = MID_REQUEST_SUBMITTED;
#ifdef CONFIG_CIFS_STATS2
@@ -738,7 +743,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
atomic_dec(&ses->server->inSend);
midQ->when_sent = jiffies;
#endif
- up(&ses->server->tcpSem);
+ mutex_unlock(&ses->server->srv_mutex);
if (rc < 0)
goto out;
@@ -772,10 +777,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
wait_for_response(ses, midQ, timeout, 10 * HZ);
spin_lock(&GlobalMid_Lock);
- if (midQ->resp_buf) {
- spin_unlock(&GlobalMid_Lock);
- receive_len = midQ->resp_buf->smb_buf_length;
- } else {
+ if (midQ->resp_buf == NULL) {
cERROR(1, ("No response for cmd %d mid %d",
midQ->command, midQ->mid));
if (midQ->midState == MID_REQUEST_SUBMITTED) {
@@ -803,47 +805,52 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
return rc;
}
+ spin_unlock(&GlobalMid_Lock);
+ receive_len = midQ->resp_buf->smb_buf_length;
+
if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
cERROR(1, ("Frame too large received. Length: %d Xid: %d",
receive_len, xid));
rc = -EIO;
- } else { /* rcvd frame is ok */
-
- if (midQ->resp_buf && out_buf
- && (midQ->midState == MID_RESPONSE_RECEIVED)) {
- out_buf->smb_buf_length = receive_len;
- memcpy((char *)out_buf + 4,
- (char *)midQ->resp_buf + 4,
- receive_len);
-
- dump_smb(out_buf, 92);
- /* convert the length into a more usable form */
- if ((receive_len > 24) &&
- (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
- SECMODE_SIGN_ENABLED))) {
- rc = cifs_verify_signature(out_buf,
+ goto out;
+ }
+
+ /* rcvd frame is ok */
+
+ if (midQ->resp_buf && out_buf
+ && (midQ->midState == MID_RESPONSE_RECEIVED)) {
+ out_buf->smb_buf_length = receive_len;
+ memcpy((char *)out_buf + 4,
+ (char *)midQ->resp_buf + 4,
+ receive_len);
+
+ dump_smb(out_buf, 92);
+ /* convert the length into a more usable form */
+ if ((receive_len > 24) &&
+ (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
+ SECMODE_SIGN_ENABLED))) {
+ rc = cifs_verify_signature(out_buf,
&ses->server->mac_signing_key,
midQ->sequence_number+1);
- if (rc) {
- cERROR(1, ("Unexpected SMB signature"));
- /* BB FIXME add code to kill session */
- }
+ if (rc) {
+ cERROR(1, ("Unexpected SMB signature"));
+ /* BB FIXME add code to kill session */
}
+ }
- *pbytes_returned = out_buf->smb_buf_length;
+ *pbytes_returned = out_buf->smb_buf_length;
- /* BB special case reconnect tid and uid here? */
- rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
+ /* BB special case reconnect tid and uid here? */
+ rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
- /* convert ByteCount if necessary */
- if (receive_len >= sizeof(struct smb_hdr) - 4
- /* do not count RFC1001 header */ +
- (2 * out_buf->WordCount) + 2 /* bcc */ )
- BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
- } else {
- rc = -EIO;
- cERROR(1, ("Bad MID state?"));
- }
+ /* convert ByteCount if necessary */
+ if (receive_len >= sizeof(struct smb_hdr) - 4
+ /* do not count RFC1001 header */ +
+ (2 * out_buf->WordCount) + 2 /* bcc */ )
+ BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
+ } else {
+ rc = -EIO;
+ cERROR(1, ("Bad MID state?"));
}
out:
@@ -866,16 +873,16 @@ send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf,
header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0);
in_buf->Mid = mid;
- down(&ses->server->tcpSem);
+ mutex_lock(&ses->server->srv_mutex);
rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
if (rc) {
- up(&ses->server->tcpSem);
+ mutex_unlock(&ses->server->srv_mutex);
return rc;
}
rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
(struct sockaddr *) &(ses->server->addr.sockAddr),
ses->server->noblocksnd);
- up(&ses->server->tcpSem);
+ mutex_unlock(&ses->server->srv_mutex);
return rc;
}
@@ -933,6 +940,12 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
to the same server. We may make this configurable later or
use ses->maxReq */
+ if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
+ cERROR(1, ("Illegal length, greater than maximum frame, %d",
+ in_buf->smb_buf_length));
+ return -EIO;
+ }
+
rc = wait_for_free_request(ses, CIFS_BLOCKING_OP);
if (rc)
return rc;
@@ -941,24 +954,21 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
and avoid races inside tcp sendmsg code that could cause corruption
of smb data */
- down(&ses->server->tcpSem);
+ mutex_lock(&ses->server->srv_mutex);
rc = allocate_mid(ses, in_buf, &midQ);
if (rc) {
- up(&ses->server->tcpSem);
+ mutex_unlock(&ses->server->srv_mutex);
return rc;
}
- if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
- up(&ses->server->tcpSem);
- cERROR(1, ("Illegal length, greater than maximum frame, %d",
- in_buf->smb_buf_length));
+ rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
+ if (rc) {
DeleteMidQEntry(midQ);
- return -EIO;
+ mutex_unlock(&ses->server->srv_mutex);
+ return rc;
}
- rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
-
midQ->midState = MID_REQUEST_SUBMITTED;
#ifdef CONFIG_CIFS_STATS2
atomic_inc(&ses->server->inSend);
@@ -970,7 +980,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
atomic_dec(&ses->server->inSend);
midQ->when_sent = jiffies;
#endif
- up(&ses->server->tcpSem);
+ mutex_unlock(&ses->server->srv_mutex);
if (rc < 0) {
DeleteMidQEntry(midQ);
@@ -1052,44 +1062,48 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
cERROR(1, ("Frame too large received. Length: %d Xid: %d",
receive_len, xid));
rc = -EIO;
- } else { /* rcvd frame is ok */
-
- if (midQ->resp_buf && out_buf
- && (midQ->midState == MID_RESPONSE_RECEIVED)) {
- out_buf->smb_buf_length = receive_len;
- memcpy((char *)out_buf + 4,
- (char *)midQ->resp_buf + 4,
- receive_len);
-
- dump_smb(out_buf, 92);
- /* convert the length into a more usable form */
- if ((receive_len > 24) &&
- (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
- SECMODE_SIGN_ENABLED))) {
- rc = cifs_verify_signature(out_buf,
- &ses->server->mac_signing_key,
- midQ->sequence_number+1);
- if (rc) {
- cERROR(1, ("Unexpected SMB signature"));
- /* BB FIXME add code to kill session */
- }
- }
+ goto out;
+ }
- *pbytes_returned = out_buf->smb_buf_length;
+ /* rcvd frame is ok */
- /* BB special case reconnect tid and uid here? */
- rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
+ if ((out_buf == NULL) || (midQ->midState != MID_RESPONSE_RECEIVED)) {
+ rc = -EIO;
+ cERROR(1, ("Bad MID state?"));
+ goto out;
+ }
- /* convert ByteCount if necessary */
- if (receive_len >= sizeof(struct smb_hdr) - 4
- /* do not count RFC1001 header */ +
- (2 * out_buf->WordCount) + 2 /* bcc */ )
- BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
- } else {
- rc = -EIO;
- cERROR(1, ("Bad MID state?"));
+ out_buf->smb_buf_length = receive_len;
+ memcpy((char *)out_buf + 4,
+ (char *)midQ->resp_buf + 4,
+ receive_len);
+
+ dump_smb(out_buf, 92);
+ /* convert the length into a more usable form */
+ if ((receive_len > 24) &&
+ (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
+ SECMODE_SIGN_ENABLED))) {
+ rc = cifs_verify_signature(out_buf,
+ &ses->server->mac_signing_key,
+ midQ->sequence_number+1);
+ if (rc) {
+ cERROR(1, ("Unexpected SMB signature"));
+ /* BB FIXME add code to kill session */
}
}
+
+ *pbytes_returned = out_buf->smb_buf_length;
+
+ /* BB special case reconnect tid and uid here? */
+ rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
+
+ /* convert ByteCount if necessary */
+ if (receive_len >= sizeof(struct smb_hdr) - 4
+ /* do not count RFC1001 header */ +
+ (2 * out_buf->WordCount) + 2 /* bcc */ )
+ BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
+
+out:
DeleteMidQEntry(midQ);
if (rstart && rc == -EACCES)
return -ERESTARTSYS;
diff --git a/fs/coda/cache.c b/fs/coda/cache.c
index 8a2370341c7..a5bf5771a22 100644
--- a/fs/coda/cache.c
+++ b/fs/coda/cache.c
@@ -32,8 +32,8 @@ void coda_cache_enter(struct inode *inode, int mask)
struct coda_inode_info *cii = ITOC(inode);
cii->c_cached_epoch = atomic_read(&permission_epoch);
- if (cii->c_uid != current->fsuid) {
- cii->c_uid = current->fsuid;
+ if (cii->c_uid != current_fsuid()) {
+ cii->c_uid = current_fsuid();
cii->c_cached_perm = mask;
} else
cii->c_cached_perm |= mask;
@@ -60,7 +60,7 @@ int coda_cache_check(struct inode *inode, int mask)
int hit;
hit = (mask & cii->c_cached_perm) == mask &&
- cii->c_uid == current->fsuid &&
+ cii->c_uid == current_fsuid() &&
cii->c_cached_epoch == atomic_read(&permission_epoch);
return hit;
diff --git a/fs/coda/file.c b/fs/coda/file.c
index 29137ff3ca6..466303db2df 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -13,6 +13,7 @@
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/stat.h>
+#include <linux/cred.h>
#include <linux/errno.h>
#include <linux/smp_lock.h>
#include <linux/string.h>
@@ -174,7 +175,7 @@ int coda_release(struct inode *coda_inode, struct file *coda_file)
BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
err = venus_close(coda_inode->i_sb, coda_i2f(coda_inode),
- coda_flags, coda_file->f_uid);
+ coda_flags, coda_file->f_cred->fsuid);
host_inode = cfi->cfi_container->f_path.dentry->d_inode;
cii = ITOC(coda_inode);
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c
index ce432bca95d..c274d949179 100644
--- a/fs/coda/upcall.c
+++ b/fs/coda/upcall.c
@@ -52,7 +52,7 @@ static void *alloc_upcall(int opcode, int size)
inp->ih.opcode = opcode;
inp->ih.pid = current->pid;
inp->ih.pgid = task_pgrp_nr(current);
- inp->ih.uid = current->fsuid;
+ inp->ih.uid = current_fsuid();
return (void*)inp;
}
diff --git a/fs/compat.c b/fs/compat.c
index e5f49f53850..d1ece79b641 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -1393,10 +1393,20 @@ int compat_do_execve(char * filename,
if (!bprm)
goto out_ret;
+ retval = mutex_lock_interruptible(&current->cred_exec_mutex);
+ if (retval < 0)
+ goto out_free;
+
+ retval = -ENOMEM;
+ bprm->cred = prepare_exec_creds();
+ if (!bprm->cred)
+ goto out_unlock;
+ check_unsafe_exec(bprm);
+
file = open_exec(filename);
retval = PTR_ERR(file);
if (IS_ERR(file))
- goto out_kfree;
+ goto out_unlock;
sched_exec();
@@ -1410,14 +1420,10 @@ int compat_do_execve(char * filename,
bprm->argc = compat_count(argv, MAX_ARG_STRINGS);
if ((retval = bprm->argc) < 0)
- goto out_mm;
+ goto out;
bprm->envc = compat_count(envp, MAX_ARG_STRINGS);
if ((retval = bprm->envc) < 0)
- goto out_mm;
-
- retval = security_bprm_alloc(bprm);
- if (retval)
goto out;
retval = prepare_binprm(bprm);
@@ -1438,19 +1444,16 @@ int compat_do_execve(char * filename,
goto out;
retval = search_binary_handler(bprm, regs);
- if (retval >= 0) {
- /* execve success */
- security_bprm_free(bprm);
- acct_update_integrals(current);
- free_bprm(bprm);
- return retval;
- }
+ if (retval < 0)
+ goto out;
-out:
- if (bprm->security)
- security_bprm_free(bprm);
+ /* execve succeeded */
+ mutex_unlock(&current->cred_exec_mutex);
+ acct_update_integrals(current);
+ free_bprm(bprm);
+ return retval;
-out_mm:
+out:
if (bprm->mm)
mmput(bprm->mm);
@@ -1460,7 +1463,10 @@ out_file:
fput(bprm->file);
}
-out_kfree:
+out_unlock:
+ mutex_unlock(&current->cred_exec_mutex);
+
+out_free:
free_bprm(bprm);
out_ret:
diff --git a/fs/dcache.c b/fs/dcache.c
index a1d86c7f3e6..e88c23b85a3 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -34,7 +34,6 @@
#include <linux/bootmem.h>
#include "internal.h"
-
int sysctl_vfs_cache_pressure __read_mostly = 100;
EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure);
@@ -948,9 +947,6 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
dentry->d_op = NULL;
dentry->d_fsdata = NULL;
dentry->d_mounted = 0;
-#ifdef CONFIG_PROFILING
- dentry->d_cookie = NULL;
-#endif
INIT_HLIST_NODE(&dentry->d_hash);
INIT_LIST_HEAD(&dentry->d_lru);
INIT_LIST_HEAD(&dentry->d_subdirs);
@@ -1336,7 +1332,7 @@ err_out:
*
* Searches the children of the parent dentry for the name in question. If
* the dentry is found its reference count is incremented and the dentry
- * is returned. The caller must use d_put to free the entry when it has
+ * is returned. The caller must use dput to free the entry when it has
* finished using it. %NULL is returned on failure.
*
* __d_lookup is dcache_lock free. The hash list is protected using RCU.
@@ -1620,8 +1616,11 @@ static void switch_names(struct dentry *dentry, struct dentry *target)
*/
memcpy(dentry->d_iname, target->d_name.name,
target->d_name.len + 1);
+ dentry->d_name.len = target->d_name.len;
+ return;
}
}
+ do_switch(dentry->d_name.len, target->d_name.len);
}
/*
@@ -1681,7 +1680,6 @@ already_unhashed:
/* Switch the names.. */
switch_names(dentry, target);
- do_switch(dentry->d_name.len, target->d_name.len);
do_switch(dentry->d_name.hash, target->d_name.hash);
/* ... and switch the parents */
@@ -1791,7 +1789,6 @@ static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon)
struct dentry *dparent, *aparent;
switch_names(dentry, anon);
- do_switch(dentry->d_name.len, anon->d_name.len);
do_switch(dentry->d_name.hash, anon->d_name.hash);
dparent = dentry->d_parent;
@@ -1911,7 +1908,8 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name)
* Convert a dentry into an ASCII path name. If the entry has been deleted
* the string " (deleted)" is appended. Note that this is ambiguous.
*
- * Returns the buffer or an error code if the path was too long.
+ * Returns a pointer into the buffer or an error code if the
+ * path was too long.
*
* "buflen" should be positive. Caller holds the dcache_lock.
*
@@ -1987,7 +1985,10 @@ Elong:
* Convert a dentry into an ASCII path name. If the entry has been deleted
* the string " (deleted)" is appended. Note that this is ambiguous.
*
- * Returns the buffer or an error code if the path was too long.
+ * Returns a pointer into the buffer or an error code if the path was
+ * too long. Note: Callers should use the returned pointer, not the passed
+ * in buffer, to use the name! The implementation often starts at an offset
+ * into the buffer, and may leave 0 bytes at the start.
*
* "buflen" should be positive.
*/
@@ -2313,9 +2314,6 @@ static void __init dcache_init(void)
/* SLAB cache for __getname() consumers */
struct kmem_cache *names_cachep __read_mostly;
-/* SLAB cache for file structures */
-struct kmem_cache *filp_cachep __read_mostly;
-
EXPORT_SYMBOL(d_genocide);
void __init vfs_caches_init_early(void)
@@ -2337,9 +2335,6 @@ void __init vfs_caches_init(unsigned long mempages)
names_cachep = kmem_cache_create("names_cache", PATH_MAX, 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
- filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0,
- SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
-
dcache_init();
inode_init();
files_init(mempages);
diff --git a/fs/dcookies.c b/fs/dcookies.c
index 855d4b1d619..180e9fec4ad 100644
--- a/fs/dcookies.c
+++ b/fs/dcookies.c
@@ -93,10 +93,15 @@ static struct dcookie_struct *alloc_dcookie(struct path *path)
{
struct dcookie_struct *dcs = kmem_cache_alloc(dcookie_cache,
GFP_KERNEL);
+ struct dentry *d;
if (!dcs)
return NULL;
- path->dentry->d_cookie = dcs;
+ d = path->dentry;
+ spin_lock(&d->d_lock);
+ d->d_flags |= DCACHE_COOKIE;
+ spin_unlock(&d->d_lock);
+
dcs->path = *path;
path_get(path);
hash_dcookie(dcs);
@@ -119,14 +124,14 @@ int get_dcookie(struct path *path, unsigned long *cookie)
goto out;
}
- dcs = path->dentry->d_cookie;
-
- if (!dcs)
+ if (path->dentry->d_flags & DCACHE_COOKIE) {
+ dcs = find_dcookie((unsigned long)path->dentry);
+ } else {
dcs = alloc_dcookie(path);
-
- if (!dcs) {
- err = -ENOMEM;
- goto out;
+ if (!dcs) {
+ err = -ENOMEM;
+ goto out;
+ }
}
*cookie = dcookie_value(dcs);
@@ -251,7 +256,12 @@ out_kmem:
static void free_dcookie(struct dcookie_struct * dcs)
{
- dcs->path.dentry->d_cookie = NULL;
+ struct dentry *d = dcs->path.dentry;
+
+ spin_lock(&d->d_lock);
+ d->d_flags &= ~DCACHE_COOKIE;
+ spin_unlock(&d->d_lock);
+
path_put(&dcs->path);
kmem_cache_free(dcookie_cache, dcs);
}
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 4a714f6c1be..fff96e152c0 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -27,25 +27,32 @@
#define DEVPTS_SUPER_MAGIC 0x1cd1
#define DEVPTS_DEFAULT_MODE 0600
+/*
+ * ptmx is a new node in /dev/pts and will be unused in legacy (single-
+ * instance) mode. To prevent surprises in user space, set permissions of
+ * ptmx to 0. Use 'chmod' or remount with '-o ptmxmode' to set meaningful
+ * permissions.
+ */
+#define DEVPTS_DEFAULT_PTMX_MODE 0000
#define PTMX_MINOR 2
extern int pty_limit; /* Config limit on Unix98 ptys */
-static DEFINE_IDA(allocated_ptys);
static DEFINE_MUTEX(allocated_ptys_lock);
static struct vfsmount *devpts_mnt;
-static struct dentry *devpts_root;
-static struct {
+struct pts_mount_opts {
int setuid;
int setgid;
uid_t uid;
gid_t gid;
umode_t mode;
-} config = {.mode = DEVPTS_DEFAULT_MODE};
+ umode_t ptmxmode;
+ int newinstance;
+};
enum {
- Opt_uid, Opt_gid, Opt_mode,
+ Opt_uid, Opt_gid, Opt_mode, Opt_ptmxmode, Opt_newinstance,
Opt_err
};
@@ -53,18 +60,50 @@ static const match_table_t tokens = {
{Opt_uid, "uid=%u"},
{Opt_gid, "gid=%u"},
{Opt_mode, "mode=%o"},
+#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
+ {Opt_ptmxmode, "ptmxmode=%o"},
+ {Opt_newinstance, "newinstance"},
+#endif
{Opt_err, NULL}
};
-static int devpts_remount(struct super_block *sb, int *flags, char *data)
+struct pts_fs_info {
+ struct ida allocated_ptys;
+ struct pts_mount_opts mount_opts;
+ struct dentry *ptmx_dentry;
+};
+
+static inline struct pts_fs_info *DEVPTS_SB(struct super_block *sb)
+{
+ return sb->s_fs_info;
+}
+
+static inline struct super_block *pts_sb_from_inode(struct inode *inode)
+{
+#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
+ if (inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC)
+ return inode->i_sb;
+#endif
+ return devpts_mnt->mnt_sb;
+}
+
+#define PARSE_MOUNT 0
+#define PARSE_REMOUNT 1
+
+static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts)
{
char *p;
- config.setuid = 0;
- config.setgid = 0;
- config.uid = 0;
- config.gid = 0;
- config.mode = DEVPTS_DEFAULT_MODE;
+ opts->setuid = 0;
+ opts->setgid = 0;
+ opts->uid = 0;
+ opts->gid = 0;
+ opts->mode = DEVPTS_DEFAULT_MODE;
+ opts->ptmxmode = DEVPTS_DEFAULT_PTMX_MODE;
+
+ /* newinstance makes sense only on initial mount */
+ if (op == PARSE_MOUNT)
+ opts->newinstance = 0;
while ((p = strsep(&data, ",")) != NULL) {
substring_t args[MAX_OPT_ARGS];
@@ -79,20 +118,32 @@ static int devpts_remount(struct super_block *sb, int *flags, char *data)
case Opt_uid:
if (match_int(&args[0], &option))
return -EINVAL;
- config.uid = option;
- config.setuid = 1;
+ opts->uid = option;
+ opts->setuid = 1;
break;
case Opt_gid:
if (match_int(&args[0], &option))
return -EINVAL;
- config.gid = option;
- config.setgid = 1;
+ opts->gid = option;
+ opts->setgid = 1;
break;
case Opt_mode:
if (match_octal(&args[0], &option))
return -EINVAL;
- config.mode = option & S_IALLUGO;
+ opts->mode = option & S_IALLUGO;
+ break;
+#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
+ case Opt_ptmxmode:
+ if (match_octal(&args[0], &option))
+ return -EINVAL;
+ opts->ptmxmode = option & S_IALLUGO;
+ break;
+ case Opt_newinstance:
+ /* newinstance makes sense only on initial mount */
+ if (op == PARSE_MOUNT)
+ opts->newinstance = 1;
break;
+#endif
default:
printk(KERN_ERR "devpts: called with bogus options\n");
return -EINVAL;
@@ -102,13 +153,108 @@ static int devpts_remount(struct super_block *sb, int *flags, char *data)
return 0;
}
+#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
+static int mknod_ptmx(struct super_block *sb)
+{
+ int mode;
+ int rc = -ENOMEM;
+ struct dentry *dentry;
+ struct inode *inode;
+ struct dentry *root = sb->s_root;
+ struct pts_fs_info *fsi = DEVPTS_SB(sb);
+ struct pts_mount_opts *opts = &fsi->mount_opts;
+
+ mutex_lock(&root->d_inode->i_mutex);
+
+ /* If we have already created ptmx node, return */
+ if (fsi->ptmx_dentry) {
+ rc = 0;
+ goto out;
+ }
+
+ dentry = d_alloc_name(root, "ptmx");
+ if (!dentry) {
+ printk(KERN_NOTICE "Unable to alloc dentry for ptmx node\n");
+ goto out;
+ }
+
+ /*
+ * Create a new 'ptmx' node in this mount of devpts.
+ */
+ inode = new_inode(sb);
+ if (!inode) {
+ printk(KERN_ERR "Unable to alloc inode for ptmx node\n");
+ dput(dentry);
+ goto out;
+ }
+
+ inode->i_ino = 2;
+ inode->i_uid = inode->i_gid = 0;
+ inode->i_blocks = 0;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+
+ mode = S_IFCHR|opts->ptmxmode;
+ init_special_inode(inode, mode, MKDEV(TTYAUX_MAJOR, 2));
+
+ d_add(dentry, inode);
+
+ fsi->ptmx_dentry = dentry;
+ rc = 0;
+
+ printk(KERN_DEBUG "Created ptmx node in devpts ino %lu\n",
+ inode->i_ino);
+out:
+ mutex_unlock(&root->d_inode->i_mutex);
+ return rc;
+}
+
+static void update_ptmx_mode(struct pts_fs_info *fsi)
+{
+ struct inode *inode;
+ if (fsi->ptmx_dentry) {
+ inode = fsi->ptmx_dentry->d_inode;
+ inode->i_mode = S_IFCHR|fsi->mount_opts.ptmxmode;
+ }
+}
+#else
+static inline void update_ptmx_mode(struct pts_fs_info *fsi)
+{
+ return;
+}
+#endif
+
+static int devpts_remount(struct super_block *sb, int *flags, char *data)
+{
+ int err;
+ struct pts_fs_info *fsi = DEVPTS_SB(sb);
+ struct pts_mount_opts *opts = &fsi->mount_opts;
+
+ err = parse_mount_options(data, PARSE_REMOUNT, opts);
+
+ /*
+ * parse_mount_options() restores options to default values
+ * before parsing and may have changed ptmxmode. So, update the
+ * mode in the inode too. Bogus options don't fail the remount,
+ * so do this even on error return.
+ */
+ update_ptmx_mode(fsi);
+
+ return err;
+}
+
static int devpts_show_options(struct seq_file *seq, struct vfsmount *vfs)
{
- if (config.setuid)
- seq_printf(seq, ",uid=%u", config.uid);
- if (config.setgid)
- seq_printf(seq, ",gid=%u", config.gid);
- seq_printf(seq, ",mode=%03o", config.mode);
+ struct pts_fs_info *fsi = DEVPTS_SB(vfs->mnt_sb);
+ struct pts_mount_opts *opts = &fsi->mount_opts;
+
+ if (opts->setuid)
+ seq_printf(seq, ",uid=%u", opts->uid);
+ if (opts->setgid)
+ seq_printf(seq, ",gid=%u", opts->gid);
+ seq_printf(seq, ",mode=%03o", opts->mode);
+#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
+ seq_printf(seq, ",ptmxmode=%03o", opts->ptmxmode);
+#endif
return 0;
}
@@ -119,10 +265,25 @@ static const struct super_operations devpts_sops = {
.show_options = devpts_show_options,
};
+static void *new_pts_fs_info(void)
+{
+ struct pts_fs_info *fsi;
+
+ fsi = kzalloc(sizeof(struct pts_fs_info), GFP_KERNEL);
+ if (!fsi)
+ return NULL;
+
+ ida_init(&fsi->allocated_ptys);
+ fsi->mount_opts.mode = DEVPTS_DEFAULT_MODE;
+ fsi->mount_opts.ptmxmode = DEVPTS_DEFAULT_PTMX_MODE;
+
+ return fsi;
+}
+
static int
devpts_fill_super(struct super_block *s, void *data, int silent)
{
- struct inode * inode;
+ struct inode *inode;
s->s_blocksize = 1024;
s->s_blocksize_bits = 10;
@@ -130,9 +291,13 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
s->s_op = &devpts_sops;
s->s_time_gran = 1;
+ s->s_fs_info = new_pts_fs_info();
+ if (!s->s_fs_info)
+ goto fail;
+
inode = new_inode(s);
if (!inode)
- goto fail;
+ goto free_fsi;
inode->i_ino = 1;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_blocks = 0;
@@ -142,27 +307,226 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
inode->i_fop = &simple_dir_operations;
inode->i_nlink = 2;
- devpts_root = s->s_root = d_alloc_root(inode);
+ s->s_root = d_alloc_root(inode);
if (s->s_root)
return 0;
-
- printk("devpts: get root dentry failed\n");
+
+ printk(KERN_ERR "devpts: get root dentry failed\n");
iput(inode);
+
+free_fsi:
+ kfree(s->s_fs_info);
fail:
return -ENOMEM;
}
+#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
+static int compare_init_pts_sb(struct super_block *s, void *p)
+{
+ if (devpts_mnt)
+ return devpts_mnt->mnt_sb == s;
+ return 0;
+}
+
+/*
+ * Safely parse the mount options in @data and update @opts.
+ *
+ * devpts ends up parsing options two times during mount, due to the
+ * two modes of operation it supports. The first parse occurs in
+ * devpts_get_sb() when determining the mode (single-instance or
+ * multi-instance mode). The second parse happens in devpts_remount()
+ * or new_pts_mount() depending on the mode.
+ *
+ * Parsing of options modifies the @data making subsequent parsing
+ * incorrect. So make a local copy of @data and parse it.
+ *
+ * Return: 0 On success, -errno on error
+ */
+static int safe_parse_mount_options(void *data, struct pts_mount_opts *opts)
+{
+ int rc;
+ void *datacp;
+
+ if (!data)
+ return 0;
+
+ /* Use kstrdup() ? */
+ datacp = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!datacp)
+ return -ENOMEM;
+
+ memcpy(datacp, data, PAGE_SIZE);
+ rc = parse_mount_options((char *)datacp, PARSE_MOUNT, opts);
+ kfree(datacp);
+
+ return rc;
+}
+
+/*
+ * Mount a new (private) instance of devpts. PTYs created in this
+ * instance are independent of the PTYs in other devpts instances.
+ */
+static int new_pts_mount(struct file_system_type *fs_type, int flags,
+ void *data, struct vfsmount *mnt)
+{
+ int err;
+ struct pts_fs_info *fsi;
+ struct pts_mount_opts *opts;
+
+ printk(KERN_NOTICE "devpts: newinstance mount\n");
+
+ err = get_sb_nodev(fs_type, flags, data, devpts_fill_super, mnt);
+ if (err)
+ return err;
+
+ fsi = DEVPTS_SB(mnt->mnt_sb);
+ opts = &fsi->mount_opts;
+
+ err = parse_mount_options(data, PARSE_MOUNT, opts);
+ if (err)
+ goto fail;
+
+ err = mknod_ptmx(mnt->mnt_sb);
+ if (err)
+ goto fail;
+
+ return 0;
+
+fail:
+ dput(mnt->mnt_sb->s_root);
+ deactivate_super(mnt->mnt_sb);
+ return err;
+}
+
+/*
+ * Check if 'newinstance' mount option was specified in @data.
+ *
+ * Return: -errno on error (eg: invalid mount options specified)
+ * : 1 if 'newinstance' mount option was specified
+ * : 0 if 'newinstance' mount option was NOT specified
+ */
+static int is_new_instance_mount(void *data)
+{
+ int rc;
+ struct pts_mount_opts opts;
+
+ if (!data)
+ return 0;
+
+ rc = safe_parse_mount_options(data, &opts);
+ if (!rc)
+ rc = opts.newinstance;
+
+ return rc;
+}
+
+/*
+ * get_init_pts_sb()
+ *
+ * This interface is needed to support multiple namespace semantics in
+ * devpts while preserving backward compatibility of the current 'single-
+ * namespace' semantics. i.e all mounts of devpts without the 'newinstance'
+ * mount option should bind to the initial kernel mount, like
+ * get_sb_single().
+ *
+ * Mounts with 'newinstance' option create a new private namespace.
+ *
+ * But for single-mount semantics, devpts cannot use get_sb_single(),
+ * because get_sb_single()/sget() find and use the super-block from
+ * the most recent mount of devpts. But that recent mount may be a
+ * 'newinstance' mount and get_sb_single() would pick the newinstance
+ * super-block instead of the initial super-block.
+ *
+ * This interface is identical to get_sb_single() except that it
+ * consistently selects the 'single-namespace' superblock even in the
+ * presence of the private namespace (i.e 'newinstance') super-blocks.
+ */
+static int get_init_pts_sb(struct file_system_type *fs_type, int flags,
+ void *data, struct vfsmount *mnt)
+{
+ struct super_block *s;
+ int error;
+
+ s = sget(fs_type, compare_init_pts_sb, set_anon_super, NULL);
+ if (IS_ERR(s))
+ return PTR_ERR(s);
+
+ if (!s->s_root) {
+ s->s_flags = flags;
+ error = devpts_fill_super(s, data, flags & MS_SILENT ? 1 : 0);
+ if (error) {
+ up_write(&s->s_umount);
+ deactivate_super(s);
+ return error;
+ }
+ s->s_flags |= MS_ACTIVE;
+ }
+ do_remount_sb(s, flags, data, 0);
+ return simple_set_mnt(mnt, s);
+}
+
+/*
+ * Mount or remount the initial kernel mount of devpts. This type of
+ * mount maintains the legacy, single-instance semantics, while the
+ * kernel still allows multiple-instances.
+ */
+static int init_pts_mount(struct file_system_type *fs_type, int flags,
+ void *data, struct vfsmount *mnt)
+{
+ int err;
+
+ err = get_init_pts_sb(fs_type, flags, data, mnt);
+ if (err)
+ return err;
+
+ err = mknod_ptmx(mnt->mnt_sb);
+ if (err) {
+ dput(mnt->mnt_sb->s_root);
+ deactivate_super(mnt->mnt_sb);
+ }
+
+ return err;
+}
+
static int devpts_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
+ int new;
+
+ new = is_new_instance_mount(data);
+ if (new < 0)
+ return new;
+
+ if (new)
+ return new_pts_mount(fs_type, flags, data, mnt);
+
+ return init_pts_mount(fs_type, flags, data, mnt);
+}
+#else
+/*
+ * This supports only the legacy single-instance semantics (no
+ * multiple-instance semantics)
+ */
+static int devpts_get_sb(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data, struct vfsmount *mnt)
+{
return get_sb_single(fs_type, flags, data, devpts_fill_super, mnt);
}
+#endif
+
+static void devpts_kill_sb(struct super_block *sb)
+{
+ struct pts_fs_info *fsi = DEVPTS_SB(sb);
+
+ kfree(fsi);
+ kill_litter_super(sb);
+}
static struct file_system_type devpts_fs_type = {
.owner = THIS_MODULE,
.name = "devpts",
.get_sb = devpts_get_sb,
- .kill_sb = kill_anon_super,
+ .kill_sb = devpts_kill_sb,
};
/*
@@ -172,16 +536,17 @@ static struct file_system_type devpts_fs_type = {
int devpts_new_index(struct inode *ptmx_inode)
{
+ struct super_block *sb = pts_sb_from_inode(ptmx_inode);
+ struct pts_fs_info *fsi = DEVPTS_SB(sb);
int index;
int ida_ret;
retry:
- if (!ida_pre_get(&allocated_ptys, GFP_KERNEL)) {
+ if (!ida_pre_get(&fsi->allocated_ptys, GFP_KERNEL))
return -ENOMEM;
- }
mutex_lock(&allocated_ptys_lock);
- ida_ret = ida_get_new(&allocated_ptys, &index);
+ ida_ret = ida_get_new(&fsi->allocated_ptys, &index);
if (ida_ret < 0) {
mutex_unlock(&allocated_ptys_lock);
if (ida_ret == -EAGAIN)
@@ -190,7 +555,7 @@ retry:
}
if (index >= pty_limit) {
- ida_remove(&allocated_ptys, index);
+ ida_remove(&fsi->allocated_ptys, index);
mutex_unlock(&allocated_ptys_lock);
return -EIO;
}
@@ -200,18 +565,26 @@ retry:
void devpts_kill_index(struct inode *ptmx_inode, int idx)
{
+ struct super_block *sb = pts_sb_from_inode(ptmx_inode);
+ struct pts_fs_info *fsi = DEVPTS_SB(sb);
+
mutex_lock(&allocated_ptys_lock);
- ida_remove(&allocated_ptys, idx);
+ ida_remove(&fsi->allocated_ptys, idx);
mutex_unlock(&allocated_ptys_lock);
}
int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty)
{
- int number = tty->index; /* tty layer puts index from devpts_new_index() in here */
+ /* tty layer puts index from devpts_new_index() in here */
+ int number = tty->index;
struct tty_driver *driver = tty->driver;
dev_t device = MKDEV(driver->major, driver->minor_start+number);
struct dentry *dentry;
- struct inode *inode = new_inode(devpts_mnt->mnt_sb);
+ struct super_block *sb = pts_sb_from_inode(ptmx_inode);
+ struct inode *inode = new_inode(sb);
+ struct dentry *root = sb->s_root;
+ struct pts_fs_info *fsi = DEVPTS_SB(sb);
+ struct pts_mount_opts *opts = &fsi->mount_opts;
char s[12];
/* We're supposed to be given the slave end of a pty */
@@ -221,25 +594,25 @@ int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty)
if (!inode)
return -ENOMEM;
- inode->i_ino = number+2;
- inode->i_uid = config.setuid ? config.uid : current->fsuid;
- inode->i_gid = config.setgid ? config.gid : current->fsgid;
+ inode->i_ino = number + 3;
+ inode->i_uid = opts->setuid ? opts->uid : current_fsuid();
+ inode->i_gid = opts->setgid ? opts->gid : current_fsgid();
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
- init_special_inode(inode, S_IFCHR|config.mode, device);
+ init_special_inode(inode, S_IFCHR|opts->mode, device);
inode->i_private = tty;
tty->driver_data = inode;
sprintf(s, "%d", number);
- mutex_lock(&devpts_root->d_inode->i_mutex);
+ mutex_lock(&root->d_inode->i_mutex);
- dentry = d_alloc_name(devpts_root, s);
+ dentry = d_alloc_name(root, s);
if (!IS_ERR(dentry)) {
d_add(dentry, inode);
- fsnotify_create(devpts_root->d_inode, dentry);
+ fsnotify_create(root->d_inode, dentry);
}
- mutex_unlock(&devpts_root->d_inode->i_mutex);
+ mutex_unlock(&root->d_inode->i_mutex);
return 0;
}
@@ -256,20 +629,27 @@ struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number)
void devpts_pty_kill(struct tty_struct *tty)
{
struct inode *inode = tty->driver_data;
+ struct super_block *sb = pts_sb_from_inode(inode);
+ struct dentry *root = sb->s_root;
struct dentry *dentry;
BUG_ON(inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR));
- mutex_lock(&devpts_root->d_inode->i_mutex);
+ mutex_lock(&root->d_inode->i_mutex);
dentry = d_find_alias(inode);
- if (dentry && !IS_ERR(dentry)) {
+ if (IS_ERR(dentry))
+ goto out;
+
+ if (dentry) {
inode->i_nlink--;
d_delete(dentry);
- dput(dentry);
+ dput(dentry); /* d_alloc_name() in devpts_pty_new() */
}
- mutex_unlock(&devpts_root->d_inode->i_mutex);
+ dput(dentry); /* d_find_alias above */
+out:
+ mutex_unlock(&root->d_inode->i_mutex);
}
static int __init init_devpts_fs(void)
diff --git a/fs/dlm/netlink.c b/fs/dlm/netlink.c
index 18bda83cc89..aa2a5775a02 100644
--- a/fs/dlm/netlink.c
+++ b/fs/dlm/netlink.c
@@ -127,8 +127,8 @@ static void fill_data(struct dlm_lock_data *data, struct dlm_lkb *lkb)
void dlm_timeout_warn(struct dlm_lkb *lkb)
{
+ struct sk_buff *uninitialized_var(send_skb);
struct dlm_lock_data *data;
- struct sk_buff *send_skb;
size_t size;
int rv;
diff --git a/fs/dquot.c b/fs/dquot.c
index 5e95261005b..c237ccc8581 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -874,7 +874,7 @@ static inline int need_print_warning(struct dquot *dquot)
switch (dquot->dq_type) {
case USRQUOTA:
- return current->fsuid == dquot->dq_id;
+ return current_fsuid() == dquot->dq_id;
case GRPQUOTA:
return in_group_p(dquot->dq_id);
}
@@ -981,7 +981,7 @@ static void send_warning(const struct dquot *dquot, const char warntype)
MINOR(dquot->dq_sb->s_dev));
if (ret)
goto attr_err_out;
- ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, current->user->uid);
+ ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, current_uid());
if (ret)
goto attr_err_out;
genlmsg_end(skb, msg_head);
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index 3504cf9df35..a75026d35d1 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -691,7 +691,8 @@ int ecryptfs_init_kthread(void);
void ecryptfs_destroy_kthread(void);
int ecryptfs_privileged_open(struct file **lower_file,
struct dentry *lower_dentry,
- struct vfsmount *lower_mnt);
+ struct vfsmount *lower_mnt,
+ const struct cred *cred);
int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry);
#endif /* #ifndef ECRYPTFS_KERNEL_H */
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 89209f00f9c..5e78fc17988 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -673,10 +673,11 @@ static void *ecryptfs_follow_link(struct dentry *dentry, struct nameidata *nd)
ecryptfs_printk(KERN_DEBUG, "Calling readlink w/ "
"dentry->d_name.name = [%s]\n", dentry->d_name.name);
rc = dentry->d_inode->i_op->readlink(dentry, (char __user *)buf, len);
- buf[rc] = '\0';
set_fs(old_fs);
if (rc < 0)
goto out_free;
+ else
+ buf[rc] = '\0';
rc = 0;
nd_set_link(nd, buf);
goto out;
diff --git a/fs/ecryptfs/kthread.c b/fs/ecryptfs/kthread.c
index c440c6b58b2..c6d7a4d748a 100644
--- a/fs/ecryptfs/kthread.c
+++ b/fs/ecryptfs/kthread.c
@@ -73,7 +73,7 @@ static int ecryptfs_threadfn(void *ignored)
mntget(req->lower_mnt);
(*req->lower_file) = dentry_open(
req->lower_dentry, req->lower_mnt,
- (O_RDWR | O_LARGEFILE));
+ (O_RDWR | O_LARGEFILE), current_cred());
req->flags |= ECRYPTFS_REQ_PROCESSED;
}
wake_up(&req->wait);
@@ -132,7 +132,8 @@ void ecryptfs_destroy_kthread(void)
*/
int ecryptfs_privileged_open(struct file **lower_file,
struct dentry *lower_dentry,
- struct vfsmount *lower_mnt)
+ struct vfsmount *lower_mnt,
+ const struct cred *cred)
{
struct ecryptfs_open_req *req;
int rc = 0;
@@ -143,7 +144,7 @@ int ecryptfs_privileged_open(struct file **lower_file,
dget(lower_dentry);
mntget(lower_mnt);
(*lower_file) = dentry_open(lower_dentry, lower_mnt,
- (O_RDWR | O_LARGEFILE));
+ (O_RDWR | O_LARGEFILE), cred);
if (!IS_ERR(*lower_file))
goto out;
req = kmem_cache_alloc(ecryptfs_open_req_cache, GFP_KERNEL);
@@ -184,7 +185,7 @@ int ecryptfs_privileged_open(struct file **lower_file,
dget(lower_dentry);
mntget(lower_mnt);
(*lower_file) = dentry_open(lower_dentry, lower_mnt,
- (O_RDONLY | O_LARGEFILE));
+ (O_RDONLY | O_LARGEFILE), cred);
if (IS_ERR(*lower_file)) {
rc = PTR_ERR(*req->lower_file);
(*lower_file) = NULL;
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index 64d2ba980df..fd630713c5c 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -115,6 +115,7 @@ void __ecryptfs_printk(const char *fmt, ...)
*/
int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry)
{
+ const struct cred *cred = current_cred();
struct ecryptfs_inode_info *inode_info =
ecryptfs_inode_to_private(ecryptfs_dentry->d_inode);
int rc = 0;
@@ -127,7 +128,7 @@ int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry)
lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
rc = ecryptfs_privileged_open(&inode_info->lower_file,
- lower_dentry, lower_mnt);
+ lower_dentry, lower_mnt, cred);
if (rc || IS_ERR(inode_info->lower_file)) {
printk(KERN_ERR "Error opening lower persistent file "
"for lower_dentry [0x%p] and lower_mnt [0x%p]; "
diff --git a/fs/ecryptfs/messaging.c b/fs/ecryptfs/messaging.c
index c6983978a31..6913f727624 100644
--- a/fs/ecryptfs/messaging.c
+++ b/fs/ecryptfs/messaging.c
@@ -360,7 +360,8 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,
struct ecryptfs_msg_ctx *msg_ctx;
size_t msg_size;
struct nsproxy *nsproxy;
- struct user_namespace *current_user_ns;
+ struct user_namespace *tsk_user_ns;
+ uid_t ctx_euid;
int rc;
if (msg->index >= ecryptfs_message_buf_len) {
@@ -384,9 +385,9 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,
mutex_unlock(&ecryptfs_daemon_hash_mux);
goto wake_up;
}
- current_user_ns = nsproxy->user_ns;
- rc = ecryptfs_find_daemon_by_euid(&daemon, msg_ctx->task->euid,
- current_user_ns);
+ tsk_user_ns = __task_cred(msg_ctx->task)->user->user_ns;
+ ctx_euid = task_euid(msg_ctx->task);
+ rc = ecryptfs_find_daemon_by_euid(&daemon, ctx_euid, tsk_user_ns);
rcu_read_unlock();
mutex_unlock(&ecryptfs_daemon_hash_mux);
if (rc) {
@@ -394,28 +395,28 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,
printk(KERN_WARNING "%s: User [%d] received a "
"message response from process [0x%p] but does "
"not have a registered daemon\n", __func__,
- msg_ctx->task->euid, pid);
+ ctx_euid, pid);
goto wake_up;
}
- if (msg_ctx->task->euid != euid) {
+ if (ctx_euid != euid) {
rc = -EBADMSG;
printk(KERN_WARNING "%s: Received message from user "
"[%d]; expected message from user [%d]\n", __func__,
- euid, msg_ctx->task->euid);
+ euid, ctx_euid);
goto unlock;
}
- if (current_user_ns != user_ns) {
+ if (tsk_user_ns != user_ns) {
rc = -EBADMSG;
printk(KERN_WARNING "%s: Received message from user_ns "
"[0x%p]; expected message from user_ns [0x%p]\n",
- __func__, user_ns, nsproxy->user_ns);
+ __func__, user_ns, tsk_user_ns);
goto unlock;
}
if (daemon->pid != pid) {
rc = -EBADMSG;
printk(KERN_ERR "%s: User [%d] sent a message response "
"from an unrecognized process [0x%p]\n",
- __func__, msg_ctx->task->euid, pid);
+ __func__, ctx_euid, pid);
goto unlock;
}
if (msg_ctx->state != ECRYPTFS_MSG_CTX_STATE_PENDING) {
@@ -464,14 +465,14 @@ ecryptfs_send_message_locked(char *data, int data_len, u8 msg_type,
struct ecryptfs_msg_ctx **msg_ctx)
{
struct ecryptfs_daemon *daemon;
+ uid_t euid = current_euid();
int rc;
- rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid,
- current->nsproxy->user_ns);
+ rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
if (rc || !daemon) {
rc = -ENOTCONN;
printk(KERN_ERR "%s: User [%d] does not have a daemon "
- "registered\n", __func__, current->euid);
+ "registered\n", __func__, euid);
goto out;
}
mutex_lock(&ecryptfs_msg_ctx_lists_mux);
diff --git a/fs/ecryptfs/miscdev.c b/fs/ecryptfs/miscdev.c
index b484792a099..efd95a0ed1e 100644
--- a/fs/ecryptfs/miscdev.c
+++ b/fs/ecryptfs/miscdev.c
@@ -42,12 +42,12 @@ ecryptfs_miscdev_poll(struct file *file, poll_table *pt)
{
struct ecryptfs_daemon *daemon;
unsigned int mask = 0;
+ uid_t euid = current_euid();
int rc;
mutex_lock(&ecryptfs_daemon_hash_mux);
/* TODO: Just use file->private_data? */
- rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid,
- current->nsproxy->user_ns);
+ rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
BUG_ON(rc || !daemon);
mutex_lock(&daemon->mux);
mutex_unlock(&ecryptfs_daemon_hash_mux);
@@ -83,6 +83,7 @@ static int
ecryptfs_miscdev_open(struct inode *inode, struct file *file)
{
struct ecryptfs_daemon *daemon = NULL;
+ uid_t euid = current_euid();
int rc;
mutex_lock(&ecryptfs_daemon_hash_mux);
@@ -93,11 +94,9 @@ ecryptfs_miscdev_open(struct inode *inode, struct file *file)
"count; rc = [%d]\n", __func__, rc);
goto out_unlock_daemon_list;
}
- rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid,
- current->nsproxy->user_ns);
+ rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
if (rc || !daemon) {
- rc = ecryptfs_spawn_daemon(&daemon, current->euid,
- current->nsproxy->user_ns,
+ rc = ecryptfs_spawn_daemon(&daemon, euid, current_user_ns(),
task_pid(current));
if (rc) {
printk(KERN_ERR "%s: Error attempting to spawn daemon; "
@@ -147,11 +146,11 @@ static int
ecryptfs_miscdev_release(struct inode *inode, struct file *file)
{
struct ecryptfs_daemon *daemon = NULL;
+ uid_t euid = current_euid();
int rc;
mutex_lock(&ecryptfs_daemon_hash_mux);
- rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid,
- current->nsproxy->user_ns);
+ rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
BUG_ON(rc || !daemon);
mutex_lock(&daemon->mux);
BUG_ON(daemon->pid != task_pid(current));
@@ -246,12 +245,12 @@ ecryptfs_miscdev_read(struct file *file, char __user *buf, size_t count,
char packet_length[3];
size_t i;
size_t total_length;
+ uid_t euid = current_euid();
int rc;
mutex_lock(&ecryptfs_daemon_hash_mux);
/* TODO: Just use file->private_data? */
- rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid,
- current->nsproxy->user_ns);
+ rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
BUG_ON(rc || !daemon);
mutex_lock(&daemon->mux);
if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
@@ -290,8 +289,8 @@ check_list:
* message from the queue; try again */
goto check_list;
}
- BUG_ON(current->euid != daemon->euid);
- BUG_ON(current->nsproxy->user_ns != daemon->user_ns);
+ BUG_ON(euid != daemon->euid);
+ BUG_ON(current_user_ns() != daemon->user_ns);
BUG_ON(task_pid(current) != daemon->pid);
msg_ctx = list_first_entry(&daemon->msg_ctx_out_queue,
struct ecryptfs_msg_ctx, daemon_out_list);
@@ -414,6 +413,7 @@ ecryptfs_miscdev_write(struct file *file, const char __user *buf,
size_t packet_size, packet_size_length, i;
ssize_t sz = 0;
char *data;
+ uid_t euid = current_euid();
int rc;
if (count == 0)
@@ -463,8 +463,7 @@ ecryptfs_miscdev_write(struct file *file, const char __user *buf,
goto out_free;
}
rc = ecryptfs_miscdev_response(&data[i], packet_size,
- current->euid,
- current->nsproxy->user_ns,
+ euid, current_user_ns(),
task_pid(current), seq);
if (rc)
printk(KERN_WARNING "%s: Failed to deliver miscdev "
diff --git a/fs/exec.c b/fs/exec.c
index 4e834f16d9d..dfbf7009fbe 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -55,6 +55,7 @@
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
#include <asm/tlb.h>
+#include "internal.h"
#ifdef __alpha__
/* for /sbin/loader handling in search_binary_handler() */
@@ -126,7 +127,8 @@ asmlinkage long sys_uselib(const char __user * library)
if (nd.path.mnt->mnt_flags & MNT_NOEXEC)
goto exit;
- error = vfs_permission(&nd, MAY_READ | MAY_EXEC | MAY_OPEN);
+ error = inode_permission(nd.path.dentry->d_inode,
+ MAY_READ | MAY_EXEC | MAY_OPEN);
if (error)
goto exit;
@@ -679,7 +681,7 @@ struct file *open_exec(const char *name)
if (nd.path.mnt->mnt_flags & MNT_NOEXEC)
goto out_path_put;
- err = vfs_permission(&nd, MAY_EXEC | MAY_OPEN);
+ err = inode_permission(nd.path.dentry->d_inode, MAY_EXEC | MAY_OPEN);
if (err)
goto out_path_put;
@@ -772,7 +774,6 @@ static int de_thread(struct task_struct *tsk)
struct signal_struct *sig = tsk->signal;
struct sighand_struct *oldsighand = tsk->sighand;
spinlock_t *lock = &oldsighand->siglock;
- struct task_struct *leader = NULL;
int count;
if (thread_group_empty(tsk))
@@ -810,7 +811,7 @@ static int de_thread(struct task_struct *tsk)
* and to assume its PID:
*/
if (!thread_group_leader(tsk)) {
- leader = tsk->group_leader;
+ struct task_struct *leader = tsk->group_leader;
sig->notify_count = -1; /* for exit_notify() */
for (;;) {
@@ -862,8 +863,9 @@ static int de_thread(struct task_struct *tsk)
BUG_ON(leader->exit_state != EXIT_ZOMBIE);
leader->exit_state = EXIT_DEAD;
-
write_unlock_irq(&tasklist_lock);
+
+ release_task(leader);
}
sig->group_exit_task = NULL;
@@ -872,8 +874,6 @@ static int de_thread(struct task_struct *tsk)
no_thread_group:
exit_itimers(sig);
flush_itimer_signals();
- if (leader)
- release_task(leader);
if (atomic_read(&oldsighand->count) != 1) {
struct sighand_struct *newsighand;
@@ -980,7 +980,7 @@ int flush_old_exec(struct linux_binprm * bprm)
/* This is the point of no return */
current->sas_ss_sp = current->sas_ss_size = 0;
- if (current->euid == current->uid && current->egid == current->gid)
+ if (current_euid() == current_uid() && current_egid() == current_gid())
set_dumpable(current->mm, 1);
else
set_dumpable(current->mm, suid_dumpable);
@@ -1007,16 +1007,17 @@ int flush_old_exec(struct linux_binprm * bprm)
*/
current->mm->task_size = TASK_SIZE;
- if (bprm->e_uid != current->euid || bprm->e_gid != current->egid) {
- suid_keys(current);
- set_dumpable(current->mm, suid_dumpable);
+ /* install the new credentials */
+ if (bprm->cred->uid != current_euid() ||
+ bprm->cred->gid != current_egid()) {
current->pdeath_signal = 0;
} else if (file_permission(bprm->file, MAY_READ) ||
- (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) {
- suid_keys(current);
+ bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP) {
set_dumpable(current->mm, suid_dumpable);
}
+ current->personality &= ~bprm->per_clear;
+
/* An exec changes our domain. We are no longer part of the thread
group */
@@ -1033,13 +1034,50 @@ out:
EXPORT_SYMBOL(flush_old_exec);
+/*
+ * install the new credentials for this executable
+ */
+void install_exec_creds(struct linux_binprm *bprm)
+{
+ security_bprm_committing_creds(bprm);
+
+ commit_creds(bprm->cred);
+ bprm->cred = NULL;
+
+ /* cred_exec_mutex must be held at least to this point to prevent
+ * ptrace_attach() from altering our determination of the task's
+ * credentials; any time after this it may be unlocked */
+
+ security_bprm_committed_creds(bprm);
+}
+EXPORT_SYMBOL(install_exec_creds);
+
+/*
+ * determine how safe it is to execute the proposed program
+ * - the caller must hold current->cred_exec_mutex to protect against
+ * PTRACE_ATTACH
+ */
+void check_unsafe_exec(struct linux_binprm *bprm)
+{
+ struct task_struct *p = current;
+
+ bprm->unsafe = tracehook_unsafe_exec(p);
+
+ if (atomic_read(&p->fs->count) > 1 ||
+ atomic_read(&p->files->count) > 1 ||
+ atomic_read(&p->sighand->count) > 1)
+ bprm->unsafe |= LSM_UNSAFE_SHARE;
+}
+
/*
* Fill the binprm structure from the inode.
* Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes
+ *
+ * This may be called multiple times for binary chains (scripts for example).
*/
int prepare_binprm(struct linux_binprm *bprm)
{
- int mode;
+ umode_t mode;
struct inode * inode = bprm->file->f_path.dentry->d_inode;
int retval;
@@ -1047,14 +1085,15 @@ int prepare_binprm(struct linux_binprm *bprm)
if (bprm->file->f_op == NULL)
return -EACCES;
- bprm->e_uid = current->euid;
- bprm->e_gid = current->egid;
+ /* clear any previous set[ug]id data from a previous binary */
+ bprm->cred->euid = current_euid();
+ bprm->cred->egid = current_egid();
- if(!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) {
+ if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) {
/* Set-uid? */
if (mode & S_ISUID) {
- current->personality &= ~PER_CLEAR_ON_SETID;
- bprm->e_uid = inode->i_uid;
+ bprm->per_clear |= PER_CLEAR_ON_SETID;
+ bprm->cred->euid = inode->i_uid;
}
/* Set-gid? */
@@ -1064,52 +1103,23 @@ int prepare_binprm(struct linux_binprm *bprm)
* executable.
*/
if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
- current->personality &= ~PER_CLEAR_ON_SETID;
- bprm->e_gid = inode->i_gid;
+ bprm->per_clear |= PER_CLEAR_ON_SETID;
+ bprm->cred->egid = inode->i_gid;
}
}
/* fill in binprm security blob */
- retval = security_bprm_set(bprm);
+ retval = security_bprm_set_creds(bprm);
if (retval)
return retval;
+ bprm->cred_prepared = 1;
- memset(bprm->buf,0,BINPRM_BUF_SIZE);
- return kernel_read(bprm->file,0,bprm->buf,BINPRM_BUF_SIZE);
+ memset(bprm->buf, 0, BINPRM_BUF_SIZE);
+ return kernel_read(bprm->file, 0, bprm->buf, BINPRM_BUF_SIZE);
}
EXPORT_SYMBOL(prepare_binprm);
-static int unsafe_exec(struct task_struct *p)
-{
- int unsafe = tracehook_unsafe_exec(p);
-
- if (atomic_read(&p->fs->count) > 1 ||
- atomic_read(&p->files->count) > 1 ||
- atomic_read(&p->sighand->count) > 1)
- unsafe |= LSM_UNSAFE_SHARE;
-
- return unsafe;
-}
-
-void compute_creds(struct linux_binprm *bprm)
-{
- int unsafe;
-
- if (bprm->e_uid != current->uid) {
- suid_keys(current);
- current->pdeath_signal = 0;
- }
- exec_keys(current);
-
- task_lock(current);
- unsafe = unsafe_exec(current);
- security_bprm_apply_creds(bprm, unsafe);
- task_unlock(current);
- security_bprm_post_apply_creds(bprm);
-}
-EXPORT_SYMBOL(compute_creds);
-
/*
* Arguments are '\0' separated strings found at the location bprm->p
* points to; chop off the first by relocating brpm->p to right after
@@ -1159,6 +1169,7 @@ EXPORT_SYMBOL(remove_arg_zero);
*/
int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
{
+ unsigned int depth = bprm->recursion_depth;
int try,retval;
struct linux_binfmt *fmt;
#ifdef __alpha__
@@ -1219,8 +1230,15 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
continue;
read_unlock(&binfmt_lock);
retval = fn(bprm, regs);
+ /*
+ * Restore the depth counter to its starting value
+ * in this call, so we don't have to rely on every
+ * load_binary function to restore it on return.
+ */
+ bprm->recursion_depth = depth;
if (retval >= 0) {
- tracehook_report_exec(fmt, bprm, regs);
+ if (depth == 0)
+ tracehook_report_exec(fmt, bprm, regs);
put_binfmt(fmt);
allow_write_access(bprm->file);
if (bprm->file)
@@ -1262,6 +1280,8 @@ EXPORT_SYMBOL(search_binary_handler);
void free_bprm(struct linux_binprm *bprm)
{
free_arg_pages(bprm);
+ if (bprm->cred)
+ abort_creds(bprm->cred);
kfree(bprm);
}
@@ -1287,10 +1307,20 @@ int do_execve(char * filename,
if (!bprm)
goto out_files;
+ retval = mutex_lock_interruptible(&current->cred_exec_mutex);
+ if (retval < 0)
+ goto out_free;
+
+ retval = -ENOMEM;
+ bprm->cred = prepare_exec_creds();
+ if (!bprm->cred)
+ goto out_unlock;
+ check_unsafe_exec(bprm);
+
file = open_exec(filename);
retval = PTR_ERR(file);
if (IS_ERR(file))
- goto out_kfree;
+ goto out_unlock;
sched_exec();
@@ -1304,14 +1334,10 @@ int do_execve(char * filename,
bprm->argc = count(argv, MAX_ARG_STRINGS);
if ((retval = bprm->argc) < 0)
- goto out_mm;
+ goto out;
bprm->envc = count(envp, MAX_ARG_STRINGS);
if ((retval = bprm->envc) < 0)
- goto out_mm;
-
- retval = security_bprm_alloc(bprm);
- if (retval)
goto out;
retval = prepare_binprm(bprm);
@@ -1333,21 +1359,18 @@ int do_execve(char * filename,
current->flags &= ~PF_KTHREAD;
retval = search_binary_handler(bprm,regs);
- if (retval >= 0) {
- /* execve success */
- security_bprm_free(bprm);
- acct_update_integrals(current);
- free_bprm(bprm);
- if (displaced)
- put_files_struct(displaced);
- return retval;
- }
+ if (retval < 0)
+ goto out;
-out:
- if (bprm->security)
- security_bprm_free(bprm);
+ /* execve succeeded */
+ mutex_unlock(&current->cred_exec_mutex);
+ acct_update_integrals(current);
+ free_bprm(bprm);
+ if (displaced)
+ put_files_struct(displaced);
+ return retval;
-out_mm:
+out:
if (bprm->mm)
mmput (bprm->mm);
@@ -1356,7 +1379,11 @@ out_file:
allow_write_access(bprm->file);
fput(bprm->file);
}
-out_kfree:
+
+out_unlock:
+ mutex_unlock(&current->cred_exec_mutex);
+
+out_free:
free_bprm(bprm);
out_files:
@@ -1388,6 +1415,7 @@ EXPORT_SYMBOL(set_binfmt);
*/
static int format_corename(char *corename, long signr)
{
+ const struct cred *cred = current_cred();
const char *pat_ptr = core_pattern;
int ispipe = (*pat_ptr == '|');
char *out_ptr = corename;
@@ -1424,7 +1452,7 @@ static int format_corename(char *corename, long signr)
/* uid */
case 'u':
rc = snprintf(out_ptr, out_end - out_ptr,
- "%d", current->uid);
+ "%d", cred->uid);
if (rc > out_end - out_ptr)
goto out;
out_ptr += rc;
@@ -1432,7 +1460,7 @@ static int format_corename(char *corename, long signr)
/* gid */
case 'g':
rc = snprintf(out_ptr, out_end - out_ptr,
- "%d", current->gid);
+ "%d", cred->gid);
if (rc > out_end - out_ptr)
goto out;
out_ptr += rc;
@@ -1708,8 +1736,9 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
struct linux_binfmt * binfmt;
struct inode * inode;
struct file * file;
+ const struct cred *old_cred;
+ struct cred *cred;
int retval = 0;
- int fsuid = current->fsuid;
int flag = 0;
int ispipe = 0;
unsigned long core_limit = current->signal->rlim[RLIMIT_CORE].rlim_cur;
@@ -1722,12 +1751,20 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
binfmt = current->binfmt;
if (!binfmt || !binfmt->core_dump)
goto fail;
+
+ cred = prepare_creds();
+ if (!cred) {
+ retval = -ENOMEM;
+ goto fail;
+ }
+
down_write(&mm->mmap_sem);
/*
* If another thread got here first, or we are not dumpable, bail out.
*/
if (mm->core_state || !get_dumpable(mm)) {
up_write(&mm->mmap_sem);
+ put_cred(cred);
goto fail;
}
@@ -1738,12 +1775,16 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
*/
if (get_dumpable(mm) == 2) { /* Setuid core dump mode */
flag = O_EXCL; /* Stop rewrite attacks */
- current->fsuid = 0; /* Dump root private */
+ cred->fsuid = 0; /* Dump root private */
}
retval = coredump_wait(exit_code, &core_state);
- if (retval < 0)
+ if (retval < 0) {
+ put_cred(cred);
goto fail;
+ }
+
+ old_cred = override_creds(cred);
/*
* Clear any false indication of pending signals that might
@@ -1815,7 +1856,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
* Dont allow local users get cute and trick others to coredump
* into their pre-created files:
*/
- if (inode->i_uid != current->fsuid)
+ if (inode->i_uid != current_fsuid())
goto close_fail;
if (!file->f_op)
goto close_fail;
@@ -1834,7 +1875,8 @@ fail_unlock:
if (helper_argv)
argv_free(helper_argv);
- current->fsuid = fsuid;
+ revert_creds(old_cred);
+ put_cred(cred);
coredump_finish(mm);
fail:
return retval;
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index 80246bad1b7..197c7db583c 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/mount.h>
#include <linux/namei.h>
+#include <linux/sched.h>
#define dprintk(fmt, args...) do{}while(0)
@@ -249,6 +250,7 @@ static int filldir_one(void * __buf, const char * name, int len,
static int get_name(struct vfsmount *mnt, struct dentry *dentry,
char *name, struct dentry *child)
{
+ const struct cred *cred = current_cred();
struct inode *dir = dentry->d_inode;
int error;
struct file *file;
@@ -263,7 +265,7 @@ static int get_name(struct vfsmount *mnt, struct dentry *dentry,
/*
* Open the directory ...
*/
- file = dentry_open(dget(dentry), mntget(mnt), O_RDONLY);
+ file = dentry_open(dget(dentry), mntget(mnt), O_RDONLY, cred);
error = PTR_ERR(file);
if (IS_ERR(file))
goto out;
@@ -367,6 +369,8 @@ struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
* Try to get any dentry for the given file handle from the filesystem.
*/
result = nop->fh_to_dentry(mnt->mnt_sb, fid, fh_len, fileid_type);
+ if (!result)
+ result = ERR_PTR(-ESTALE);
if (IS_ERR(result))
return result;
@@ -420,6 +424,8 @@ struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
target_dir = nop->fh_to_parent(mnt->mnt_sb, fid,
fh_len, fileid_type);
+ if (!target_dir)
+ goto err_result;
err = PTR_ERR(target_dir);
if (IS_ERR(target_dir))
goto err_result;
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index 6dac7ba2d22..4a29d637608 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -1193,7 +1193,7 @@ static int ext2_has_free_blocks(struct ext2_sb_info *sbi)
free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count);
if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) &&
- sbi->s_resuid != current->fsuid &&
+ sbi->s_resuid != current_fsuid() &&
(sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) {
return 0;
}
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index f5974134676..c454d5db28a 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -550,7 +550,7 @@ got:
sb->s_dirt = 1;
mark_buffer_dirty(bh2);
- inode->i_uid = current->fsuid;
+ inode->i_uid = current_fsuid();
if (test_opt (sb, GRPID))
inode->i_gid = dir->i_gid;
else if (dir->i_mode & S_ISGID) {
@@ -558,7 +558,7 @@ got:
if (S_ISDIR(mode))
mode |= S_ISGID;
} else
- inode->i_gid = current->fsgid;
+ inode->i_gid = current_fsgid();
inode->i_mode = mode;
inode->i_ino = ino;
@@ -585,7 +585,10 @@ got:
spin_lock(&sbi->s_next_gen_lock);
inode->i_generation = sbi->s_next_generation++;
spin_unlock(&sbi->s_next_gen_lock);
- insert_inode_hash(inode);
+ if (insert_inode_locked(inode) < 0) {
+ err = -EINVAL;
+ goto fail_drop;
+ }
if (DQUOT_ALLOC_INODE(inode)) {
err = -EDQUOT;
@@ -612,6 +615,7 @@ fail_drop:
DQUOT_DROP(inode);
inode->i_flags |= S_NOQUOTA;
inode->i_nlink = 0;
+ unlock_new_inode(inode);
iput(inode);
return ERR_PTR(err);
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 7658b33e265..02b39a5deb7 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -32,6 +32,7 @@
#include <linux/buffer_head.h>
#include <linux/mpage.h>
#include <linux/fiemap.h>
+#include <linux/namei.h>
#include "ext2.h"
#include "acl.h"
#include "xip.h"
@@ -1286,9 +1287,11 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino)
else
inode->i_mapping->a_ops = &ext2_aops;
} else if (S_ISLNK(inode->i_mode)) {
- if (ext2_inode_is_fast_symlink(inode))
+ if (ext2_inode_is_fast_symlink(inode)) {
inode->i_op = &ext2_fast_symlink_inode_operations;
- else {
+ nd_terminate_link(ei->i_data, inode->i_size,
+ sizeof(ei->i_data) - 1);
+ } else {
inode->i_op = &ext2_symlink_inode_operations;
if (test_opt(inode->i_sb, NOBH))
inode->i_mapping->a_ops = &ext2_nobh_aops;
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 2a747252ec1..90ea17998a7 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -41,9 +41,11 @@ static inline int ext2_add_nondir(struct dentry *dentry, struct inode *inode)
int err = ext2_add_link(dentry, inode);
if (!err) {
d_instantiate(dentry, inode);
+ unlock_new_inode(inode);
return 0;
}
inode_dec_link_count(inode);
+ unlock_new_inode(inode);
iput(inode);
return err;
}
@@ -170,6 +172,7 @@ out:
out_fail:
inode_dec_link_count(inode);
+ unlock_new_inode(inode);
iput (inode);
goto out;
}
@@ -178,6 +181,7 @@ static int ext2_link (struct dentry * old_dentry, struct inode * dir,
struct dentry *dentry)
{
struct inode *inode = old_dentry->d_inode;
+ int err;
if (inode->i_nlink >= EXT2_LINK_MAX)
return -EMLINK;
@@ -186,7 +190,14 @@ static int ext2_link (struct dentry * old_dentry, struct inode * dir,
inode_inc_link_count(inode);
atomic_inc(&inode->i_count);
- return ext2_add_nondir(dentry, inode);
+ err = ext2_add_link(dentry, inode);
+ if (!err) {
+ d_instantiate(dentry, inode);
+ return 0;
+ }
+ inode_dec_link_count(inode);
+ iput(inode);
+ return err;
}
static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
@@ -222,12 +233,14 @@ static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
goto out_fail;
d_instantiate(dentry, inode);
+ unlock_new_inode(inode);
out:
return err;
out_fail:
inode_dec_link_count(inode);
inode_dec_link_count(inode);
+ unlock_new_inode(inode);
iput(inode);
out_dir:
inode_dec_link_count(dir);
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c
index f5b57a2ca35..0dbf1c04847 100644
--- a/fs/ext3/balloc.c
+++ b/fs/ext3/balloc.c
@@ -1422,7 +1422,7 @@ static int ext3_has_free_blocks(struct ext3_sb_info *sbi)
free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count);
if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) &&
- sbi->s_resuid != current->fsuid &&
+ sbi->s_resuid != current_fsuid() &&
(sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) {
return 0;
}
diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
index 47b678d73e7..5655fbcbd11 100644
--- a/fs/ext3/ialloc.c
+++ b/fs/ext3/ialloc.c
@@ -539,7 +539,7 @@ got:
percpu_counter_inc(&sbi->s_dirs_counter);
sb->s_dirt = 1;
- inode->i_uid = current->fsuid;
+ inode->i_uid = current_fsuid();
if (test_opt (sb, GRPID))
inode->i_gid = dir->i_gid;
else if (dir->i_mode & S_ISGID) {
@@ -547,7 +547,7 @@ got:
if (S_ISDIR(mode))
mode |= S_ISGID;
} else
- inode->i_gid = current->fsgid;
+ inode->i_gid = current_fsgid();
inode->i_mode = mode;
inode->i_ino = ino;
@@ -579,7 +579,10 @@ got:
ext3_set_inode_flags(inode);
if (IS_DIRSYNC(inode))
handle->h_sync = 1;
- insert_inode_hash(inode);
+ if (insert_inode_locked(inode) < 0) {
+ err = -EINVAL;
+ goto fail_drop;
+ }
spin_lock(&sbi->s_next_gen_lock);
inode->i_generation = sbi->s_next_generation++;
spin_unlock(&sbi->s_next_gen_lock);
@@ -627,6 +630,7 @@ fail_drop:
DQUOT_DROP(inode);
inode->i_flags |= S_NOQUOTA;
inode->i_nlink = 0;
+ unlock_new_inode(inode);
iput(inode);
brelse(bitmap_bh);
return ERR_PTR(err);
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index f8424ad8997..c4bdccf976b 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -37,6 +37,7 @@
#include <linux/uio.h>
#include <linux/bio.h>
#include <linux/fiemap.h>
+#include <linux/namei.h>
#include "xattr.h"
#include "acl.h"
@@ -2817,9 +2818,11 @@ struct inode *ext3_iget(struct super_block *sb, unsigned long ino)
inode->i_op = &ext3_dir_inode_operations;
inode->i_fop = &ext3_dir_operations;
} else if (S_ISLNK(inode->i_mode)) {
- if (ext3_inode_is_fast_symlink(inode))
+ if (ext3_inode_is_fast_symlink(inode)) {
inode->i_op = &ext3_fast_symlink_inode_operations;
- else {
+ nd_terminate_link(ei->i_data, inode->i_size,
+ sizeof(ei->i_data) - 1);
+ } else {
inode->i_op = &ext3_symlink_inode_operations;
ext3_set_aops(inode);
}
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index 3e5edc92aa0..297ea8dfac7 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -1652,9 +1652,11 @@ static int ext3_add_nondir(handle_t *handle,
if (!err) {
ext3_mark_inode_dirty(handle, inode);
d_instantiate(dentry, inode);
+ unlock_new_inode(inode);
return 0;
}
drop_nlink(inode);
+ unlock_new_inode(inode);
iput(inode);
return err;
}
@@ -1765,6 +1767,7 @@ retry:
dir_block = ext3_bread (handle, inode, 0, 1, &err);
if (!dir_block) {
drop_nlink(inode); /* is this nlink == 0? */
+ unlock_new_inode(inode);
ext3_mark_inode_dirty(handle, inode);
iput (inode);
goto out_stop;
@@ -1792,6 +1795,7 @@ retry:
err = ext3_add_entry (handle, dentry, inode);
if (err) {
inode->i_nlink = 0;
+ unlock_new_inode(inode);
ext3_mark_inode_dirty(handle, inode);
iput (inode);
goto out_stop;
@@ -1800,6 +1804,7 @@ retry:
ext3_update_dx_flag(dir);
ext3_mark_inode_dirty(handle, dir);
d_instantiate(dentry, inode);
+ unlock_new_inode(inode);
out_stop:
ext3_journal_stop(handle);
if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))
@@ -2174,6 +2179,7 @@ retry:
mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS);
if (err) {
drop_nlink(inode);
+ unlock_new_inode(inode);
ext3_mark_inode_dirty(handle, inode);
iput (inode);
goto out_stop;
@@ -2221,7 +2227,14 @@ retry:
inc_nlink(inode);
atomic_inc(&inode->i_count);
- err = ext3_add_nondir(handle, dentry, inode);
+ err = ext3_add_entry(handle, dentry, inode);
+ if (!err) {
+ ext3_mark_inode_dirty(handle, inode);
+ d_instantiate(dentry, inode);
+ } else {
+ drop_nlink(inode);
+ iput(inode);
+ }
ext3_journal_stop(handle);
if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))
goto retry;
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index d2003cdc36a..38b3acf5683 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -609,8 +609,8 @@ int ext4_has_free_blocks(struct ext4_sb_info *sbi, s64 nblocks)
if (free_blocks - (nblocks + root_blocks + dirty_blocks) <
EXT4_FREEBLOCKS_WATERMARK) {
- free_blocks = percpu_counter_sum(fbc);
- dirty_blocks = percpu_counter_sum(dbc);
+ free_blocks = percpu_counter_sum_positive(fbc);
+ dirty_blocks = percpu_counter_sum_positive(dbc);
if (dirty_blocks < 0) {
printk(KERN_CRIT "Dirty block accounting "
"went wrong %lld\n",
@@ -624,7 +624,7 @@ int ext4_has_free_blocks(struct ext4_sb_info *sbi, s64 nblocks)
return 1;
/* Hm, nope. Are (enough) root reserved blocks available? */
- if (sbi->s_resuid == current->fsuid ||
+ if (sbi->s_resuid == current_fsuid() ||
((sbi->s_resgid != 0) && in_group_p(sbi->s_resgid)) ||
capable(CAP_SYS_RESOURCE)) {
if (free_blocks >= (nblocks + dirty_blocks))
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 2a117e286e5..6e6052879aa 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -787,7 +787,7 @@ got:
spin_unlock(sb_bgl_lock(sbi, flex_group));
}
- inode->i_uid = current->fsuid;
+ inode->i_uid = current_fsuid();
if (test_opt(sb, GRPID))
inode->i_gid = dir->i_gid;
else if (dir->i_mode & S_ISGID) {
@@ -795,7 +795,7 @@ got:
if (S_ISDIR(mode))
mode |= S_ISGID;
} else
- inode->i_gid = current->fsgid;
+ inode->i_gid = current_fsgid();
inode->i_mode = mode;
inode->i_ino = ino + group * EXT4_INODES_PER_GROUP(sb);
@@ -826,7 +826,10 @@ got:
ext4_set_inode_flags(inode);
if (IS_DIRSYNC(inode))
handle->h_sync = 1;
- insert_inode_hash(inode);
+ if (insert_inode_locked(inode) < 0) {
+ err = -EINVAL;
+ goto fail_drop;
+ }
spin_lock(&sbi->s_next_gen_lock);
inode->i_generation = sbi->s_next_generation++;
spin_unlock(&sbi->s_next_gen_lock);
@@ -881,6 +884,7 @@ fail_drop:
DQUOT_DROP(inode);
inode->i_flags |= S_NOQUOTA;
inode->i_nlink = 0;
+ unlock_new_inode(inode);
iput(inode);
brelse(bitmap_bh);
return ERR_PTR(err);
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index be21a5ae33c..7c3325e0b00 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -34,6 +34,7 @@
#include <linux/writeback.h>
#include <linux/pagevec.h>
#include <linux/mpage.h>
+#include <linux/namei.h>
#include <linux/uio.h>
#include <linux/bio.h>
#include "ext4_jbd2.h"
@@ -4164,9 +4165,11 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
inode->i_op = &ext4_dir_inode_operations;
inode->i_fop = &ext4_dir_operations;
} else if (S_ISLNK(inode->i_mode)) {
- if (ext4_inode_is_fast_symlink(inode))
+ if (ext4_inode_is_fast_symlink(inode)) {
inode->i_op = &ext4_fast_symlink_inode_operations;
- else {
+ nd_terminate_link(ei->i_data, inode->i_size,
+ sizeof(ei->i_data) - 1);
+ } else {
inode->i_op = &ext4_symlink_inode_operations;
ext4_set_aops(inode);
}
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 63adcb79298..da98a9012fa 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -1693,9 +1693,11 @@ static int ext4_add_nondir(handle_t *handle,
if (!err) {
ext4_mark_inode_dirty(handle, inode);
d_instantiate(dentry, inode);
+ unlock_new_inode(inode);
return 0;
}
drop_nlink(inode);
+ unlock_new_inode(inode);
iput(inode);
return err;
}
@@ -1830,6 +1832,7 @@ retry:
if (err) {
out_clear_inode:
clear_nlink(inode);
+ unlock_new_inode(inode);
ext4_mark_inode_dirty(handle, inode);
iput(inode);
goto out_stop;
@@ -1838,6 +1841,7 @@ out_clear_inode:
ext4_update_dx_flag(dir);
ext4_mark_inode_dirty(handle, dir);
d_instantiate(dentry, inode);
+ unlock_new_inode(inode);
out_stop:
ext4_journal_stop(handle);
if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
@@ -2212,6 +2216,7 @@ retry:
mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS);
if (err) {
clear_nlink(inode);
+ unlock_new_inode(inode);
ext4_mark_inode_dirty(handle, inode);
iput(inode);
goto out_stop;
@@ -2262,7 +2267,14 @@ retry:
ext4_inc_count(handle, inode);
atomic_inc(&inode->i_count);
- err = ext4_add_nondir(handle, dentry, inode);
+ err = ext4_add_entry(handle, dentry, inode);
+ if (!err) {
+ ext4_mark_inode_dirty(handle, inode);
+ d_instantiate(dentry, inode);
+ } else {
+ drop_nlink(inode);
+ iput(inode);
+ }
ext4_journal_stop(handle);
if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
goto retry;
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index e4a241c65db..04158ad74db 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1721,7 +1721,7 @@ static loff_t ext4_max_size(int blkbits, int has_huge_files)
/* small i_blocks in vfs inode? */
if (!has_huge_files || sizeof(blkcnt_t) < sizeof(u64)) {
/*
- * CONFIG_LSF is not enabled implies the inode
+ * CONFIG_LBD is not enabled implies the inode
* i_block represent total blocks in 512 bytes
* 32 == size of vfs inode i_blocks * 8
*/
@@ -1764,7 +1764,7 @@ static loff_t ext4_max_bitmap_size(int bits, int has_huge_files)
if (!has_huge_files || sizeof(blkcnt_t) < sizeof(u64)) {
/*
- * !has_huge_files or CONFIG_LSF is not enabled
+ * !has_huge_files or CONFIG_LBD is not enabled
* implies the inode i_block represent total blocks in
* 512 bytes 32 == size of vfs inode i_blocks * 8
*/
@@ -2021,13 +2021,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
if (has_huge_files) {
/*
* Large file size enabled file system can only be
- * mount if kernel is build with CONFIG_LSF
+ * mount if kernel is build with CONFIG_LBD
*/
if (sizeof(root->i_blocks) < sizeof(u64) &&
!(sb->s_flags & MS_RDONLY)) {
printk(KERN_ERR "EXT4-fs: %s: Filesystem with huge "
"files cannot be mounted read-write "
- "without CONFIG_LSF.\n", sb->s_id);
+ "without CONFIG_LBD.\n", sb->s_id);
goto failed_mount;
}
}
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 67e05835709..3a7f603b698 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -841,7 +841,6 @@ const struct file_operations fat_dir_operations = {
.compat_ioctl = fat_compat_dir_ioctl,
#endif
.fsync = file_fsync,
- .llseek = generic_file_llseek,
};
static int fat_get_short_entry(struct inode *dir, loff_t *pos,
diff --git a/fs/fat/file.c b/fs/fat/file.c
index f06a4e525ec..0a7f4a9918b 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -304,7 +304,7 @@ static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode)
{
mode_t allow_utime = sbi->options.allow_utime;
- if (current->fsuid != inode->i_uid) {
+ if (current_fsuid() != inode->i_uid) {
if (in_group_p(inode->i_gid))
allow_utime >>= 3;
if (allow_utime & MAY_WRITE)
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index bdd8fb7be2c..6b74d09adbe 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -749,6 +749,8 @@ static struct dentry *fat_get_parent(struct dentry *child)
brelse(bh);
parent = d_obtain_alias(inode);
+ if (!IS_ERR(parent))
+ parent->d_op = sb->s_root->d_op;
out:
unlock_super(sb);
@@ -926,8 +928,8 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug,
opts->isvfat = is_vfat;
- opts->fs_uid = current->uid;
- opts->fs_gid = current->gid;
+ opts->fs_uid = current_uid();
+ opts->fs_gid = current_gid();
opts->fs_fmask = opts->fs_dmask = current->fs->umask;
opts->allow_utime = -1;
opts->codepage = fat_default_codepage;
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
index bf326d4356a..8ae32e37673 100644
--- a/fs/fat/namei_vfat.c
+++ b/fs/fat/namei_vfat.c
@@ -78,7 +78,7 @@ static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd)
* for creation.
*/
if (!(nd->flags & (LOOKUP_CONTINUE | LOOKUP_PARENT))) {
- if (nd->flags & LOOKUP_CREATE)
+ if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
return 0;
}
diff --git a/fs/fcntl.c b/fs/fcntl.c
index ac4f7db9f13..cdc14194672 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -19,6 +19,7 @@
#include <linux/signal.h>
#include <linux/rcupdate.h>
#include <linux/pid_namespace.h>
+#include <linux/smp_lock.h>
#include <asm/poll.h>
#include <asm/siginfo.h>
@@ -175,6 +176,11 @@ static int setfl(int fd, struct file * filp, unsigned long arg)
if (error)
return error;
+ /*
+ * We still need a lock here for now to keep multiple FASYNC calls
+ * from racing with each other.
+ */
+ lock_kernel();
if ((arg ^ filp->f_flags) & FASYNC) {
if (filp->f_op && filp->f_op->fasync) {
error = filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0);
@@ -185,6 +191,7 @@ static int setfl(int fd, struct file * filp, unsigned long arg)
filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK);
out:
+ unlock_kernel();
return error;
}
@@ -205,13 +212,14 @@ static void f_modown(struct file *filp, struct pid *pid, enum pid_type type,
int __f_setown(struct file *filp, struct pid *pid, enum pid_type type,
int force)
{
+ const struct cred *cred = current_cred();
int err;
err = security_file_set_fowner(filp);
if (err)
return err;
- f_modown(filp, pid, type, current->uid, current->euid, force);
+ f_modown(filp, pid, type, cred->uid, cred->euid, force);
return 0;
}
EXPORT_SYMBOL(__f_setown);
@@ -400,10 +408,17 @@ static const long band_table[NSIGPOLL] = {
static inline int sigio_perm(struct task_struct *p,
struct fown_struct *fown, int sig)
{
- return (((fown->euid == 0) ||
- (fown->euid == p->suid) || (fown->euid == p->uid) ||
- (fown->uid == p->suid) || (fown->uid == p->uid)) &&
- !security_file_send_sigiotask(p, fown, sig));
+ const struct cred *cred;
+ int ret;
+
+ rcu_read_lock();
+ cred = __task_cred(p);
+ ret = ((fown->euid == 0 ||
+ fown->euid == cred->suid || fown->euid == cred->uid ||
+ fown->uid == cred->suid || fown->uid == cred->uid) &&
+ !security_file_send_sigiotask(p, fown, sig));
+ rcu_read_unlock();
+ return ret;
}
static void send_sigio_to_task(struct task_struct *p,
diff --git a/fs/file_table.c b/fs/file_table.c
index 5ad0eca6eea..bbeeac6efa1 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -32,11 +32,16 @@ struct files_stat_struct files_stat = {
/* public. Not pretty! */
__cacheline_aligned_in_smp DEFINE_SPINLOCK(files_lock);
+/* SLAB cache for file structures */
+static struct kmem_cache *filp_cachep __read_mostly;
+
static struct percpu_counter nr_files __cacheline_aligned_in_smp;
static inline void file_free_rcu(struct rcu_head *head)
{
- struct file *f = container_of(head, struct file, f_u.fu_rcuhead);
+ struct file *f = container_of(head, struct file, f_u.fu_rcuhead);
+
+ put_cred(f->f_cred);
kmem_cache_free(filp_cachep, f);
}
@@ -94,7 +99,7 @@ int proc_nr_files(ctl_table *table, int write, struct file *filp,
*/
struct file *get_empty_filp(void)
{
- struct task_struct *tsk;
+ const struct cred *cred = current_cred();
static int old_max;
struct file * f;
@@ -118,12 +123,10 @@ struct file *get_empty_filp(void)
if (security_file_alloc(f))
goto fail_sec;
- tsk = current;
INIT_LIST_HEAD(&f->f_u.fu_list);
atomic_long_set(&f->f_count, 1);
rwlock_init(&f->f_owner.lock);
- f->f_uid = tsk->fsuid;
- f->f_gid = tsk->fsgid;
+ f->f_cred = get_cred(cred);
eventpoll_init_file(f);
/* f->f_version: 0 */
return f;
@@ -397,7 +400,12 @@ too_bad:
void __init files_init(unsigned long mempages)
{
int n;
- /* One file with associated inode and dcache is very roughly 1K.
+
+ filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0,
+ SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
+
+ /*
+ * One file with associated inode and dcache is very roughly 1K.
* Per default don't use more than 10% of our memory for files.
*/
diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c
index 9f3f2ceb73f..03a6ea5e99f 100644
--- a/fs/freevxfs/vxfs_inode.c
+++ b/fs/freevxfs/vxfs_inode.c
@@ -325,8 +325,10 @@ vxfs_iget(struct super_block *sbp, ino_t ino)
if (!VXFS_ISIMMED(vip)) {
ip->i_op = &page_symlink_inode_operations;
ip->i_mapping->a_ops = &vxfs_aops;
- } else
+ } else {
ip->i_op = &vxfs_immed_symlink_iops;
+ vip->vii_immed.vi_immed[ip->i_size] = '\0';
+ }
} else
init_special_inode(ip, ip->i_mode, old_decode_dev(vip->vii_rdev));
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index b72361479be..fba571648a8 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -87,8 +87,8 @@ static void __fuse_put_request(struct fuse_req *req)
static void fuse_req_init_context(struct fuse_req *req)
{
- req->in.h.uid = current->fsuid;
- req->in.h.gid = current->fsgid;
+ req->in.h.uid = current_fsuid();
+ req->in.h.gid = current_fsgid();
req->in.h.pid = current->pid;
}
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index fd03330cade..95bc22bdd06 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -869,18 +869,25 @@ int fuse_update_attributes(struct inode *inode, struct kstat *stat,
*/
int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
{
+ const struct cred *cred;
+ int ret;
+
if (fc->flags & FUSE_ALLOW_OTHER)
return 1;
- if (task->euid == fc->user_id &&
- task->suid == fc->user_id &&
- task->uid == fc->user_id &&
- task->egid == fc->group_id &&
- task->sgid == fc->group_id &&
- task->gid == fc->group_id)
- return 1;
+ rcu_read_lock();
+ ret = 0;
+ cred = __task_cred(task);
+ if (cred->euid == fc->user_id &&
+ cred->suid == fc->user_id &&
+ cred->uid == fc->user_id &&
+ cred->egid == fc->group_id &&
+ cred->sgid == fc->group_id &&
+ cred->gid == fc->group_id)
+ ret = 1;
+ rcu_read_unlock();
- return 0;
+ return ret;
}
static int fuse_access(struct inode *inode, int mask)
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 7cee695fa44..d57616840e8 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -705,18 +705,18 @@ static void munge_mode_uid_gid(struct gfs2_inode *dip, unsigned int *mode,
(dip->i_inode.i_mode & S_ISUID) && dip->i_inode.i_uid) {
if (S_ISDIR(*mode))
*mode |= S_ISUID;
- else if (dip->i_inode.i_uid != current->fsuid)
+ else if (dip->i_inode.i_uid != current_fsuid())
*mode &= ~07111;
*uid = dip->i_inode.i_uid;
} else
- *uid = current->fsuid;
+ *uid = current_fsuid();
if (dip->i_inode.i_mode & S_ISGID) {
if (S_ISDIR(*mode))
*mode |= S_ISGID;
*gid = dip->i_inode.i_gid;
} else
- *gid = current->fsgid;
+ *gid = current_fsgid();
}
static int alloc_dinode(struct gfs2_inode *dip, u64 *no_addr, u64 *generation)
@@ -1124,8 +1124,8 @@ int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name,
return -EPERM;
if ((dip->i_inode.i_mode & S_ISVTX) &&
- dip->i_inode.i_uid != current->fsuid &&
- ip->i_inode.i_uid != current->fsuid && !capable(CAP_FOWNER))
+ dip->i_inode.i_uid != current_fsuid() &&
+ ip->i_inode.i_uid != current_fsuid() && !capable(CAP_FOWNER))
return -EPERM;
if (IS_APPEND(&dip->i_inode))
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index c69b7ac75bf..9435dda8f1e 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -155,8 +155,8 @@ struct inode *hfs_new_inode(struct inode *dir, struct qstr *name, int mode)
hfs_cat_build_key(sb, (btree_key *)&HFS_I(inode)->cat_key, dir->i_ino, name);
inode->i_ino = HFS_SB(sb)->next_id++;
inode->i_mode = mode;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
inode->i_nlink = 1;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
HFS_I(inode)->flags = 0;
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index 3c7c7637719..c8b5acf4b0b 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -210,8 +210,8 @@ static int parse_options(char *options, struct hfs_sb_info *hsb)
int tmp, token;
/* initialize the sb with defaults */
- hsb->s_uid = current->uid;
- hsb->s_gid = current->gid;
+ hsb->s_uid = current_uid();
+ hsb->s_gid = current_gid();
hsb->s_file_umask = 0133;
hsb->s_dir_umask = 0022;
hsb->s_type = hsb->s_creator = cpu_to_be32(0x3f3f3f3f); /* == '????' */
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index b207f0e6fc2..f105ee9e1cc 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -296,8 +296,8 @@ struct inode *hfsplus_new_inode(struct super_block *sb, int mode)
inode->i_ino = HFSPLUS_SB(sb).next_cnid++;
inode->i_mode = mode;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
inode->i_nlink = 1;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list);
diff --git a/fs/hfsplus/options.c b/fs/hfsplus/options.c
index 9699c56d323..bab7f8d1bdf 100644
--- a/fs/hfsplus/options.c
+++ b/fs/hfsplus/options.c
@@ -49,8 +49,8 @@ void hfsplus_fill_defaults(struct hfsplus_sb_info *opts)
opts->creator = HFSPLUS_DEF_CR_TYPE;
opts->type = HFSPLUS_DEF_CR_TYPE;
opts->umask = current->fs->umask;
- opts->uid = current->uid;
- opts->gid = current->gid;
+ opts->uid = current_uid();
+ opts->gid = current_gid();
opts->part = -1;
opts->session = -1;
}
diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c
index 10783f3d265..b649232dde9 100644
--- a/fs/hpfs/namei.c
+++ b/fs/hpfs/namei.c
@@ -92,11 +92,11 @@ static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
inc_nlink(dir);
insert_inode_hash(result);
- if (result->i_uid != current->fsuid ||
- result->i_gid != current->fsgid ||
+ if (result->i_uid != current_fsuid() ||
+ result->i_gid != current_fsgid() ||
result->i_mode != (mode | S_IFDIR)) {
- result->i_uid = current->fsuid;
- result->i_gid = current->fsgid;
+ result->i_uid = current_fsuid();
+ result->i_gid = current_fsgid();
result->i_mode = mode | S_IFDIR;
hpfs_write_inode_nolock(result);
}
@@ -184,11 +184,11 @@ static int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struc
insert_inode_hash(result);
- if (result->i_uid != current->fsuid ||
- result->i_gid != current->fsgid ||
+ if (result->i_uid != current_fsuid() ||
+ result->i_gid != current_fsgid() ||
result->i_mode != (mode | S_IFREG)) {
- result->i_uid = current->fsuid;
- result->i_gid = current->fsgid;
+ result->i_uid = current_fsuid();
+ result->i_gid = current_fsgid();
result->i_mode = mode | S_IFREG;
hpfs_write_inode_nolock(result);
}
@@ -247,8 +247,8 @@ static int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t
result->i_mtime.tv_nsec = 0;
result->i_atime.tv_nsec = 0;
hpfs_i(result)->i_ea_size = 0;
- result->i_uid = current->fsuid;
- result->i_gid = current->fsgid;
+ result->i_uid = current_fsuid();
+ result->i_gid = current_fsgid();
result->i_nlink = 1;
result->i_size = 0;
result->i_blocks = 1;
@@ -325,8 +325,8 @@ static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *sy
result->i_atime.tv_nsec = 0;
hpfs_i(result)->i_ea_size = 0;
result->i_mode = S_IFLNK | 0777;
- result->i_uid = current->fsuid;
- result->i_gid = current->fsgid;
+ result->i_uid = current_fsuid();
+ result->i_gid = current_fsgid();
result->i_blocks = 1;
result->i_nlink = 1;
result->i_size = strlen(symlink);
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
index 29ad461d568..0d049b8919c 100644
--- a/fs/hpfs/super.c
+++ b/fs/hpfs/super.c
@@ -475,8 +475,8 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent)
init_MUTEX(&sbi->hpfs_creation_de);
- uid = current->uid;
- gid = current->gid;
+ uid = current_uid();
+ gid = current_gid();
umask = current->fs->umask;
lowercase = 0;
conv = CONV_BINARY;
diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c
index 2b3d1828db9..b278f7f5202 100644
--- a/fs/hppfs/hppfs.c
+++ b/fs/hppfs/hppfs.c
@@ -426,6 +426,7 @@ static int file_mode(int fmode)
static int hppfs_open(struct inode *inode, struct file *file)
{
+ const struct cred *cred = file->f_cred;
struct hppfs_private *data;
struct vfsmount *proc_mnt;
struct dentry *proc_dentry;
@@ -446,7 +447,7 @@ static int hppfs_open(struct inode *inode, struct file *file)
/* XXX This isn't closed anywhere */
data->proc_file = dentry_open(dget(proc_dentry), mntget(proc_mnt),
- file_mode(file->f_mode));
+ file_mode(file->f_mode), cred);
err = PTR_ERR(data->proc_file);
if (IS_ERR(data->proc_file))
goto out_free1;
@@ -489,6 +490,7 @@ static int hppfs_open(struct inode *inode, struct file *file)
static int hppfs_dir_open(struct inode *inode, struct file *file)
{
+ const struct cred *cred = file->f_cred;
struct hppfs_private *data;
struct vfsmount *proc_mnt;
struct dentry *proc_dentry;
@@ -502,7 +504,7 @@ static int hppfs_dir_open(struct inode *inode, struct file *file)
proc_dentry = HPPFS_I(inode)->proc_dentry;
proc_mnt = inode->i_sb->s_fs_info;
data->proc_file = dentry_open(dget(proc_dentry), mntget(proc_mnt),
- file_mode(file->f_mode));
+ file_mode(file->f_mode), cred);
err = PTR_ERR(data->proc_file);
if (IS_ERR(data->proc_file))
goto out_free;
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 61edc701b0e..7d479ce3ace 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -551,9 +551,9 @@ static int hugetlbfs_mknod(struct inode *dir,
if (S_ISDIR(mode))
mode |= S_ISGID;
} else {
- gid = current->fsgid;
+ gid = current_fsgid();
}
- inode = hugetlbfs_get_inode(dir->i_sb, current->fsuid, gid, mode, dev);
+ inode = hugetlbfs_get_inode(dir->i_sb, current_fsuid(), gid, mode, dev);
if (inode) {
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
d_instantiate(dentry, inode);
@@ -586,9 +586,9 @@ static int hugetlbfs_symlink(struct inode *dir,
if (dir->i_mode & S_ISGID)
gid = dir->i_gid;
else
- gid = current->fsgid;
+ gid = current_fsgid();
- inode = hugetlbfs_get_inode(dir->i_sb, current->fsuid,
+ inode = hugetlbfs_get_inode(dir->i_sb, current_fsuid(),
gid, S_IFLNK|S_IRWXUGO, 0);
if (inode) {
int l = strlen(symname)+1;
@@ -854,8 +854,8 @@ hugetlbfs_fill_super(struct super_block *sb, void *data, int silent)
config.nr_blocks = -1; /* No limit on size by default */
config.nr_inodes = -1; /* No limit on number of inodes by default */
- config.uid = current->fsuid;
- config.gid = current->fsgid;
+ config.uid = current_fsuid();
+ config.gid = current_fsgid();
config.mode = 0755;
config.hstate = &default_hstate;
ret = hugetlbfs_parse_options(data, &config);
@@ -951,6 +951,7 @@ struct file *hugetlb_file_setup(const char *name, size_t size)
struct inode *inode;
struct dentry *dentry, *root;
struct qstr quick_string;
+ struct user_struct *user = current_user();
if (!hugetlbfs_vfsmount)
return ERR_PTR(-ENOENT);
@@ -958,7 +959,7 @@ struct file *hugetlb_file_setup(const char *name, size_t size)
if (!can_do_hugetlb_shm())
return ERR_PTR(-EPERM);
- if (!user_shm_lock(size, current->user))
+ if (!user_shm_lock(size, user))
return ERR_PTR(-ENOMEM);
root = hugetlbfs_vfsmount->mnt_root;
@@ -970,8 +971,8 @@ struct file *hugetlb_file_setup(const char *name, size_t size)
goto out_shm_unlock;
error = -ENOSPC;
- inode = hugetlbfs_get_inode(root->d_sb, current->fsuid,
- current->fsgid, S_IFREG | S_IRWXUGO, 0);
+ inode = hugetlbfs_get_inode(root->d_sb, current_fsuid(),
+ current_fsgid(), S_IFREG | S_IRWXUGO, 0);
if (!inode)
goto out_dentry;
@@ -998,7 +999,7 @@ out_inode:
out_dentry:
dput(dentry);
out_shm_unlock:
- user_shm_unlock(size, current->user);
+ user_shm_unlock(size, user);
return ERR_PTR(error);
}
diff --git a/fs/inode.c b/fs/inode.c
index 0487ddba139..7de1cda9248 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -108,84 +108,100 @@ static void wake_up_inode(struct inode *inode)
wake_up_bit(&inode->i_state, __I_LOCK);
}
-static struct inode *alloc_inode(struct super_block *sb)
+/**
+ * inode_init_always - perform inode structure intialisation
+ * @sb - superblock inode belongs to.
+ * @inode - inode to initialise
+ *
+ * These are initializations that need to be done on every inode
+ * allocation as the fields are not initialised by slab allocation.
+ */
+struct inode *inode_init_always(struct super_block *sb, struct inode *inode)
{
static const struct address_space_operations empty_aops;
static struct inode_operations empty_iops;
static const struct file_operations empty_fops;
- struct inode *inode;
- if (sb->s_op->alloc_inode)
- inode = sb->s_op->alloc_inode(sb);
- else
- inode = (struct inode *) kmem_cache_alloc(inode_cachep, GFP_KERNEL);
-
- if (inode) {
- struct address_space * const mapping = &inode->i_data;
-
- inode->i_sb = sb;
- inode->i_blkbits = sb->s_blocksize_bits;
- inode->i_flags = 0;
- atomic_set(&inode->i_count, 1);
- inode->i_op = &empty_iops;
- inode->i_fop = &empty_fops;
- inode->i_nlink = 1;
- atomic_set(&inode->i_writecount, 0);
- inode->i_size = 0;
- inode->i_blocks = 0;
- inode->i_bytes = 0;
- inode->i_generation = 0;
+ struct address_space * const mapping = &inode->i_data;
+
+ inode->i_sb = sb;
+ inode->i_blkbits = sb->s_blocksize_bits;
+ inode->i_flags = 0;
+ atomic_set(&inode->i_count, 1);
+ inode->i_op = &empty_iops;
+ inode->i_fop = &empty_fops;
+ inode->i_nlink = 1;
+ atomic_set(&inode->i_writecount, 0);
+ inode->i_size = 0;
+ inode->i_blocks = 0;
+ inode->i_bytes = 0;
+ inode->i_generation = 0;
#ifdef CONFIG_QUOTA
- memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
+ memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
#endif
- inode->i_pipe = NULL;
- inode->i_bdev = NULL;
- inode->i_cdev = NULL;
- inode->i_rdev = 0;
- inode->dirtied_when = 0;
- if (security_inode_alloc(inode)) {
- if (inode->i_sb->s_op->destroy_inode)
- inode->i_sb->s_op->destroy_inode(inode);
- else
- kmem_cache_free(inode_cachep, (inode));
- return NULL;
- }
+ inode->i_pipe = NULL;
+ inode->i_bdev = NULL;
+ inode->i_cdev = NULL;
+ inode->i_rdev = 0;
+ inode->dirtied_when = 0;
+ if (security_inode_alloc(inode)) {
+ if (inode->i_sb->s_op->destroy_inode)
+ inode->i_sb->s_op->destroy_inode(inode);
+ else
+ kmem_cache_free(inode_cachep, (inode));
+ return NULL;
+ }
- spin_lock_init(&inode->i_lock);
- lockdep_set_class(&inode->i_lock, &sb->s_type->i_lock_key);
+ spin_lock_init(&inode->i_lock);
+ lockdep_set_class(&inode->i_lock, &sb->s_type->i_lock_key);
- mutex_init(&inode->i_mutex);
- lockdep_set_class(&inode->i_mutex, &sb->s_type->i_mutex_key);
+ mutex_init(&inode->i_mutex);
+ lockdep_set_class(&inode->i_mutex, &sb->s_type->i_mutex_key);
- init_rwsem(&inode->i_alloc_sem);
- lockdep_set_class(&inode->i_alloc_sem, &sb->s_type->i_alloc_sem_key);
+ init_rwsem(&inode->i_alloc_sem);
+ lockdep_set_class(&inode->i_alloc_sem, &sb->s_type->i_alloc_sem_key);
- mapping->a_ops = &empty_aops;
- mapping->host = inode;
- mapping->flags = 0;
- mapping_set_gfp_mask(mapping, GFP_HIGHUSER_PAGECACHE);
- mapping->assoc_mapping = NULL;
- mapping->backing_dev_info = &default_backing_dev_info;
- mapping->writeback_index = 0;
+ mapping->a_ops = &empty_aops;
+ mapping->host = inode;
+ mapping->flags = 0;
+ mapping_set_gfp_mask(mapping, GFP_HIGHUSER_PAGECACHE);
+ mapping->assoc_mapping = NULL;
+ mapping->backing_dev_info = &default_backing_dev_info;
+ mapping->writeback_index = 0;
- /*
- * If the block_device provides a backing_dev_info for client
- * inodes then use that. Otherwise the inode share the bdev's
- * backing_dev_info.
- */
- if (sb->s_bdev) {
- struct backing_dev_info *bdi;
+ /*
+ * If the block_device provides a backing_dev_info for client
+ * inodes then use that. Otherwise the inode share the bdev's
+ * backing_dev_info.
+ */
+ if (sb->s_bdev) {
+ struct backing_dev_info *bdi;
- bdi = sb->s_bdev->bd_inode_backing_dev_info;
- if (!bdi)
- bdi = sb->s_bdev->bd_inode->i_mapping->backing_dev_info;
- mapping->backing_dev_info = bdi;
- }
- inode->i_private = NULL;
- inode->i_mapping = mapping;
+ bdi = sb->s_bdev->bd_inode_backing_dev_info;
+ if (!bdi)
+ bdi = sb->s_bdev->bd_inode->i_mapping->backing_dev_info;
+ mapping->backing_dev_info = bdi;
}
+ inode->i_private = NULL;
+ inode->i_mapping = mapping;
+
return inode;
}
+EXPORT_SYMBOL(inode_init_always);
+
+static struct inode *alloc_inode(struct super_block *sb)
+{
+ struct inode *inode;
+
+ if (sb->s_op->alloc_inode)
+ inode = sb->s_op->alloc_inode(sb);
+ else
+ inode = kmem_cache_alloc(inode_cachep, GFP_KERNEL);
+
+ if (inode)
+ return inode_init_always(sb, inode);
+ return NULL;
+}
void destroy_inode(struct inode *inode)
{
@@ -196,6 +212,7 @@ void destroy_inode(struct inode *inode)
else
kmem_cache_free(inode_cachep, (inode));
}
+EXPORT_SYMBOL(destroy_inode);
/*
@@ -534,6 +551,49 @@ repeat:
return node ? inode : NULL;
}
+static unsigned long hash(struct super_block *sb, unsigned long hashval)
+{
+ unsigned long tmp;
+
+ tmp = (hashval * (unsigned long)sb) ^ (GOLDEN_RATIO_PRIME + hashval) /
+ L1_CACHE_BYTES;
+ tmp = tmp ^ ((tmp ^ GOLDEN_RATIO_PRIME) >> I_HASHBITS);
+ return tmp & I_HASHMASK;
+}
+
+static inline void
+__inode_add_to_lists(struct super_block *sb, struct hlist_head *head,
+ struct inode *inode)
+{
+ inodes_stat.nr_inodes++;
+ list_add(&inode->i_list, &inode_in_use);
+ list_add(&inode->i_sb_list, &sb->s_inodes);
+ if (head)
+ hlist_add_head(&inode->i_hash, head);
+}
+
+/**
+ * inode_add_to_lists - add a new inode to relevant lists
+ * @sb - superblock inode belongs to.
+ * @inode - inode to mark in use
+ *
+ * When an inode is allocated it needs to be accounted for, added to the in use
+ * list, the owning superblock and the inode hash. This needs to be done under
+ * the inode_lock, so export a function to do this rather than the inode lock
+ * itself. We calculate the hash list to add to here so it is all internal
+ * which requires the caller to have already set up the inode number in the
+ * inode to add.
+ */
+void inode_add_to_lists(struct super_block *sb, struct inode *inode)
+{
+ struct hlist_head *head = inode_hashtable + hash(sb, inode->i_ino);
+
+ spin_lock(&inode_lock);
+ __inode_add_to_lists(sb, head, inode);
+ spin_unlock(&inode_lock);
+}
+EXPORT_SYMBOL_GPL(inode_add_to_lists);
+
/**
* new_inode - obtain an inode
* @sb: superblock
@@ -561,9 +621,7 @@ struct inode *new_inode(struct super_block *sb)
inode = alloc_inode(sb);
if (inode) {
spin_lock(&inode_lock);
- inodes_stat.nr_inodes++;
- list_add(&inode->i_list, &inode_in_use);
- list_add(&inode->i_sb_list, &sb->s_inodes);
+ __inode_add_to_lists(sb, NULL, inode);
inode->i_ino = ++last_ino;
inode->i_state = 0;
spin_unlock(&inode_lock);
@@ -622,10 +680,7 @@ static struct inode * get_new_inode(struct super_block *sb, struct hlist_head *h
if (set(inode, data))
goto set_failed;
- inodes_stat.nr_inodes++;
- list_add(&inode->i_list, &inode_in_use);
- list_add(&inode->i_sb_list, &sb->s_inodes);
- hlist_add_head(&inode->i_hash, head);
+ __inode_add_to_lists(sb, head, inode);
inode->i_state = I_LOCK|I_NEW;
spin_unlock(&inode_lock);
@@ -671,10 +726,7 @@ static struct inode * get_new_inode_fast(struct super_block *sb, struct hlist_he
old = find_inode_fast(sb, head, ino);
if (!old) {
inode->i_ino = ino;
- inodes_stat.nr_inodes++;
- list_add(&inode->i_list, &inode_in_use);
- list_add(&inode->i_sb_list, &sb->s_inodes);
- hlist_add_head(&inode->i_hash, head);
+ __inode_add_to_lists(sb, head, inode);
inode->i_state = I_LOCK|I_NEW;
spin_unlock(&inode_lock);
@@ -698,16 +750,6 @@ static struct inode * get_new_inode_fast(struct super_block *sb, struct hlist_he
return inode;
}
-static unsigned long hash(struct super_block *sb, unsigned long hashval)
-{
- unsigned long tmp;
-
- tmp = (hashval * (unsigned long)sb) ^ (GOLDEN_RATIO_PRIME + hashval) /
- L1_CACHE_BYTES;
- tmp = tmp ^ ((tmp ^ GOLDEN_RATIO_PRIME) >> I_HASHBITS);
- return tmp & I_HASHMASK;
-}
-
/**
* iunique - get a unique inode number
* @sb: superblock
@@ -990,6 +1032,65 @@ struct inode *iget_locked(struct super_block *sb, unsigned long ino)
EXPORT_SYMBOL(iget_locked);
+int insert_inode_locked(struct inode *inode)
+{
+ struct super_block *sb = inode->i_sb;
+ ino_t ino = inode->i_ino;
+ struct hlist_head *head = inode_hashtable + hash(sb, ino);
+ struct inode *old;
+
+ inode->i_state |= I_LOCK|I_NEW;
+ while (1) {
+ spin_lock(&inode_lock);
+ old = find_inode_fast(sb, head, ino);
+ if (likely(!old)) {
+ hlist_add_head(&inode->i_hash, head);
+ spin_unlock(&inode_lock);
+ return 0;
+ }
+ __iget(old);
+ spin_unlock(&inode_lock);
+ wait_on_inode(old);
+ if (unlikely(!hlist_unhashed(&old->i_hash))) {
+ iput(old);
+ return -EBUSY;
+ }
+ iput(old);
+ }
+}
+
+EXPORT_SYMBOL(insert_inode_locked);
+
+int insert_inode_locked4(struct inode *inode, unsigned long hashval,
+ int (*test)(struct inode *, void *), void *data)
+{
+ struct super_block *sb = inode->i_sb;
+ struct hlist_head *head = inode_hashtable + hash(sb, hashval);
+ struct inode *old;
+
+ inode->i_state |= I_LOCK|I_NEW;
+
+ while (1) {
+ spin_lock(&inode_lock);
+ old = find_inode(sb, head, test, data);
+ if (likely(!old)) {
+ hlist_add_head(&inode->i_hash, head);
+ spin_unlock(&inode_lock);
+ return 0;
+ }
+ __iget(old);
+ spin_unlock(&inode_lock);
+ wait_on_inode(old);
+ if (unlikely(!hlist_unhashed(&old->i_hash))) {
+ iput(old);
+ return -EBUSY;
+ }
+ iput(old);
+ }
+}
+
+EXPORT_SYMBOL(insert_inode_locked4);
+
/**
* __insert_inode_hash - hash an inode
* @inode: unhashed inode
@@ -1292,6 +1393,7 @@ int inode_wait(void *word)
schedule();
return 0;
}
+EXPORT_SYMBOL(inode_wait);
/*
* If we try to find an inode in the inode hash while it is being
diff --git a/fs/internal.h b/fs/internal.h
index 80aa9a02337..53af885f173 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -10,6 +10,7 @@
*/
struct super_block;
+struct linux_binprm;
/*
* block_dev.c
@@ -40,6 +41,11 @@ static inline int sb_is_blkdev_sb(struct super_block *sb)
extern void __init chrdev_init(void);
/*
+ * exec.c
+ */
+extern void check_unsafe_exec(struct linux_binprm *);
+
+/*
* namespace.c
*/
extern int copy_mount_options(const void __user *, unsigned long *);
diff --git a/fs/ioctl.c b/fs/ioctl.c
index d152856c371..43e8b2c0664 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -400,11 +400,9 @@ static int ioctl_fioasync(unsigned int fd, struct file *filp,
/* Did FASYNC state change ? */
if ((flag ^ filp->f_flags) & FASYNC) {
- if (filp->f_op && filp->f_op->fasync) {
- lock_kernel();
+ if (filp->f_op && filp->f_op->fasync)
error = filp->f_op->fasync(fd, filp, on);
- unlock_kernel();
- } else
+ else
error = -ENOTTY;
}
if (error)
@@ -440,11 +438,17 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
break;
case FIONBIO:
+ /* BKL needed to avoid races tweaking f_flags */
+ lock_kernel();
error = ioctl_fionbio(filp, argp);
+ unlock_kernel();
break;
case FIOASYNC:
+ /* BKL needed to avoid races tweaking f_flags */
+ lock_kernel();
error = ioctl_fioasync(fd, filp, argp);
+ unlock_kernel();
break;
case FIOQSIZE:
diff --git a/fs/ioprio.c b/fs/ioprio.c
index da3cc460d4d..3569e0ad86a 100644
--- a/fs/ioprio.c
+++ b/fs/ioprio.c
@@ -31,10 +31,16 @@ static int set_task_ioprio(struct task_struct *task, int ioprio)
{
int err;
struct io_context *ioc;
+ const struct cred *cred = current_cred(), *tcred;
- if (task->uid != current->euid &&
- task->uid != current->uid && !capable(CAP_SYS_NICE))
+ rcu_read_lock();
+ tcred = __task_cred(task);
+ if (tcred->uid != cred->euid &&
+ tcred->uid != cred->uid && !capable(CAP_SYS_NICE)) {
+ rcu_read_unlock();
return -EPERM;
+ }
+ rcu_read_unlock();
err = security_task_setioprio(task, ioprio);
if (err)
@@ -123,7 +129,7 @@ asmlinkage long sys_ioprio_set(int which, int who, int ioprio)
break;
case IOPRIO_WHO_USER:
if (!who)
- user = current->user;
+ user = current_user();
else
user = find_user(who);
@@ -131,7 +137,7 @@ asmlinkage long sys_ioprio_set(int which, int who, int ioprio)
break;
do_each_thread(g, p) {
- if (p->uid != who)
+ if (__task_cred(p)->uid != who)
continue;
ret = set_task_ioprio(p, ioprio);
if (ret)
@@ -216,7 +222,7 @@ asmlinkage long sys_ioprio_get(int which, int who)
break;
case IOPRIO_WHO_USER:
if (!who)
- user = current->user;
+ user = current_user();
else
user = find_user(who);
@@ -224,7 +230,7 @@ asmlinkage long sys_ioprio_get(int which, int who)
break;
do_each_thread(g, p) {
- if (p->uid != user->uid)
+ if (__task_cred(p)->uid != user->uid)
continue;
tmpio = get_task_ioprio(p);
if (tmpio < 0)
diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c
index 210339784b5..b00ee9f05a0 100644
--- a/fs/jfs/inode.c
+++ b/fs/jfs/inode.c
@@ -59,8 +59,14 @@ struct inode *jfs_iget(struct super_block *sb, unsigned long ino)
if (inode->i_size >= IDATASIZE) {
inode->i_op = &page_symlink_inode_operations;
inode->i_mapping->a_ops = &jfs_aops;
- } else
+ } else {
inode->i_op = &jfs_symlink_inode_operations;
+ /*
+ * The inline data should be null-terminated, but
+ * don't let on-disk corruption crash the kernel
+ */
+ JFS_IP(inode)->i_inline[inode->i_size] = '\0';
+ }
} else {
inode->i_op = &jfs_file_inode_operations;
init_special_inode(inode, inode->i_mode, inode->i_rdev);
diff --git a/fs/jfs/jfs_inode.c b/fs/jfs/jfs_inode.c
index ed6574bee51..d4d142c2edd 100644
--- a/fs/jfs/jfs_inode.c
+++ b/fs/jfs/jfs_inode.c
@@ -79,7 +79,8 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
inode = new_inode(sb);
if (!inode) {
jfs_warn("ialloc: new_inode returned NULL!");
- return ERR_PTR(-ENOMEM);
+ rc = -ENOMEM;
+ goto fail;
}
jfs_inode = JFS_IP(inode);
@@ -89,17 +90,21 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
jfs_warn("ialloc: diAlloc returned %d!", rc);
if (rc == -EIO)
make_bad_inode(inode);
- iput(inode);
- return ERR_PTR(rc);
+ goto fail_put;
}
- inode->i_uid = current->fsuid;
+ if (insert_inode_locked(inode) < 0) {
+ rc = -EINVAL;
+ goto fail_unlock;
+ }
+
+ inode->i_uid = current_fsuid();
if (parent->i_mode & S_ISGID) {
inode->i_gid = parent->i_gid;
if (S_ISDIR(mode))
mode |= S_ISGID;
} else
- inode->i_gid = current->fsgid;
+ inode->i_gid = current_fsgid();
/*
* New inodes need to save sane values on disk when
@@ -112,11 +117,8 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
* Allocate inode to quota.
*/
if (DQUOT_ALLOC_INODE(inode)) {
- DQUOT_DROP(inode);
- inode->i_flags |= S_NOQUOTA;
- inode->i_nlink = 0;
- iput(inode);
- return ERR_PTR(-EDQUOT);
+ rc = -EDQUOT;
+ goto fail_drop;
}
inode->i_mode = mode;
@@ -158,4 +160,15 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
jfs_info("ialloc returns inode = 0x%p\n", inode);
return inode;
+
+fail_drop:
+ DQUOT_DROP(inode);
+ inode->i_flags |= S_NOQUOTA;
+fail_unlock:
+ inode->i_nlink = 0;
+ unlock_new_inode(inode);
+fail_put:
+ iput(inode);
+fail:
+ return ERR_PTR(rc);
}
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index cc3cedffbfa..b4de56b851e 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -155,7 +155,6 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
ip->i_fop = &jfs_file_operations;
ip->i_mapping->a_ops = &jfs_aops;
- insert_inode_hash(ip);
mark_inode_dirty(ip);
dip->i_ctime = dip->i_mtime = CURRENT_TIME;
@@ -171,9 +170,12 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
if (rc) {
free_ea_wmap(ip);
ip->i_nlink = 0;
+ unlock_new_inode(ip);
iput(ip);
- } else
+ } else {
d_instantiate(dentry, ip);
+ unlock_new_inode(ip);
+ }
out2:
free_UCSname(&dname);
@@ -289,7 +291,6 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
ip->i_op = &jfs_dir_inode_operations;
ip->i_fop = &jfs_dir_operations;
- insert_inode_hash(ip);
mark_inode_dirty(ip);
/* update parent directory inode */
@@ -306,9 +307,12 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
if (rc) {
free_ea_wmap(ip);
ip->i_nlink = 0;
+ unlock_new_inode(ip);
iput(ip);
- } else
+ } else {
d_instantiate(dentry, ip);
+ unlock_new_inode(ip);
+ }
out2:
free_UCSname(&dname);
@@ -1019,7 +1023,6 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
goto out3;
}
- insert_inode_hash(ip);
mark_inode_dirty(ip);
dip->i_ctime = dip->i_mtime = CURRENT_TIME;
@@ -1039,9 +1042,12 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
if (rc) {
free_ea_wmap(ip);
ip->i_nlink = 0;
+ unlock_new_inode(ip);
iput(ip);
- } else
+ } else {
d_instantiate(dentry, ip);
+ unlock_new_inode(ip);
+ }
out2:
free_UCSname(&dname);
@@ -1399,7 +1405,6 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
jfs_ip->dev = new_encode_dev(rdev);
init_special_inode(ip, ip->i_mode, rdev);
- insert_inode_hash(ip);
mark_inode_dirty(ip);
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
@@ -1417,9 +1422,12 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
if (rc) {
free_ea_wmap(ip);
ip->i_nlink = 0;
+ unlock_new_inode(ip);
iput(ip);
- } else
+ } else {
d_instantiate(dentry, ip);
+ unlock_new_inode(ip);
+ }
out1:
free_UCSname(&dname);
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c
index 8307dd64bf4..1f3b0fc0d35 100644
--- a/fs/lockd/clntlock.c
+++ b/fs/lockd/clntlock.c
@@ -14,6 +14,7 @@
#include <linux/sunrpc/svc.h>
#include <linux/lockd/lockd.h>
#include <linux/smp_lock.h>
+#include <linux/kthread.h>
#define NLMDBG_FACILITY NLMDBG_CLIENT
@@ -60,7 +61,7 @@ struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init)
host = nlmclnt_lookup_host(nlm_init->address, nlm_init->addrlen,
nlm_init->protocol, nlm_version,
- nlm_init->hostname);
+ nlm_init->hostname, nlm_init->noresvport);
if (host == NULL) {
lockd_down();
return ERR_PTR(-ENOLCK);
@@ -191,11 +192,15 @@ __be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock)
void
nlmclnt_recovery(struct nlm_host *host)
{
+ struct task_struct *task;
+
if (!host->h_reclaiming++) {
nlm_get_host(host);
- __module_get(THIS_MODULE);
- if (kernel_thread(reclaimer, host, CLONE_FS | CLONE_FILES) < 0)
- module_put(THIS_MODULE);
+ task = kthread_run(reclaimer, host, "%s-reclaim", host->h_name);
+ if (IS_ERR(task))
+ printk(KERN_ERR "lockd: unable to spawn reclaimer "
+ "thread. Locks for %s won't be reclaimed! "
+ "(%ld)\n", host->h_name, PTR_ERR(task));
}
}
@@ -207,7 +212,6 @@ reclaimer(void *ptr)
struct file_lock *fl, *next;
u32 nsmstate;
- daemonize("%s-reclaim", host->h_name);
allow_signal(SIGKILL);
down_write(&host->h_rwsem);
@@ -233,7 +237,12 @@ restart:
list_for_each_entry_safe(fl, next, &host->h_reclaim, fl_u.nfs_fl.list) {
list_del_init(&fl->fl_u.nfs_fl.list);
- /* Why are we leaking memory here? --okir */
+ /*
+ * sending this thread a SIGKILL will result in any unreclaimed
+ * locks being removed from the h_granted list. This means that
+ * the kernel will not attempt to reclaim them again if a new
+ * reclaimer thread is spawned for this host.
+ */
if (signalled())
continue;
if (nlmclnt_reclaim(host, fl) != 0)
@@ -261,5 +270,5 @@ restart:
nlm_release_host(host);
lockd_down();
unlock_kernel();
- module_put_and_exit(0);
+ return 0;
}
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index 9fd8889097b..abdebf76b82 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -48,6 +48,7 @@ struct nlm_lookup_host_info {
const size_t hostname_len; /* it's length */
const struct sockaddr *src_sap; /* our address (optional) */
const size_t src_len; /* it's length */
+ const int noresvport; /* use non-priv port */
};
/*
@@ -115,14 +116,14 @@ static void nlm_display_address(const struct sockaddr *sap,
snprintf(buf, len, "unspecified");
break;
case AF_INET:
- snprintf(buf, len, NIPQUAD_FMT, NIPQUAD(sin->sin_addr.s_addr));
+ snprintf(buf, len, "%pI4", &sin->sin_addr.s_addr);
break;
case AF_INET6:
if (ipv6_addr_v4mapped(&sin6->sin6_addr))
- snprintf(buf, len, NIPQUAD_FMT,
- NIPQUAD(sin6->sin6_addr.s6_addr32[3]));
+ snprintf(buf, len, "%pI4",
+ &sin6->sin6_addr.s6_addr32[3]);
else
- snprintf(buf, len, NIP6_FMT, NIP6(sin6->sin6_addr));
+ snprintf(buf, len, "%pI6", &sin6->sin6_addr);
break;
default:
snprintf(buf, len, "unsupported address family");
@@ -167,7 +168,8 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni)
continue;
if (host->h_server != ni->server)
continue;
- if (!nlm_cmp_addr(nlm_srcaddr(host), ni->src_sap))
+ if (ni->server &&
+ !nlm_cmp_addr(nlm_srcaddr(host), ni->src_sap))
continue;
/* Move to head of hash chain. */
@@ -221,6 +223,7 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni)
host->h_nsmstate = 0; /* real NSM state */
host->h_nsmhandle = nsm;
host->h_server = ni->server;
+ host->h_noresvport = ni->noresvport;
hlist_add_head(&host->h_hash, chain);
INIT_LIST_HEAD(&host->h_lockowners);
spin_lock_init(&host->h_lock);
@@ -271,6 +274,7 @@ nlm_destroy_host(struct nlm_host *host)
* @protocol: transport protocol to use
* @version: NLM protocol version
* @hostname: '\0'-terminated hostname of server
+ * @noresvport: 1 if non-privileged port should be used
*
* Returns an nlm_host structure that matches the passed-in
* [server address, transport protocol, NLM version, server hostname].
@@ -280,7 +284,9 @@ nlm_destroy_host(struct nlm_host *host)
struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
const size_t salen,
const unsigned short protocol,
- const u32 version, const char *hostname)
+ const u32 version,
+ const char *hostname,
+ int noresvport)
{
const struct sockaddr source = {
.sa_family = AF_UNSPEC,
@@ -295,6 +301,7 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
.hostname_len = strlen(hostname),
.src_sap = &source,
.src_len = sizeof(source),
+ .noresvport = noresvport,
};
dprintk("lockd: %s(host='%s', vers=%u, proto=%s)\n", __func__,
@@ -416,6 +423,8 @@ nlm_bind_host(struct nlm_host *host)
*/
if (!host->h_server)
args.flags |= RPC_CLNT_CREATE_HARDRTRY;
+ if (host->h_noresvport)
+ args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
clnt = rpc_create(&args);
if (!IS_ERR(clnt))
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
index 4e7e958e8f6..ffd3461f75e 100644
--- a/fs/lockd/mon.c
+++ b/fs/lockd/mon.c
@@ -179,7 +179,7 @@ static __be32 *xdr_encode_mon_name(__be32 *p, struct nsm_args *argp)
if (!nsm_use_hostnames) {
snprintf(buffer, XDR_ADDRBUF_LEN,
- NIPQUAD_FMT, NIPQUAD(argp->addr));
+ "%pI4", &argp->addr);
name = buffer;
}
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index c631a83931c..252d80163d0 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -45,7 +45,7 @@
static struct svc_program nlmsvc_program;
struct nlmsvc_binding * nlmsvc_ops;
-EXPORT_SYMBOL(nlmsvc_ops);
+EXPORT_SYMBOL_GPL(nlmsvc_ops);
static DEFINE_MUTEX(nlmsvc_mutex);
static unsigned int nlmsvc_users;
@@ -181,6 +181,7 @@ lockd(void *vrqstp)
}
flush_signals(current);
cancel_delayed_work_sync(&grace_period_end);
+ locks_end_grace(&lockd_manager);
if (nlmsvc_ops)
nlmsvc_invalidate_all();
nlm_shutdown_hosts();
@@ -299,7 +300,7 @@ out:
mutex_unlock(&nlmsvc_mutex);
return error;
}
-EXPORT_SYMBOL(lockd_up);
+EXPORT_SYMBOL_GPL(lockd_up);
/*
* Decrement the user count and bring down lockd if we're the last.
@@ -328,7 +329,7 @@ lockd_down(void)
out:
mutex_unlock(&nlmsvc_mutex);
}
-EXPORT_SYMBOL(lockd_down);
+EXPORT_SYMBOL_GPL(lockd_down);
#ifdef CONFIG_SYSCTL
diff --git a/fs/locks.c b/fs/locks.c
index 09062e3ff10..46a2e12f7d4 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -1349,7 +1349,7 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
struct inode *inode = dentry->d_inode;
int error, rdlease_count = 0, wrlease_count = 0;
- if ((current->fsuid != inode->i_uid) && !capable(CAP_LEASE))
+ if ((current_fsuid() != inode->i_uid) && !capable(CAP_LEASE))
return -EACCES;
if (!S_ISREG(inode->i_mode))
return -EINVAL;
diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c
index 703cc35e04b..3aebe322271 100644
--- a/fs/minix/bitmap.c
+++ b/fs/minix/bitmap.c
@@ -262,8 +262,8 @@ struct inode * minix_new_inode(const struct inode * dir, int * error)
iput(inode);
return NULL;
}
- inode->i_uid = current->fsuid;
- inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current_fsgid();
inode->i_ino = j;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
inode->i_blocks = 0;
diff --git a/fs/namei.c b/fs/namei.c
index d34e0f9681c..dd5c9f0bf82 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -186,7 +186,7 @@ int generic_permission(struct inode *inode, int mask,
mask &= MAY_READ | MAY_WRITE | MAY_EXEC;
- if (current->fsuid == inode->i_uid)
+ if (current_fsuid() == inode->i_uid)
mode >>= 6;
else {
if (IS_POSIXACL(inode) && (mode & S_IRWXG) && check_acl) {
@@ -226,6 +226,16 @@ int generic_permission(struct inode *inode, int mask,
return -EACCES;
}
+/**
+ * inode_permission - check for access rights to a given inode
+ * @inode: inode to check permission on
+ * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
+ *
+ * Used to check for read/write/execute permissions on an inode.
+ * We use "fsuid" for this, letting us set arbitrary permissions
+ * for filesystem access without changing the "normal" uids which
+ * are used for other things.
+ */
int inode_permission(struct inode *inode, int mask)
{
int retval;
@@ -247,7 +257,6 @@ int inode_permission(struct inode *inode, int mask)
return -EACCES;
}
- /* Ordinary permission routines do not understand MAY_APPEND. */
if (inode->i_op && inode->i_op->permission)
retval = inode->i_op->permission(inode, mask);
else
@@ -265,21 +274,6 @@ int inode_permission(struct inode *inode, int mask)
}
/**
- * vfs_permission - check for access rights to a given path
- * @nd: lookup result that describes the path
- * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
- *
- * Used to check for read/write/execute permissions on a path.
- * We use "fsuid" for this, letting us set arbitrary permissions
- * for filesystem access without changing the "normal" uids which
- * are used for other things.
- */
-int vfs_permission(struct nameidata *nd, int mask)
-{
- return inode_permission(nd->path.dentry->d_inode, mask);
-}
-
-/**
* file_permission - check for additional access rights to a given file
* @file: file to check access rights for
* @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
@@ -289,7 +283,7 @@ int vfs_permission(struct nameidata *nd, int mask)
*
* Note:
* Do not use this function in new code. All access checks should
- * be done using vfs_permission().
+ * be done using inode_permission().
*/
int file_permission(struct file *file, int mask)
{
@@ -441,7 +435,7 @@ static int exec_permission_lite(struct inode *inode)
if (inode->i_op && inode->i_op->permission)
return -EAGAIN;
- if (current->fsuid == inode->i_uid)
+ if (current_fsuid() == inode->i_uid)
mode >>= 6;
else if (in_group_p(inode->i_gid))
mode >>= 3;
@@ -527,18 +521,6 @@ out_unlock:
return result;
}
-/* SMP-safe */
-static __always_inline void
-walk_init_root(const char *name, struct nameidata *nd)
-{
- struct fs_struct *fs = current->fs;
-
- read_lock(&fs->lock);
- nd->path = fs->root;
- path_get(&fs->root);
- read_unlock(&fs->lock);
-}
-
/*
* Wrapper to retry pathname resolution whenever the underlying
* file system returns an ESTALE.
@@ -576,9 +558,16 @@ static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *l
goto fail;
if (*link == '/') {
+ struct fs_struct *fs = current->fs;
+
path_put(&nd->path);
- walk_init_root(link, nd);
+
+ read_lock(&fs->lock);
+ nd->path = fs->root;
+ path_get(&fs->root);
+ read_unlock(&fs->lock);
}
+
res = link_path_walk(link, nd);
if (nd->depth || res || nd->last_type!=LAST_NORM)
return res;
@@ -859,7 +848,8 @@ static int __link_path_walk(const char *name, struct nameidata *nd)
nd->flags |= LOOKUP_CONTINUE;
err = exec_permission_lite(inode);
if (err == -EAGAIN)
- err = vfs_permission(nd, MAY_EXEC);
+ err = inode_permission(nd->path.dentry->d_inode,
+ MAY_EXEC);
if (err)
break;
@@ -1334,11 +1324,13 @@ static int user_path_parent(int dfd, const char __user *path,
*/
static inline int check_sticky(struct inode *dir, struct inode *inode)
{
+ uid_t fsuid = current_fsuid();
+
if (!(dir->i_mode & S_ISVTX))
return 0;
- if (inode->i_uid == current->fsuid)
+ if (inode->i_uid == fsuid)
return 0;
- if (dir->i_uid == current->fsuid)
+ if (dir->i_uid == fsuid)
return 0;
return !capable(CAP_FOWNER);
}
@@ -1491,9 +1483,9 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode,
return error;
}
-int may_open(struct nameidata *nd, int acc_mode, int flag)
+int may_open(struct path *path, int acc_mode, int flag)
{
- struct dentry *dentry = nd->path.dentry;
+ struct dentry *dentry = path->dentry;
struct inode *inode = dentry->d_inode;
int error;
@@ -1514,13 +1506,13 @@ int may_open(struct nameidata *nd, int acc_mode, int flag)
if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
flag &= ~O_TRUNC;
} else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
- if (nd->path.mnt->mnt_flags & MNT_NODEV)
+ if (path->mnt->mnt_flags & MNT_NODEV)
return -EACCES;
flag &= ~O_TRUNC;
}
- error = vfs_permission(nd, acc_mode);
+ error = inode_permission(inode, acc_mode);
if (error)
return error;
/*
@@ -1554,6 +1546,9 @@ int may_open(struct nameidata *nd, int acc_mode, int flag)
* Refuse to truncate files with mandatory locks held on them.
*/
error = locks_verify_locked(inode);
+ if (!error)
+ error = security_path_truncate(path, 0,
+ ATTR_MTIME|ATTR_CTIME|ATTR_OPEN);
if (!error) {
DQUOT_INIT(inode);
@@ -1584,14 +1579,18 @@ static int __open_namei_create(struct nameidata *nd, struct path *path,
if (!IS_POSIXACL(dir->d_inode))
mode &= ~current->fs->umask;
+ error = security_path_mknod(&nd->path, path->dentry, mode, 0);
+ if (error)
+ goto out_unlock;
error = vfs_create(dir->d_inode, path->dentry, mode, nd);
+out_unlock:
mutex_unlock(&dir->d_inode->i_mutex);
dput(nd->path.dentry);
nd->path.dentry = path->dentry;
if (error)
return error;
/* Don't check for write permission, don't truncate */
- return may_open(nd, 0, flag & ~O_TRUNC);
+ return may_open(&nd->path, 0, flag & ~O_TRUNC);
}
/*
@@ -1777,7 +1776,7 @@ ok:
if (error)
goto exit;
}
- error = may_open(&nd, acc_mode, flag);
+ error = may_open(&nd.path, acc_mode, flag);
if (error) {
if (will_write)
mnt_drop_write(nd.path.mnt);
@@ -1997,6 +1996,9 @@ asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode,
error = mnt_want_write(nd.path.mnt);
if (error)
goto out_dput;
+ error = security_path_mknod(&nd.path, dentry, mode, dev);
+ if (error)
+ goto out_drop_write;
switch (mode & S_IFMT) {
case 0: case S_IFREG:
error = vfs_create(nd.path.dentry->d_inode,dentry,mode,&nd);
@@ -2009,6 +2011,7 @@ asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode,
error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,0);
break;
}
+out_drop_write:
mnt_drop_write(nd.path.mnt);
out_dput:
dput(dentry);
@@ -2068,7 +2071,11 @@ asmlinkage long sys_mkdirat(int dfd, const char __user *pathname, int mode)
error = mnt_want_write(nd.path.mnt);
if (error)
goto out_dput;
+ error = security_path_mkdir(&nd.path, dentry, mode);
+ if (error)
+ goto out_drop_write;
error = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode);
+out_drop_write:
mnt_drop_write(nd.path.mnt);
out_dput:
dput(dentry);
@@ -2178,7 +2185,11 @@ static long do_rmdir(int dfd, const char __user *pathname)
error = mnt_want_write(nd.path.mnt);
if (error)
goto exit3;
+ error = security_path_rmdir(&nd.path, dentry);
+ if (error)
+ goto exit4;
error = vfs_rmdir(nd.path.dentry->d_inode, dentry);
+exit4:
mnt_drop_write(nd.path.mnt);
exit3:
dput(dentry);
@@ -2263,7 +2274,11 @@ static long do_unlinkat(int dfd, const char __user *pathname)
error = mnt_want_write(nd.path.mnt);
if (error)
goto exit2;
+ error = security_path_unlink(&nd.path, dentry);
+ if (error)
+ goto exit3;
error = vfs_unlink(nd.path.dentry->d_inode, dentry);
+exit3:
mnt_drop_write(nd.path.mnt);
exit2:
dput(dentry);
@@ -2344,7 +2359,11 @@ asmlinkage long sys_symlinkat(const char __user *oldname,
error = mnt_want_write(nd.path.mnt);
if (error)
goto out_dput;
+ error = security_path_symlink(&nd.path, dentry, from);
+ if (error)
+ goto out_drop_write;
error = vfs_symlink(nd.path.dentry->d_inode, dentry, from);
+out_drop_write:
mnt_drop_write(nd.path.mnt);
out_dput:
dput(dentry);
@@ -2441,7 +2460,11 @@ asmlinkage long sys_linkat(int olddfd, const char __user *oldname,
error = mnt_want_write(nd.path.mnt);
if (error)
goto out_dput;
+ error = security_path_link(old_path.dentry, &nd.path, new_dentry);
+ if (error)
+ goto out_drop_write;
error = vfs_link(old_path.dentry, nd.path.dentry->d_inode, new_dentry);
+out_drop_write:
mnt_drop_write(nd.path.mnt);
out_dput:
dput(new_dentry);
@@ -2677,8 +2700,13 @@ asmlinkage long sys_renameat(int olddfd, const char __user *oldname,
error = mnt_want_write(oldnd.path.mnt);
if (error)
goto exit5;
+ error = security_path_rename(&oldnd.path, old_dentry,
+ &newnd.path, new_dentry);
+ if (error)
+ goto exit6;
error = vfs_rename(old_dir->d_inode, old_dentry,
new_dir->d_inode, new_dentry);
+exit6:
mnt_drop_write(oldnd.path.mnt);
exit5:
dput(new_dentry);
@@ -2748,13 +2776,16 @@ int vfs_follow_link(struct nameidata *nd, const char *link)
/* get the link contents into pagecache */
static char *page_getlink(struct dentry * dentry, struct page **ppage)
{
- struct page * page;
+ char *kaddr;
+ struct page *page;
struct address_space *mapping = dentry->d_inode->i_mapping;
page = read_mapping_page(mapping, 0, NULL);
if (IS_ERR(page))
return (char*)page;
*ppage = page;
- return kmap(page);
+ kaddr = kmap(page);
+ nd_terminate_link(kaddr, dentry->d_inode->i_size, PAGE_SIZE - 1);
+ return kaddr;
}
int page_readlink(struct dentry *dentry, char __user *buffer, int buflen)
@@ -2847,7 +2878,6 @@ EXPORT_SYMBOL(path_lookup);
EXPORT_SYMBOL(kern_path);
EXPORT_SYMBOL(vfs_path_lookup);
EXPORT_SYMBOL(inode_permission);
-EXPORT_SYMBOL(vfs_permission);
EXPORT_SYMBOL(file_permission);
EXPORT_SYMBOL(unlock_rename);
EXPORT_SYMBOL(vfs_create);
@@ -2863,3 +2893,10 @@ EXPORT_SYMBOL(vfs_symlink);
EXPORT_SYMBOL(vfs_unlink);
EXPORT_SYMBOL(dentry_unhash);
EXPORT_SYMBOL(generic_readlink);
+
+/* to be mentioned only in INIT_TASK */
+struct fs_struct init_fs = {
+ .count = ATOMIC_INIT(1),
+ .lock = __RW_LOCK_UNLOCKED(init_fs.lock),
+ .umask = 0022,
+};
diff --git a/fs/namespace.c b/fs/namespace.c
index 65b3dc844c8..a40685d800a 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1176,7 +1176,7 @@ static int mount_is_safe(struct path *path)
if (S_ISLNK(path->dentry->d_inode->i_mode))
return -EPERM;
if (path->dentry->d_inode->i_mode & S_ISVTX) {
- if (current->uid != path->dentry->d_inode->i_uid)
+ if (current_uid() != path->dentry->d_inode->i_uid)
return -EPERM;
}
if (inode_permission(path->dentry->d_inode, MAY_WRITE))
@@ -1990,7 +1990,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
if (!new_ns->root) {
up_write(&namespace_sem);
kfree(new_ns);
- return ERR_PTR(-ENOMEM);;
+ return ERR_PTR(-ENOMEM);
}
spin_lock(&vfsmount_lock);
list_add_tail(&new_ns->list, &new_ns->root->mnt_list);
diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c
index 3a97c95e1ca..6d04e050c74 100644
--- a/fs/ncpfs/ioctl.c
+++ b/fs/ncpfs/ioctl.c
@@ -40,10 +40,10 @@ ncp_get_fs_info(struct ncp_server * server, struct file *file,
struct inode *inode = file->f_path.dentry->d_inode;
struct ncp_fs_info info;
- if ((file_permission(file, MAY_WRITE) != 0)
- && (current->uid != server->m.mounted_uid)) {
+ if (file_permission(file, MAY_WRITE) != 0
+ && current_uid() != server->m.mounted_uid)
return -EACCES;
- }
+
if (copy_from_user(&info, arg, sizeof(info)))
return -EFAULT;
@@ -70,10 +70,10 @@ ncp_get_fs_info_v2(struct ncp_server * server, struct file *file,
struct inode *inode = file->f_path.dentry->d_inode;
struct ncp_fs_info_v2 info2;
- if ((file_permission(file, MAY_WRITE) != 0)
- && (current->uid != server->m.mounted_uid)) {
+ if (file_permission(file, MAY_WRITE) != 0
+ && current_uid() != server->m.mounted_uid)
return -EACCES;
- }
+
if (copy_from_user(&info2, arg, sizeof(info2)))
return -EFAULT;
@@ -141,10 +141,10 @@ ncp_get_compat_fs_info_v2(struct ncp_server * server, struct file *file,
struct inode *inode = file->f_path.dentry->d_inode;
struct compat_ncp_fs_info_v2 info2;
- if ((file_permission(file, MAY_WRITE) != 0)
- && (current->uid != server->m.mounted_uid)) {
+ if (file_permission(file, MAY_WRITE) != 0
+ && current_uid() != server->m.mounted_uid)
return -EACCES;
- }
+
if (copy_from_user(&info2, arg, sizeof(info2)))
return -EFAULT;
@@ -270,16 +270,17 @@ static int __ncp_ioctl(struct inode *inode, struct file *filp,
struct ncp_ioctl_request request;
char* bouncebuffer;
void __user *argp = (void __user *)arg;
+ uid_t uid = current_uid();
switch (cmd) {
#ifdef CONFIG_COMPAT
case NCP_IOC_NCPREQUEST_32:
#endif
case NCP_IOC_NCPREQUEST:
- if ((file_permission(filp, MAY_WRITE) != 0)
- && (current->uid != server->m.mounted_uid)) {
+ if (file_permission(filp, MAY_WRITE) != 0
+ && uid != server->m.mounted_uid)
return -EACCES;
- }
+
#ifdef CONFIG_COMPAT
if (cmd == NCP_IOC_NCPREQUEST_32) {
struct compat_ncp_ioctl_request request32;
@@ -356,10 +357,10 @@ static int __ncp_ioctl(struct inode *inode, struct file *filp,
case NCP_IOC_GETMOUNTUID16:
case NCP_IOC_GETMOUNTUID32:
case NCP_IOC_GETMOUNTUID64:
- if ((file_permission(filp, MAY_READ) != 0)
- && (current->uid != server->m.mounted_uid)) {
+ if (file_permission(filp, MAY_READ) != 0
+ && uid != server->m.mounted_uid)
return -EACCES;
- }
+
if (cmd == NCP_IOC_GETMOUNTUID16) {
u16 uid;
SET_UID(uid, server->m.mounted_uid);
@@ -380,11 +381,10 @@ static int __ncp_ioctl(struct inode *inode, struct file *filp,
{
struct ncp_setroot_ioctl sr;
- if ((file_permission(filp, MAY_READ) != 0)
- && (current->uid != server->m.mounted_uid))
- {
+ if (file_permission(filp, MAY_READ) != 0
+ && uid != server->m.mounted_uid)
return -EACCES;
- }
+
if (server->m.mounted_vol[0]) {
struct dentry* dentry = inode->i_sb->s_root;
@@ -408,6 +408,7 @@ static int __ncp_ioctl(struct inode *inode, struct file *filp,
return -EFAULT;
return 0;
}
+
case NCP_IOC_SETROOT:
{
struct ncp_setroot_ioctl sr;
@@ -455,11 +456,10 @@ static int __ncp_ioctl(struct inode *inode, struct file *filp,
#ifdef CONFIG_NCPFS_PACKET_SIGNING
case NCP_IOC_SIGN_INIT:
- if ((file_permission(filp, MAY_WRITE) != 0)
- && (current->uid != server->m.mounted_uid))
- {
+ if (file_permission(filp, MAY_WRITE) != 0
+ && uid != server->m.mounted_uid)
return -EACCES;
- }
+
if (argp) {
if (server->sign_wanted)
{
@@ -478,24 +478,22 @@ static int __ncp_ioctl(struct inode *inode, struct file *filp,
return 0;
case NCP_IOC_SIGN_WANTED:
- if ((file_permission(filp, MAY_READ) != 0)
- && (current->uid != server->m.mounted_uid))
- {
+ if (file_permission(filp, MAY_READ) != 0
+ && uid != server->m.mounted_uid)
return -EACCES;
- }
if (put_user(server->sign_wanted, (int __user *)argp))
return -EFAULT;
return 0;
+
case NCP_IOC_SET_SIGN_WANTED:
{
int newstate;
- if ((file_permission(filp, MAY_WRITE) != 0)
- && (current->uid != server->m.mounted_uid))
- {
+ if (file_permission(filp, MAY_WRITE) != 0
+ && uid != server->m.mounted_uid)
return -EACCES;
- }
+
/* get only low 8 bits... */
if (get_user(newstate, (unsigned char __user *)argp))
return -EFAULT;
@@ -512,11 +510,10 @@ static int __ncp_ioctl(struct inode *inode, struct file *filp,
#ifdef CONFIG_NCPFS_IOCTL_LOCKING
case NCP_IOC_LOCKUNLOCK:
- if ((file_permission(filp, MAY_WRITE) != 0)
- && (current->uid != server->m.mounted_uid))
- {
+ if (file_permission(filp, MAY_WRITE) != 0
+ && uid != server->m.mounted_uid)
return -EACCES;
- }
+
{
struct ncp_lock_ioctl rqdata;
@@ -585,9 +582,8 @@ outrel:
#ifdef CONFIG_COMPAT
case NCP_IOC_GETOBJECTNAME_32:
- if (current->uid != server->m.mounted_uid) {
+ if (uid != server->m.mounted_uid)
return -EACCES;
- }
{
struct compat_ncp_objectname_ioctl user;
size_t outl;
@@ -609,10 +605,10 @@ outrel:
return 0;
}
#endif
+
case NCP_IOC_GETOBJECTNAME:
- if (current->uid != server->m.mounted_uid) {
+ if (uid != server->m.mounted_uid)
return -EACCES;
- }
{
struct ncp_objectname_ioctl user;
size_t outl;
@@ -633,13 +629,13 @@ outrel:
return -EFAULT;
return 0;
}
+
#ifdef CONFIG_COMPAT
case NCP_IOC_SETOBJECTNAME_32:
#endif
case NCP_IOC_SETOBJECTNAME:
- if (current->uid != server->m.mounted_uid) {
+ if (uid != server->m.mounted_uid)
return -EACCES;
- }
{
struct ncp_objectname_ioctl user;
void* newname;
@@ -691,13 +687,13 @@ outrel:
kfree(oldname);
return 0;
}
+
#ifdef CONFIG_COMPAT
case NCP_IOC_GETPRIVATEDATA_32:
#endif
case NCP_IOC_GETPRIVATEDATA:
- if (current->uid != server->m.mounted_uid) {
+ if (uid != server->m.mounted_uid)
return -EACCES;
- }
{
struct ncp_privatedata_ioctl user;
size_t outl;
@@ -736,13 +732,13 @@ outrel:
return 0;
}
+
#ifdef CONFIG_COMPAT
case NCP_IOC_SETPRIVATEDATA_32:
#endif
case NCP_IOC_SETPRIVATEDATA:
- if (current->uid != server->m.mounted_uid) {
+ if (uid != server->m.mounted_uid)
return -EACCES;
- }
{
struct ncp_privatedata_ioctl user;
void* new;
@@ -794,9 +790,10 @@ outrel:
#endif /* CONFIG_NCPFS_NLS */
case NCP_IOC_SETDENTRYTTL:
- if ((file_permission(filp, MAY_WRITE) != 0) &&
- (current->uid != server->m.mounted_uid))
+ if (file_permission(filp, MAY_WRITE) != 0 &&
+ uid != server->m.mounted_uid)
return -EACCES;
+
{
u_int32_t user;
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index c2e9cfd9e5a..3e634f2a108 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -16,6 +16,7 @@
#include <linux/mutex.h>
#include <linux/freezer.h>
#include <linux/kthread.h>
+#include <linux/sunrpc/svcauth_gss.h>
#include <net/inet_sock.h>
@@ -182,10 +183,34 @@ void nfs_callback_down(void)
mutex_unlock(&nfs_callback_mutex);
}
+static int check_gss_callback_principal(struct nfs_client *clp,
+ struct svc_rqst *rqstp)
+{
+ struct rpc_clnt *r = clp->cl_rpcclient;
+ char *p = svc_gss_principal(rqstp);
+
+ /*
+ * It might just be a normal user principal, in which case
+ * userspace won't bother to tell us the name at all.
+ */
+ if (p == NULL)
+ return SVC_DENIED;
+
+ /* Expect a GSS_C_NT_HOSTBASED_NAME like "nfs@serverhostname" */
+
+ if (memcmp(p, "nfs@", 4) != 0)
+ return SVC_DENIED;
+ p += 4;
+ if (strcmp(p, r->cl_server) != 0)
+ return SVC_DENIED;
+ return SVC_OK;
+}
+
static int nfs_callback_authenticate(struct svc_rqst *rqstp)
{
struct nfs_client *clp;
RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
+ int ret = SVC_OK;
/* Don't talk to strangers */
clp = nfs_find_client(svc_addr(rqstp), 4);
@@ -194,21 +219,22 @@ static int nfs_callback_authenticate(struct svc_rqst *rqstp)
dprintk("%s: %s NFSv4 callback!\n", __func__,
svc_print_addr(rqstp, buf, sizeof(buf)));
- nfs_put_client(clp);
switch (rqstp->rq_authop->flavour) {
case RPC_AUTH_NULL:
if (rqstp->rq_proc != CB_NULL)
- return SVC_DENIED;
+ ret = SVC_DENIED;
break;
case RPC_AUTH_UNIX:
break;
case RPC_AUTH_GSS:
- /* FIXME: RPCSEC_GSS handling? */
+ ret = check_gss_callback_principal(clp, rqstp);
+ break;
default:
- return SVC_DENIED;
+ ret = SVC_DENIED;
}
- return SVC_OK;
+ nfs_put_client(clp);
+ return ret;
}
/*
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 7547600b617..9b728f3565a 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -143,7 +143,6 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_
clp->cl_proto = cl_init->proto;
#ifdef CONFIG_NFS_V4
- init_rwsem(&clp->cl_sem);
INIT_LIST_HEAD(&clp->cl_delegations);
spin_lock_init(&clp->cl_lock);
INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state);
@@ -224,31 +223,54 @@ void nfs_put_client(struct nfs_client *clp)
}
}
-static int nfs_sockaddr_match_ipaddr4(const struct sockaddr_in *sa1,
- const struct sockaddr_in *sa2)
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static const struct in6_addr *nfs_map_ipv4_addr(const struct sockaddr *sa, struct in6_addr *addr_mapped)
{
- return sa1->sin_addr.s_addr == sa2->sin_addr.s_addr;
+ switch (sa->sa_family) {
+ default:
+ return NULL;
+ case AF_INET6:
+ return &((const struct sockaddr_in6 *)sa)->sin6_addr;
+ break;
+ case AF_INET:
+ ipv6_addr_set_v4mapped(((const struct sockaddr_in *)sa)->sin_addr.s_addr,
+ addr_mapped);
+ return addr_mapped;
+ }
}
-static int nfs_sockaddr_match_ipaddr6(const struct sockaddr_in6 *sa1,
- const struct sockaddr_in6 *sa2)
+static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
+ const struct sockaddr *sa2)
+{
+ const struct in6_addr *addr1;
+ const struct in6_addr *addr2;
+ struct in6_addr addr1_mapped;
+ struct in6_addr addr2_mapped;
+
+ addr1 = nfs_map_ipv4_addr(sa1, &addr1_mapped);
+ if (likely(addr1 != NULL)) {
+ addr2 = nfs_map_ipv4_addr(sa2, &addr2_mapped);
+ if (likely(addr2 != NULL))
+ return ipv6_addr_equal(addr1, addr2);
+ }
+ return 0;
+}
+#else
+static int nfs_sockaddr_match_ipaddr4(const struct sockaddr_in *sa1,
+ const struct sockaddr_in *sa2)
{
- return ipv6_addr_equal(&sa1->sin6_addr, &sa2->sin6_addr);
+ return sa1->sin_addr.s_addr == sa2->sin_addr.s_addr;
}
static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
const struct sockaddr *sa2)
{
- switch (sa1->sa_family) {
- case AF_INET:
- return nfs_sockaddr_match_ipaddr4((const struct sockaddr_in *)sa1,
- (const struct sockaddr_in *)sa2);
- case AF_INET6:
- return nfs_sockaddr_match_ipaddr6((const struct sockaddr_in6 *)sa1,
- (const struct sockaddr_in6 *)sa2);
- }
- BUG();
+ if (unlikely(sa1->sa_family != AF_INET || sa2->sa_family != AF_INET))
+ return 0;
+ return nfs_sockaddr_match_ipaddr4((const struct sockaddr_in *)sa1,
+ (const struct sockaddr_in *)sa2);
}
+#endif
/*
* Find a client by IP address and protocol version
@@ -270,8 +292,6 @@ struct nfs_client *nfs_find_client(const struct sockaddr *addr, u32 nfsversion)
if (clp->rpc_ops->version != nfsversion)
continue;
- if (addr->sa_family != clap->sa_family)
- continue;
/* Match only the IP address, not the port number */
if (!nfs_sockaddr_match_ipaddr(addr, clap))
continue;
@@ -305,8 +325,6 @@ struct nfs_client *nfs_find_client_next(struct nfs_client *clp)
if (clp->rpc_ops->version != nfsvers)
continue;
- if (sap->sa_family != clap->sa_family)
- continue;
/* Match only the IP address, not the port number */
if (!nfs_sockaddr_match_ipaddr(sap, clap))
continue;
@@ -470,7 +488,7 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto,
static int nfs_create_rpc_client(struct nfs_client *clp,
const struct rpc_timeout *timeparms,
rpc_authflavor_t flavor,
- int flags)
+ int discrtry, int noresvport)
{
struct rpc_clnt *clnt = NULL;
struct rpc_create_args args = {
@@ -482,9 +500,13 @@ static int nfs_create_rpc_client(struct nfs_client *clp,
.program = &nfs_program,
.version = clp->rpc_ops->version,
.authflavor = flavor,
- .flags = flags,
};
+ if (discrtry)
+ args.flags |= RPC_CLNT_CREATE_DISCRTRY;
+ if (noresvport)
+ args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
+
if (!IS_ERR(clp->cl_rpcclient))
return 0;
@@ -522,6 +544,8 @@ static int nfs_start_lockd(struct nfs_server *server)
.protocol = server->flags & NFS_MOUNT_TCP ?
IPPROTO_TCP : IPPROTO_UDP,
.nfs_version = clp->rpc_ops->version,
+ .noresvport = server->flags & NFS_MOUNT_NORESVPORT ?
+ 1 : 0,
};
if (nlm_init.nfs_version > 3)
@@ -623,7 +647,8 @@ static int nfs_init_client(struct nfs_client *clp,
* Create a client RPC handle for doing FSSTAT with UNIX auth only
* - RFC 2623, sec 2.3.2
*/
- error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX, 0);
+ error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX,
+ 0, data->flags & NFS_MOUNT_NORESVPORT);
if (error < 0)
goto error;
nfs_mark_client_ready(clp, NFS_CS_READY);
@@ -965,7 +990,8 @@ error:
static int nfs4_init_client(struct nfs_client *clp,
const struct rpc_timeout *timeparms,
const char *ip_addr,
- rpc_authflavor_t authflavour)
+ rpc_authflavor_t authflavour,
+ int flags)
{
int error;
@@ -979,7 +1005,7 @@ static int nfs4_init_client(struct nfs_client *clp,
clp->rpc_ops = &nfs_v4_clientops;
error = nfs_create_rpc_client(clp, timeparms, authflavour,
- RPC_CLNT_CREATE_DISCRTRY);
+ 1, flags & NFS_MOUNT_NORESVPORT);
if (error < 0)
goto error;
memcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr));
@@ -1030,7 +1056,8 @@ static int nfs4_set_client(struct nfs_server *server,
error = PTR_ERR(clp);
goto error;
}
- error = nfs4_init_client(clp, timeparms, ip_addr, authflavour);
+ error = nfs4_init_client(clp, timeparms, ip_addr, authflavour,
+ server->flags);
if (error < 0)
goto error_put;
@@ -1059,6 +1086,10 @@ static int nfs4_init_server(struct nfs_server *server,
nfs_init_timeout_values(&timeparms, data->nfs_server.protocol,
data->timeo, data->retrans);
+ /* Initialise the client representation from the mount data */
+ server->flags = data->flags;
+ server->caps |= NFS_CAP_ATOMIC_OPEN;
+
/* Get a client record */
error = nfs4_set_client(server,
data->nfs_server.hostname,
@@ -1071,10 +1102,6 @@ static int nfs4_init_server(struct nfs_server *server,
if (error < 0)
goto error;
- /* Initialise the client representation from the mount data */
- server->flags = data->flags;
- server->caps |= NFS_CAP_ATOMIC_OPEN;
-
if (data->rsize)
server->rsize = nfs_block_size(data->rsize, NULL);
if (data->wsize)
@@ -1177,6 +1204,10 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
parent_server = NFS_SB(data->sb);
parent_client = parent_server->nfs_client;
+ /* Initialise the client representation from the parent server */
+ nfs_server_copy_userdata(server, parent_server);
+ server->caps |= NFS_CAP_ATOMIC_OPEN;
+
/* Get a client representation.
* Note: NFSv4 always uses TCP, */
error = nfs4_set_client(server, data->hostname,
@@ -1189,10 +1220,6 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
if (error < 0)
goto error;
- /* Initialise the client representation from the parent server */
- nfs_server_copy_userdata(server, parent_server);
- server->caps |= NFS_CAP_ATOMIC_OPEN;
-
error = nfs_init_server_rpcclient(server, parent_server->client->cl_timeout, data->authflavor);
if (error < 0)
goto error;
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index cc563cfa694..968225a8801 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -43,6 +43,27 @@ static void nfs_free_delegation(struct nfs_delegation *delegation)
put_rpccred(cred);
}
+void nfs_mark_delegation_referenced(struct nfs_delegation *delegation)
+{
+ set_bit(NFS_DELEGATION_REFERENCED, &delegation->flags);
+}
+
+int nfs_have_delegation(struct inode *inode, fmode_t flags)
+{
+ struct nfs_delegation *delegation;
+ int ret = 0;
+
+ flags &= FMODE_READ|FMODE_WRITE;
+ rcu_read_lock();
+ delegation = rcu_dereference(NFS_I(inode)->delegation);
+ if (delegation != NULL && (delegation->type & flags) == flags) {
+ nfs_mark_delegation_referenced(delegation);
+ ret = 1;
+ }
+ rcu_read_unlock();
+ return ret;
+}
+
static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state)
{
struct inode *inode = state->inode;
@@ -119,7 +140,7 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, st
delegation->maxsize = res->maxsize;
oldcred = delegation->cred;
delegation->cred = get_rpccred(cred);
- delegation->flags &= ~NFS_DELEGATION_NEED_RECLAIM;
+ clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
NFS_I(inode)->delegation_state = delegation->type;
smp_wmb();
put_rpccred(oldcred);
@@ -134,19 +155,35 @@ static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *
return res;
}
+static struct inode *nfs_delegation_grab_inode(struct nfs_delegation *delegation)
+{
+ struct inode *inode = NULL;
+
+ spin_lock(&delegation->lock);
+ if (delegation->inode != NULL)
+ inode = igrab(delegation->inode);
+ spin_unlock(&delegation->lock);
+ return inode;
+}
+
static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid)
{
struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation);
if (delegation == NULL)
goto nomatch;
+ spin_lock(&delegation->lock);
if (stateid != NULL && memcmp(delegation->stateid.data, stateid->data,
sizeof(delegation->stateid.data)) != 0)
- goto nomatch;
+ goto nomatch_unlock;
list_del_rcu(&delegation->super_list);
+ delegation->inode = NULL;
nfsi->delegation_state = 0;
rcu_assign_pointer(nfsi->delegation, NULL);
+ spin_unlock(&delegation->lock);
return delegation;
+nomatch_unlock:
+ spin_unlock(&delegation->lock);
nomatch:
return NULL;
}
@@ -172,6 +209,8 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
delegation->change_attr = nfsi->change_attr;
delegation->cred = get_rpccred(cred);
delegation->inode = inode;
+ delegation->flags = 1<<NFS_DELEGATION_REFERENCED;
+ spin_lock_init(&delegation->lock);
spin_lock(&clp->cl_lock);
if (rcu_dereference(nfsi->delegation) != NULL) {
@@ -226,22 +265,47 @@ static void nfs_msync_inode(struct inode *inode)
*/
static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegation *delegation)
{
- struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
struct nfs_inode *nfsi = NFS_I(inode);
nfs_msync_inode(inode);
- down_read(&clp->cl_sem);
/* Guard against new delegated open calls */
down_write(&nfsi->rwsem);
nfs_delegation_claim_opens(inode, &delegation->stateid);
up_write(&nfsi->rwsem);
- up_read(&clp->cl_sem);
nfs_msync_inode(inode);
return nfs_do_return_delegation(inode, delegation, 1);
}
/*
+ * Return all delegations that have been marked for return
+ */
+void nfs_client_return_marked_delegations(struct nfs_client *clp)
+{
+ struct nfs_delegation *delegation;
+ struct inode *inode;
+
+restart:
+ rcu_read_lock();
+ list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
+ if (!test_and_clear_bit(NFS_DELEGATION_RETURN, &delegation->flags))
+ continue;
+ inode = nfs_delegation_grab_inode(delegation);
+ if (inode == NULL)
+ continue;
+ spin_lock(&clp->cl_lock);
+ delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL);
+ spin_unlock(&clp->cl_lock);
+ rcu_read_unlock();
+ if (delegation != NULL)
+ __nfs_inode_return_delegation(inode, delegation);
+ iput(inode);
+ goto restart;
+ }
+ rcu_read_unlock();
+}
+
+/*
* This function returns the delegation without reclaiming opens
* or protecting against delegation reclaims.
* It is therefore really only safe to be called from
@@ -279,83 +343,55 @@ int nfs_inode_return_delegation(struct inode *inode)
return err;
}
+static void nfs_mark_return_delegation(struct nfs_client *clp, struct nfs_delegation *delegation)
+{
+ set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
+ set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
+}
+
/*
* Return all delegations associated to a super block
*/
-void nfs_return_all_delegations(struct super_block *sb)
+void nfs_super_return_all_delegations(struct super_block *sb)
{
struct nfs_client *clp = NFS_SB(sb)->nfs_client;
struct nfs_delegation *delegation;
- struct inode *inode;
if (clp == NULL)
return;
-restart:
rcu_read_lock();
list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
- if (delegation->inode->i_sb != sb)
- continue;
- inode = igrab(delegation->inode);
- if (inode == NULL)
- continue;
- spin_lock(&clp->cl_lock);
- delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL);
- spin_unlock(&clp->cl_lock);
- rcu_read_unlock();
- if (delegation != NULL)
- __nfs_inode_return_delegation(inode, delegation);
- iput(inode);
- goto restart;
+ spin_lock(&delegation->lock);
+ if (delegation->inode != NULL && delegation->inode->i_sb == sb)
+ set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
+ spin_unlock(&delegation->lock);
}
rcu_read_unlock();
+ nfs_client_return_marked_delegations(clp);
}
-static int nfs_do_expire_all_delegations(void *ptr)
+static void nfs_client_mark_return_all_delegations(struct nfs_client *clp)
{
- struct nfs_client *clp = ptr;
struct nfs_delegation *delegation;
- struct inode *inode;
- allow_signal(SIGKILL);
-restart:
- if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) != 0)
- goto out;
- if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0)
- goto out;
rcu_read_lock();
list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
- inode = igrab(delegation->inode);
- if (inode == NULL)
- continue;
- spin_lock(&clp->cl_lock);
- delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL);
- spin_unlock(&clp->cl_lock);
- rcu_read_unlock();
- if (delegation)
- __nfs_inode_return_delegation(inode, delegation);
- iput(inode);
- goto restart;
+ set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
+ set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
}
rcu_read_unlock();
-out:
- nfs_put_client(clp);
- module_put_and_exit(0);
+}
+
+static void nfs_delegation_run_state_manager(struct nfs_client *clp)
+{
+ if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state))
+ nfs4_schedule_state_manager(clp);
}
void nfs_expire_all_delegations(struct nfs_client *clp)
{
- struct task_struct *task;
-
- __module_get(THIS_MODULE);
- atomic_inc(&clp->cl_count);
- task = kthread_run(nfs_do_expire_all_delegations, clp,
- "%s-delegreturn",
- rpc_peeraddr2str(clp->cl_rpcclient,
- RPC_DISPLAY_ADDR));
- if (!IS_ERR(task))
- return;
- nfs_put_client(clp);
- module_put(THIS_MODULE);
+ nfs_client_mark_return_all_delegations(clp);
+ nfs_delegation_run_state_manager(clp);
}
/*
@@ -363,68 +399,29 @@ void nfs_expire_all_delegations(struct nfs_client *clp)
*/
void nfs_handle_cb_pathdown(struct nfs_client *clp)
{
- struct nfs_delegation *delegation;
- struct inode *inode;
-
if (clp == NULL)
return;
-restart:
+ nfs_client_mark_return_all_delegations(clp);
+}
+
+static void nfs_client_mark_return_unreferenced_delegations(struct nfs_client *clp)
+{
+ struct nfs_delegation *delegation;
+
rcu_read_lock();
list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
- inode = igrab(delegation->inode);
- if (inode == NULL)
+ if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags))
continue;
- spin_lock(&clp->cl_lock);
- delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL);
- spin_unlock(&clp->cl_lock);
- rcu_read_unlock();
- if (delegation != NULL)
- __nfs_inode_return_delegation(inode, delegation);
- iput(inode);
- goto restart;
+ set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
+ set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
}
rcu_read_unlock();
}
-struct recall_threadargs {
- struct inode *inode;
- struct nfs_client *clp;
- const nfs4_stateid *stateid;
-
- struct completion started;
- int result;
-};
-
-static int recall_thread(void *data)
+void nfs_expire_unreferenced_delegations(struct nfs_client *clp)
{
- struct recall_threadargs *args = (struct recall_threadargs *)data;
- struct inode *inode = igrab(args->inode);
- struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
- struct nfs_inode *nfsi = NFS_I(inode);
- struct nfs_delegation *delegation;
-
- daemonize("nfsv4-delegreturn");
-
- nfs_msync_inode(inode);
- down_read(&clp->cl_sem);
- down_write(&nfsi->rwsem);
- spin_lock(&clp->cl_lock);
- delegation = nfs_detach_delegation_locked(nfsi, args->stateid);
- if (delegation != NULL)
- args->result = 0;
- else
- args->result = -ENOENT;
- spin_unlock(&clp->cl_lock);
- complete(&args->started);
- nfs_delegation_claim_opens(inode, args->stateid);
- up_write(&nfsi->rwsem);
- up_read(&clp->cl_sem);
- nfs_msync_inode(inode);
-
- if (delegation != NULL)
- nfs_do_return_delegation(inode, delegation, 1);
- iput(inode);
- module_put_and_exit(0);
+ nfs_client_mark_return_unreferenced_delegations(clp);
+ nfs_delegation_run_state_manager(clp);
}
/*
@@ -432,22 +429,20 @@ static int recall_thread(void *data)
*/
int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid)
{
- struct recall_threadargs data = {
- .inode = inode,
- .stateid = stateid,
- };
- int status;
+ struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
+ struct nfs_delegation *delegation;
- init_completion(&data.started);
- __module_get(THIS_MODULE);
- status = kernel_thread(recall_thread, &data, CLONE_KERNEL);
- if (status < 0)
- goto out_module_put;
- wait_for_completion(&data.started);
- return data.result;
-out_module_put:
- module_put(THIS_MODULE);
- return status;
+ rcu_read_lock();
+ delegation = rcu_dereference(NFS_I(inode)->delegation);
+ if (delegation == NULL || memcmp(delegation->stateid.data, stateid->data,
+ sizeof(delegation->stateid.data)) != 0) {
+ rcu_read_unlock();
+ return -ENOENT;
+ }
+ nfs_mark_return_delegation(clp, delegation);
+ rcu_read_unlock();
+ nfs_delegation_run_state_manager(clp);
+ return 0;
}
/*
@@ -459,10 +454,14 @@ struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs
struct inode *res = NULL;
rcu_read_lock();
list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
- if (nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) {
+ spin_lock(&delegation->lock);
+ if (delegation->inode != NULL &&
+ nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) {
res = igrab(delegation->inode);
- break;
}
+ spin_unlock(&delegation->lock);
+ if (res != NULL)
+ break;
}
rcu_read_unlock();
return res;
@@ -476,7 +475,7 @@ void nfs_delegation_mark_reclaim(struct nfs_client *clp)
struct nfs_delegation *delegation;
rcu_read_lock();
list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list)
- delegation->flags |= NFS_DELEGATION_NEED_RECLAIM;
+ set_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
rcu_read_unlock();
}
@@ -486,17 +485,22 @@ void nfs_delegation_mark_reclaim(struct nfs_client *clp)
void nfs_delegation_reap_unclaimed(struct nfs_client *clp)
{
struct nfs_delegation *delegation;
+ struct inode *inode;
restart:
rcu_read_lock();
list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
- if ((delegation->flags & NFS_DELEGATION_NEED_RECLAIM) == 0)
+ if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags) == 0)
+ continue;
+ inode = nfs_delegation_grab_inode(delegation);
+ if (inode == NULL)
continue;
spin_lock(&clp->cl_lock);
- delegation = nfs_detach_delegation_locked(NFS_I(delegation->inode), NULL);
+ delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL);
spin_unlock(&clp->cl_lock);
rcu_read_unlock();
if (delegation != NULL)
nfs_free_delegation(delegation);
+ iput(inode);
goto restart;
}
rcu_read_unlock();
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h
index f1c5e2a5d88..09f38379517 100644
--- a/fs/nfs/delegation.h
+++ b/fs/nfs/delegation.h
@@ -17,14 +17,20 @@ struct nfs_delegation {
struct rpc_cred *cred;
struct inode *inode;
nfs4_stateid stateid;
- int type;
-#define NFS_DELEGATION_NEED_RECLAIM 1
- long flags;
+ fmode_t type;
loff_t maxsize;
__u64 change_attr;
+ unsigned long flags;
+ spinlock_t lock;
struct rcu_head rcu;
};
+enum {
+ NFS_DELEGATION_NEED_RECLAIM = 0,
+ NFS_DELEGATION_RETURN,
+ NFS_DELEGATION_REFERENCED,
+};
+
int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
int nfs_inode_return_delegation(struct inode *inode);
@@ -32,9 +38,11 @@ int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *s
void nfs_inode_return_delegation_noreclaim(struct inode *inode);
struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle);
-void nfs_return_all_delegations(struct super_block *sb);
+void nfs_super_return_all_delegations(struct super_block *sb);
void nfs_expire_all_delegations(struct nfs_client *clp);
+void nfs_expire_unreferenced_delegations(struct nfs_client *clp);
void nfs_handle_cb_pathdown(struct nfs_client *clp);
+void nfs_client_return_marked_delegations(struct nfs_client *clp);
void nfs_delegation_mark_reclaim(struct nfs_client *clp);
void nfs_delegation_reap_unclaimed(struct nfs_client *clp);
@@ -45,22 +53,11 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state
int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl);
int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode);
-static inline int nfs_have_delegation(struct inode *inode, int flags)
-{
- struct nfs_delegation *delegation;
- int ret = 0;
-
- flags &= FMODE_READ|FMODE_WRITE;
- rcu_read_lock();
- delegation = rcu_dereference(NFS_I(inode)->delegation);
- if (delegation != NULL && (delegation->type & flags) == flags)
- ret = 1;
- rcu_read_unlock();
- return ret;
-}
+void nfs_mark_delegation_referenced(struct nfs_delegation *delegation);
+int nfs_have_delegation(struct inode *inode, fmode_t flags);
#else
-static inline int nfs_have_delegation(struct inode *inode, int flags)
+static inline int nfs_have_delegation(struct inode *inode, fmode_t flags)
{
return 0;
}
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 3e64b98f3a9..e35c8199f82 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -799,6 +799,9 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
goto out_bad;
}
+ if (nfs_have_delegation(inode, FMODE_READ))
+ goto out_set_verifier;
+
/* Force a full look up iff the parent directory has changed */
if (!nfs_is_exclusive_create(dir, nd) && nfs_check_verifier(dir, dentry)) {
if (nfs_lookup_verify_inode(inode, nd))
@@ -817,6 +820,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
if ((error = nfs_refresh_inode(inode, &fattr)) != 0)
goto out_bad;
+out_set_verifier:
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
out_valid:
dput(parent);
@@ -973,7 +977,7 @@ struct dentry_operations nfs4_dentry_operations = {
* Use intent information to determine whether we need to substitute
* the NFSv4-style stateful OPEN for the LOOKUP call
*/
-static int is_atomic_open(struct inode *dir, struct nameidata *nd)
+static int is_atomic_open(struct nameidata *nd)
{
if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_OPEN) == 0)
return 0;
@@ -996,7 +1000,7 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
/* Check that we are indeed trying to open this file */
- if (!is_atomic_open(dir, nd))
+ if (!is_atomic_open(nd))
goto no_open;
if (dentry->d_name.len > NFS_SERVER(dir)->namelen) {
@@ -1047,10 +1051,10 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
struct inode *dir;
int openflags, ret = 0;
+ if (!is_atomic_open(nd))
+ goto no_open;
parent = dget_parent(dentry);
dir = parent->d_inode;
- if (!is_atomic_open(dir, nd))
- goto no_open;
/* We can't create new files in nfs_open_revalidate(), so we
* optimize away revalidation of negative dentries.
*/
@@ -1062,11 +1066,11 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
/* NFS only supports OPEN on regular files */
if (!S_ISREG(inode->i_mode))
- goto no_open;
+ goto no_open_dput;
openflags = nd->intent.open.flags;
/* We cannot do exclusive creation on a positive dentry */
if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))
- goto no_open;
+ goto no_open_dput;
/* We can't create new files, or truncate existing ones here */
openflags &= ~(O_CREAT|O_TRUNC);
@@ -1081,10 +1085,9 @@ out:
if (!ret)
d_drop(dentry);
return ret;
-no_open:
+no_open_dput:
dput(parent);
- if (inode != NULL && nfs_have_delegation(inode, FMODE_READ))
- return 1;
+no_open:
return nfs_lookup_revalidate(dentry, nd);
}
#endif /* CONFIG_NFSV4 */
@@ -1794,7 +1797,8 @@ static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, str
cache = nfs_access_search_rbtree(inode, cred);
if (cache == NULL)
goto out;
- if (!time_in_range(jiffies, cache->jiffies, cache->jiffies + nfsi->attrtimeo))
+ if (!nfs_have_delegation(inode, FMODE_READ) &&
+ !time_in_range_open(jiffies, cache->jiffies, cache->jiffies + nfsi->attrtimeo))
goto out_stale;
res->jiffies = cache->jiffies;
res->cred = cache->cred;
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index d22eb383e1c..0c381686171 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -592,7 +592,7 @@ static void nfs_file_set_open_context(struct file *filp, struct nfs_open_context
/*
* Given an inode, search for an open context with the desired characteristics
*/
-struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, int mode)
+struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, fmode_t mode)
{
struct nfs_inode *nfsi = NFS_I(inode);
struct nfs_open_context *pos, *ctx = NULL;
@@ -712,14 +712,7 @@ int nfs_attribute_timeout(struct inode *inode)
if (nfs_have_delegation(inode, FMODE_READ))
return 0;
- /*
- * Special case: if the attribute timeout is set to 0, then always
- * treat the cache as having expired (unless holding
- * a delegation).
- */
- if (nfsi->attrtimeo == 0)
- return 1;
- return !time_in_range(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo);
+ return !time_in_range_open(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo);
}
/**
@@ -1182,7 +1175,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
nfsi->attrtimeo_timestamp = now;
nfsi->attr_gencount = nfs_inc_attr_generation_counter();
} else {
- if (!time_in_range(now, nfsi->attrtimeo_timestamp, nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) {
+ if (!time_in_range_open(now, nfsi->attrtimeo_timestamp, nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) {
if ((nfsi->attrtimeo <<= 1) > NFS_MAXATTRTIMEO(inode))
nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode);
nfsi->attrtimeo_timestamp = now;
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index d212ee41caf..340ede8f608 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -63,6 +63,20 @@ struct nfs_parsed_mount_data {
struct security_mnt_opts lsm_opts;
};
+/* mount_clnt.c */
+struct nfs_mount_request {
+ struct sockaddr *sap;
+ size_t salen;
+ char *hostname;
+ char *dirpath;
+ u32 version;
+ unsigned short protocol;
+ struct nfs_fh *fh;
+ int noresvport;
+};
+
+extern int nfs_mount(struct nfs_mount_request *info);
+
/* client.c */
extern struct rpc_program nfs_program;
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c
index 086a6830d78..ca905a5bb1b 100644
--- a/fs/nfs/mount_clnt.c
+++ b/fs/nfs/mount_clnt.c
@@ -29,47 +29,43 @@ struct mnt_fhstatus {
/**
* nfs_mount - Obtain an NFS file handle for the given host and path
- * @addr: pointer to server's address
- * @len: size of server's address
- * @hostname: name of server host, or NULL
- * @path: pointer to string containing export path to mount
- * @version: mount version to use for this request
- * @protocol: transport protocol to use for thie request
- * @fh: pointer to location to place returned file handle
+ * @info: pointer to mount request arguments
*
* Uses default timeout parameters specified by underlying transport.
*/
-int nfs_mount(struct sockaddr *addr, size_t len, char *hostname, char *path,
- int version, int protocol, struct nfs_fh *fh)
+int nfs_mount(struct nfs_mount_request *info)
{
struct mnt_fhstatus result = {
- .fh = fh
+ .fh = info->fh
};
struct rpc_message msg = {
- .rpc_argp = path,
+ .rpc_argp = info->dirpath,
.rpc_resp = &result,
};
struct rpc_create_args args = {
- .protocol = protocol,
- .address = addr,
- .addrsize = len,
- .servername = hostname,
+ .protocol = info->protocol,
+ .address = info->sap,
+ .addrsize = info->salen,
+ .servername = info->hostname,
.program = &mnt_program,
- .version = version,
+ .version = info->version,
.authflavor = RPC_AUTH_UNIX,
- .flags = 0,
};
struct rpc_clnt *mnt_clnt;
int status;
dprintk("NFS: sending MNT request for %s:%s\n",
- (hostname ? hostname : "server"), path);
+ (info->hostname ? info->hostname : "server"),
+ info->dirpath);
+
+ if (info->noresvport)
+ args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
mnt_clnt = rpc_create(&args);
if (IS_ERR(mnt_clnt))
goto out_clnt_err;
- if (version == NFS_MNT3_VERSION)
+ if (info->version == NFS_MNT3_VERSION)
msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT];
else
msg.rpc_proc = &mnt_clnt->cl_procinfo[MNTPROC_MNT];
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index ea790645fda..4e4d3320437 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -38,8 +38,12 @@ struct idmap;
((err) != NFSERR_NOFILEHANDLE))
enum nfs4_client_state {
- NFS4CLNT_STATE_RECOVER = 0,
+ NFS4CLNT_MANAGER_RUNNING = 0,
+ NFS4CLNT_CHECK_LEASE,
NFS4CLNT_LEASE_EXPIRED,
+ NFS4CLNT_RECLAIM_REBOOT,
+ NFS4CLNT_RECLAIM_NOGRACE,
+ NFS4CLNT_DELEGRETURN,
};
/*
@@ -90,12 +94,18 @@ struct nfs4_state_owner {
spinlock_t so_lock;
atomic_t so_count;
+ unsigned long so_flags;
struct list_head so_states;
struct list_head so_delegations;
struct nfs_seqid_counter so_seqid;
struct rpc_sequence so_sequence;
};
+enum {
+ NFS_OWNER_RECLAIM_REBOOT,
+ NFS_OWNER_RECLAIM_NOGRACE
+};
+
/*
* struct nfs4_state maintains the client-side state for a given
* (state_owner,inode) tuple (OPEN) or state_owner (LOCK).
@@ -128,6 +138,8 @@ enum {
NFS_O_RDONLY_STATE, /* OPEN stateid has read-only state */
NFS_O_WRONLY_STATE, /* OPEN stateid has write-only state */
NFS_O_RDWR_STATE, /* OPEN stateid has read/write state */
+ NFS_STATE_RECLAIM_REBOOT, /* OPEN stateid server rebooted */
+ NFS_STATE_RECLAIM_NOGRACE, /* OPEN stateid needs to recover state */
};
struct nfs4_state {
@@ -149,7 +161,7 @@ struct nfs4_state {
unsigned int n_rdonly; /* Number of read-only references */
unsigned int n_wronly; /* Number of write-only references */
unsigned int n_rdwr; /* Number of read/write references */
- int state; /* State on the server (R,W, or RW) */
+ fmode_t state; /* State on the server (R,W, or RW) */
atomic_t count;
};
@@ -157,9 +169,12 @@ struct nfs4_state {
struct nfs4_exception {
long timeout;
int retry;
+ struct nfs4_state *state;
};
struct nfs4_state_recovery_ops {
+ int owner_flag_bit;
+ int state_flag_bit;
int (*recover_open)(struct nfs4_state_owner *, struct nfs4_state *);
int (*recover_lock)(struct nfs4_state *, struct file_lock *);
};
@@ -174,7 +189,6 @@ extern ssize_t nfs4_listxattr(struct dentry *, char *, size_t);
/* nfs4proc.c */
-extern int nfs4_map_errors(int err);
extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *);
extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *);
extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *);
@@ -187,7 +201,7 @@ extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
struct nfs4_fs_locations *fs_locations, struct page *page);
extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops;
-extern struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops;
+extern struct nfs4_state_recovery_ops nfs4_nograce_recovery_ops;
extern const u32 nfs4_fattr_bitmap[2];
extern const u32 nfs4_statfs_bitmap[2];
@@ -202,16 +216,18 @@ extern void nfs4_kill_renewd(struct nfs_client *);
extern void nfs4_renew_state(struct work_struct *);
/* nfs4state.c */
-struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp);
+struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp);
extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *);
extern void nfs4_put_state_owner(struct nfs4_state_owner *);
extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *);
extern void nfs4_put_open_state(struct nfs4_state *);
-extern void nfs4_close_state(struct path *, struct nfs4_state *, mode_t);
-extern void nfs4_close_sync(struct path *, struct nfs4_state *, mode_t);
-extern void nfs4_state_set_mode_locked(struct nfs4_state *, mode_t);
+extern void nfs4_close_state(struct path *, struct nfs4_state *, fmode_t);
+extern void nfs4_close_sync(struct path *, struct nfs4_state *, fmode_t);
+extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t);
extern void nfs4_schedule_state_recovery(struct nfs_client *);
+extern void nfs4_schedule_state_manager(struct nfs_client *);
+extern int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state);
extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t);
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 83e700a2b0c..8dde84b988d 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -62,14 +62,12 @@
struct nfs4_opendata;
static int _nfs4_proc_open(struct nfs4_opendata *data);
static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
-static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *);
-static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception);
-static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp);
+static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *);
static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr);
static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr);
/* Prevent leaks of NFSv4 errors into userland */
-int nfs4_map_errors(int err)
+static int nfs4_map_errors(int err)
{
if (err < -1000) {
dprintk("%s could not handle NFSv4 error %d\n",
@@ -195,6 +193,83 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent
kunmap_atomic(start, KM_USER0);
}
+static int nfs4_wait_bit_killable(void *word)
+{
+ if (fatal_signal_pending(current))
+ return -ERESTARTSYS;
+ schedule();
+ return 0;
+}
+
+static int nfs4_wait_clnt_recover(struct nfs_client *clp)
+{
+ int res;
+
+ might_sleep();
+
+ res = wait_on_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING,
+ nfs4_wait_bit_killable, TASK_KILLABLE);
+ return res;
+}
+
+static int nfs4_delay(struct rpc_clnt *clnt, long *timeout)
+{
+ int res = 0;
+
+ might_sleep();
+
+ if (*timeout <= 0)
+ *timeout = NFS4_POLL_RETRY_MIN;
+ if (*timeout > NFS4_POLL_RETRY_MAX)
+ *timeout = NFS4_POLL_RETRY_MAX;
+ schedule_timeout_killable(*timeout);
+ if (fatal_signal_pending(current))
+ res = -ERESTARTSYS;
+ *timeout <<= 1;
+ return res;
+}
+
+/* This is the error handling routine for processes that are allowed
+ * to sleep.
+ */
+static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception)
+{
+ struct nfs_client *clp = server->nfs_client;
+ struct nfs4_state *state = exception->state;
+ int ret = errorcode;
+
+ exception->retry = 0;
+ switch(errorcode) {
+ case 0:
+ return 0;
+ case -NFS4ERR_ADMIN_REVOKED:
+ case -NFS4ERR_BAD_STATEID:
+ case -NFS4ERR_OPENMODE:
+ if (state == NULL)
+ break;
+ nfs4_state_mark_reclaim_nograce(clp, state);
+ case -NFS4ERR_STALE_CLIENTID:
+ case -NFS4ERR_STALE_STATEID:
+ case -NFS4ERR_EXPIRED:
+ nfs4_schedule_state_recovery(clp);
+ ret = nfs4_wait_clnt_recover(clp);
+ if (ret == 0)
+ exception->retry = 1;
+ break;
+ case -NFS4ERR_FILE_OPEN:
+ case -NFS4ERR_GRACE:
+ case -NFS4ERR_DELAY:
+ ret = nfs4_delay(server->client, &exception->timeout);
+ if (ret != 0)
+ break;
+ case -NFS4ERR_OLD_STATEID:
+ exception->retry = 1;
+ }
+ /* We failed to handle the error */
+ return nfs4_map_errors(ret);
+}
+
+
static void renew_lease(const struct nfs_server *server, unsigned long timestamp)
{
struct nfs_client *clp = server->nfs_client;
@@ -248,7 +323,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p)
}
static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
- struct nfs4_state_owner *sp, int flags,
+ struct nfs4_state_owner *sp, fmode_t fmode, int flags,
const struct iattr *attrs)
{
struct dentry *parent = dget_parent(path->dentry);
@@ -268,7 +343,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
p->owner = sp;
atomic_inc(&sp->so_count);
p->o_arg.fh = NFS_FH(dir);
- p->o_arg.open_flags = flags,
+ p->o_arg.open_flags = flags;
+ p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE);
p->o_arg.clientid = server->nfs_client->cl_clientid;
p->o_arg.id = sp->so_owner_id.id;
p->o_arg.name = &p->path.dentry->d_name;
@@ -324,10 +400,13 @@ static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task)
return ret;
}
-static int can_open_cached(struct nfs4_state *state, int mode)
+static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode)
{
int ret = 0;
- switch (mode & (FMODE_READ|FMODE_WRITE|O_EXCL)) {
+
+ if (open_mode & O_EXCL)
+ goto out;
+ switch (mode & (FMODE_READ|FMODE_WRITE)) {
case FMODE_READ:
ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0;
break;
@@ -337,21 +416,23 @@ static int can_open_cached(struct nfs4_state *state, int mode)
case FMODE_READ|FMODE_WRITE:
ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0;
}
+out:
return ret;
}
-static int can_open_delegated(struct nfs_delegation *delegation, mode_t open_flags)
+static int can_open_delegated(struct nfs_delegation *delegation, fmode_t fmode)
{
- if ((delegation->type & open_flags) != open_flags)
+ if ((delegation->type & fmode) != fmode)
return 0;
- if (delegation->flags & NFS_DELEGATION_NEED_RECLAIM)
+ if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags))
return 0;
+ nfs_mark_delegation_referenced(delegation);
return 1;
}
-static void update_open_stateflags(struct nfs4_state *state, mode_t open_flags)
+static void update_open_stateflags(struct nfs4_state *state, fmode_t fmode)
{
- switch (open_flags) {
+ switch (fmode) {
case FMODE_WRITE:
state->n_wronly++;
break;
@@ -361,15 +442,15 @@ static void update_open_stateflags(struct nfs4_state *state, mode_t open_flags)
case FMODE_READ|FMODE_WRITE:
state->n_rdwr++;
}
- nfs4_state_set_mode_locked(state, state->state | open_flags);
+ nfs4_state_set_mode_locked(state, state->state | fmode);
}
-static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags)
+static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode)
{
if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
memcpy(state->stateid.data, stateid->data, sizeof(state->stateid.data));
memcpy(state->open_stateid.data, stateid->data, sizeof(state->open_stateid.data));
- switch (open_flags) {
+ switch (fmode) {
case FMODE_READ:
set_bit(NFS_O_RDONLY_STATE, &state->flags);
break;
@@ -381,16 +462,15 @@ static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *
}
}
-static void nfs_set_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags)
+static void nfs_set_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode)
{
write_seqlock(&state->seqlock);
- nfs_set_open_stateid_locked(state, stateid, open_flags);
+ nfs_set_open_stateid_locked(state, stateid, fmode);
write_sequnlock(&state->seqlock);
}
-static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, nfs4_stateid *deleg_stateid, int open_flags)
+static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, const nfs4_stateid *deleg_stateid, fmode_t fmode)
{
- open_flags &= (FMODE_READ|FMODE_WRITE);
/*
* Protect the call to nfs4_state_set_mode_locked and
* serialise the stateid update
@@ -401,20 +481,60 @@ static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_sta
set_bit(NFS_DELEGATED_STATE, &state->flags);
}
if (open_stateid != NULL)
- nfs_set_open_stateid_locked(state, open_stateid, open_flags);
+ nfs_set_open_stateid_locked(state, open_stateid, fmode);
write_sequnlock(&state->seqlock);
spin_lock(&state->owner->so_lock);
- update_open_stateflags(state, open_flags);
+ update_open_stateflags(state, fmode);
spin_unlock(&state->owner->so_lock);
}
-static void nfs4_return_incompatible_delegation(struct inode *inode, mode_t open_flags)
+static int update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, nfs4_stateid *delegation, fmode_t fmode)
+{
+ struct nfs_inode *nfsi = NFS_I(state->inode);
+ struct nfs_delegation *deleg_cur;
+ int ret = 0;
+
+ fmode &= (FMODE_READ|FMODE_WRITE);
+
+ rcu_read_lock();
+ deleg_cur = rcu_dereference(nfsi->delegation);
+ if (deleg_cur == NULL)
+ goto no_delegation;
+
+ spin_lock(&deleg_cur->lock);
+ if (nfsi->delegation != deleg_cur ||
+ (deleg_cur->type & fmode) != fmode)
+ goto no_delegation_unlock;
+
+ if (delegation == NULL)
+ delegation = &deleg_cur->stateid;
+ else if (memcmp(deleg_cur->stateid.data, delegation->data, NFS4_STATEID_SIZE) != 0)
+ goto no_delegation_unlock;
+
+ nfs_mark_delegation_referenced(deleg_cur);
+ __update_open_stateid(state, open_stateid, &deleg_cur->stateid, fmode);
+ ret = 1;
+no_delegation_unlock:
+ spin_unlock(&deleg_cur->lock);
+no_delegation:
+ rcu_read_unlock();
+
+ if (!ret && open_stateid != NULL) {
+ __update_open_stateid(state, open_stateid, NULL, fmode);
+ ret = 1;
+ }
+
+ return ret;
+}
+
+
+static void nfs4_return_incompatible_delegation(struct inode *inode, fmode_t fmode)
{
struct nfs_delegation *delegation;
rcu_read_lock();
delegation = rcu_dereference(NFS_I(inode)->delegation);
- if (delegation == NULL || (delegation->type & open_flags) == open_flags) {
+ if (delegation == NULL || (delegation->type & fmode) == fmode) {
rcu_read_unlock();
return;
}
@@ -427,27 +547,28 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
struct nfs4_state *state = opendata->state;
struct nfs_inode *nfsi = NFS_I(state->inode);
struct nfs_delegation *delegation;
- int open_mode = opendata->o_arg.open_flags & (FMODE_READ|FMODE_WRITE|O_EXCL);
+ int open_mode = opendata->o_arg.open_flags & O_EXCL;
+ fmode_t fmode = opendata->o_arg.fmode;
nfs4_stateid stateid;
int ret = -EAGAIN;
- rcu_read_lock();
- delegation = rcu_dereference(nfsi->delegation);
for (;;) {
- if (can_open_cached(state, open_mode)) {
+ if (can_open_cached(state, fmode, open_mode)) {
spin_lock(&state->owner->so_lock);
- if (can_open_cached(state, open_mode)) {
- update_open_stateflags(state, open_mode);
+ if (can_open_cached(state, fmode, open_mode)) {
+ update_open_stateflags(state, fmode);
spin_unlock(&state->owner->so_lock);
- rcu_read_unlock();
goto out_return_state;
}
spin_unlock(&state->owner->so_lock);
}
- if (delegation == NULL)
- break;
- if (!can_open_delegated(delegation, open_mode))
+ rcu_read_lock();
+ delegation = rcu_dereference(nfsi->delegation);
+ if (delegation == NULL ||
+ !can_open_delegated(delegation, fmode)) {
+ rcu_read_unlock();
break;
+ }
/* Save the delegation */
memcpy(stateid.data, delegation->stateid.data, sizeof(stateid.data));
rcu_read_unlock();
@@ -455,19 +576,11 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
if (ret != 0)
goto out;
ret = -EAGAIN;
- rcu_read_lock();
- delegation = rcu_dereference(nfsi->delegation);
- /* If no delegation, try a cached open */
- if (delegation == NULL)
- continue;
- /* Is the delegation still valid? */
- if (memcmp(stateid.data, delegation->stateid.data, sizeof(stateid.data)) != 0)
- continue;
- rcu_read_unlock();
- update_open_stateid(state, NULL, &stateid, open_mode);
- goto out_return_state;
+
+ /* Try to update the stateid using the delegation */
+ if (update_open_stateid(state, NULL, &stateid, fmode))
+ goto out_return_state;
}
- rcu_read_unlock();
out:
return ERR_PTR(ret);
out_return_state:
@@ -480,7 +593,6 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data
struct inode *inode;
struct nfs4_state *state = NULL;
struct nfs_delegation *delegation;
- nfs4_stateid *deleg_stateid = NULL;
int ret;
if (!data->rpc_done) {
@@ -507,7 +619,7 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data
if (delegation)
delegation_flags = delegation->flags;
rcu_read_unlock();
- if (!(delegation_flags & NFS_DELEGATION_NEED_RECLAIM))
+ if ((delegation_flags & 1UL<<NFS_DELEGATION_NEED_RECLAIM) == 0)
nfs_inode_set_delegation(state->inode,
data->owner->so_cred,
&data->o_res);
@@ -516,12 +628,9 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data
data->owner->so_cred,
&data->o_res);
}
- rcu_read_lock();
- delegation = rcu_dereference(NFS_I(inode)->delegation);
- if (delegation != NULL)
- deleg_stateid = &delegation->stateid;
- update_open_stateid(state, &data->o_res.stateid, deleg_stateid, data->o_arg.open_flags);
- rcu_read_unlock();
+
+ update_open_stateid(state, &data->o_res.stateid, NULL,
+ data->o_arg.fmode);
iput(inode);
out:
return state;
@@ -552,7 +661,7 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context
{
struct nfs4_opendata *opendata;
- opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL);
+ opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, 0, NULL);
if (opendata == NULL)
return ERR_PTR(-ENOMEM);
opendata->state = state;
@@ -560,12 +669,13 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context
return opendata;
}
-static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openflags, struct nfs4_state **res)
+static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, fmode_t fmode, struct nfs4_state **res)
{
struct nfs4_state *newstate;
int ret;
- opendata->o_arg.open_flags = openflags;
+ opendata->o_arg.open_flags = 0;
+ opendata->o_arg.fmode = fmode;
memset(&opendata->o_res, 0, sizeof(opendata->o_res));
memset(&opendata->c_res, 0, sizeof(opendata->c_res));
nfs4_init_opendata_res(opendata);
@@ -575,7 +685,7 @@ static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openf
newstate = nfs4_opendata_to_nfs4_state(opendata);
if (IS_ERR(newstate))
return PTR_ERR(newstate);
- nfs4_close_state(&opendata->path, newstate, openflags);
+ nfs4_close_state(&opendata->path, newstate, fmode);
*res = newstate;
return 0;
}
@@ -631,7 +741,7 @@ static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state
{
struct nfs_delegation *delegation;
struct nfs4_opendata *opendata;
- int delegation_type = 0;
+ fmode_t delegation_type = 0;
int status;
opendata = nfs4_open_recoverdata_alloc(ctx, state);
@@ -641,7 +751,7 @@ static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state
opendata->o_arg.fh = NFS_FH(state->inode);
rcu_read_lock();
delegation = rcu_dereference(NFS_I(state->inode)->delegation);
- if (delegation != NULL && (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) != 0)
+ if (delegation != NULL && test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags) != 0)
delegation_type = delegation->type;
rcu_read_unlock();
opendata->o_arg.u.delegation_type = delegation_type;
@@ -744,7 +854,7 @@ static void nfs4_open_confirm_release(void *calldata)
goto out_free;
state = nfs4_opendata_to_nfs4_state(data);
if (!IS_ERR(state))
- nfs4_close_state(&data->path, state, data->o_arg.open_flags);
+ nfs4_close_state(&data->path, state, data->o_arg.fmode);
out_free:
nfs4_opendata_put(data);
}
@@ -808,12 +918,12 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
if (data->state != NULL) {
struct nfs_delegation *delegation;
- if (can_open_cached(data->state, data->o_arg.open_flags & (FMODE_READ|FMODE_WRITE|O_EXCL)))
+ if (can_open_cached(data->state, data->o_arg.fmode, data->o_arg.open_flags))
goto out_no_action;
rcu_read_lock();
delegation = rcu_dereference(NFS_I(data->state->inode)->delegation);
if (delegation != NULL &&
- (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) == 0) {
+ test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags) == 0) {
rcu_read_unlock();
goto out_no_action;
}
@@ -877,7 +987,7 @@ static void nfs4_open_release(void *calldata)
goto out_free;
state = nfs4_opendata_to_nfs4_state(data);
if (!IS_ERR(state))
- nfs4_close_state(&data->path, state, data->o_arg.open_flags);
+ nfs4_close_state(&data->path, state, data->o_arg.fmode);
out_free:
nfs4_opendata_put(data);
}
@@ -955,10 +1065,11 @@ static int nfs4_recover_expired_lease(struct nfs_server *server)
int ret;
for (;;) {
- ret = nfs4_wait_clnt_recover(server->client, clp);
+ ret = nfs4_wait_clnt_recover(clp);
if (ret != 0)
return ret;
- if (!test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
+ if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) &&
+ !test_bit(NFS4CLNT_CHECK_LEASE,&clp->cl_state))
break;
nfs4_schedule_state_recovery(clp);
}
@@ -993,8 +1104,9 @@ static inline int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4
do {
err = _nfs4_open_expired(ctx, state);
- if (err == -NFS4ERR_DELAY)
- nfs4_handle_exception(server, err, &exception);
+ if (err != -NFS4ERR_DELAY)
+ break;
+ nfs4_handle_exception(server, err, &exception);
} while (exception.retry);
return err;
}
@@ -1031,12 +1143,11 @@ static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata, struct
/*
* Returns a referenced nfs4_state
*/
-static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res)
+static int _nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res)
{
struct nfs4_state_owner *sp;
struct nfs4_state *state = NULL;
struct nfs_server *server = NFS_SERVER(dir);
- struct nfs_client *clp = server->nfs_client;
struct nfs4_opendata *opendata;
int status;
@@ -1050,12 +1161,11 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct
if (status != 0)
goto err_put_state_owner;
if (path->dentry->d_inode != NULL)
- nfs4_return_incompatible_delegation(path->dentry->d_inode, flags & (FMODE_READ|FMODE_WRITE));
- down_read(&clp->cl_sem);
+ nfs4_return_incompatible_delegation(path->dentry->d_inode, fmode);
status = -ENOMEM;
- opendata = nfs4_opendata_alloc(path, sp, flags, sattr);
+ opendata = nfs4_opendata_alloc(path, sp, fmode, flags, sattr);
if (opendata == NULL)
- goto err_release_rwsem;
+ goto err_put_state_owner;
if (path->dentry->d_inode != NULL)
opendata->state = nfs4_get_open_state(path->dentry->d_inode, sp);
@@ -1073,13 +1183,10 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct
goto err_opendata_put;
nfs4_opendata_put(opendata);
nfs4_put_state_owner(sp);
- up_read(&clp->cl_sem);
*res = state;
return 0;
err_opendata_put:
nfs4_opendata_put(opendata);
-err_release_rwsem:
- up_read(&clp->cl_sem);
err_put_state_owner:
nfs4_put_state_owner(sp);
out_err:
@@ -1088,14 +1195,14 @@ out_err:
}
-static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred)
+static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, int flags, struct iattr *sattr, struct rpc_cred *cred)
{
struct nfs4_exception exception = { };
struct nfs4_state *res;
int status;
do {
- status = _nfs4_do_open(dir, path, flags, sattr, cred, &res);
+ status = _nfs4_do_open(dir, path, fmode, flags, sattr, cred, &res);
if (status == 0)
break;
/* NOTE: BAD_SEQID means the server and client disagree about the
@@ -1230,10 +1337,13 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
renew_lease(server, calldata->timestamp);
break;
case -NFS4ERR_STALE_STATEID:
+ case -NFS4ERR_OLD_STATEID:
+ case -NFS4ERR_BAD_STATEID:
case -NFS4ERR_EXPIRED:
- break;
+ if (calldata->arg.fmode == 0)
+ break;
default:
- if (nfs4_async_handle_error(task, server) == -EAGAIN) {
+ if (nfs4_async_handle_error(task, server, state) == -EAGAIN) {
rpc_restart_call(task);
return;
}
@@ -1272,10 +1382,10 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
nfs_fattr_init(calldata->res.fattr);
if (test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0) {
task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE];
- calldata->arg.open_flags = FMODE_READ;
+ calldata->arg.fmode = FMODE_READ;
} else if (test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0) {
task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE];
- calldata->arg.open_flags = FMODE_WRITE;
+ calldata->arg.fmode = FMODE_WRITE;
}
calldata->timestamp = jiffies;
rpc_call_start(task);
@@ -1328,6 +1438,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait)
calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid);
if (calldata->arg.seqid == NULL)
goto out_free_calldata;
+ calldata->arg.fmode = 0;
calldata->arg.bitmask = server->attr_bitmask;
calldata->res.fattr = &calldata->fattr;
calldata->res.seqid = calldata->arg.seqid;
@@ -1354,13 +1465,13 @@ out:
return status;
}
-static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct nfs4_state *state)
+static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct nfs4_state *state, fmode_t fmode)
{
struct file *filp;
int ret;
/* If the open_intent is for execute, we have an extra check to make */
- if (nd->intent.open.flags & FMODE_EXEC) {
+ if (fmode & FMODE_EXEC) {
ret = nfs_may_open(state->inode,
state->owner->so_cred,
nd->intent.open.flags);
@@ -1376,7 +1487,7 @@ static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct
}
ret = PTR_ERR(filp);
out_close:
- nfs4_close_sync(path, state, nd->intent.open.flags);
+ nfs4_close_sync(path, state, fmode & (FMODE_READ|FMODE_WRITE));
return ret;
}
@@ -1392,6 +1503,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
struct rpc_cred *cred;
struct nfs4_state *state;
struct dentry *res;
+ fmode_t fmode = nd->intent.open.flags & (FMODE_READ | FMODE_WRITE | FMODE_EXEC);
if (nd->flags & LOOKUP_CREATE) {
attr.ia_mode = nd->intent.open.create_mode;
@@ -1409,7 +1521,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
parent = dentry->d_parent;
/* Protect against concurrent sillydeletes */
nfs_block_sillyrename(parent);
- state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, cred);
+ state = nfs4_do_open(dir, &path, fmode, nd->intent.open.flags, &attr, cred);
put_rpccred(cred);
if (IS_ERR(state)) {
if (PTR_ERR(state) == -ENOENT) {
@@ -1424,7 +1536,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
path.dentry = res;
nfs_set_verifier(path.dentry, nfs_save_change_attribute(dir));
nfs_unblock_sillyrename(parent);
- nfs4_intent_set_file(nd, &path, state);
+ nfs4_intent_set_file(nd, &path, state, fmode);
return res;
}
@@ -1437,11 +1549,12 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st
};
struct rpc_cred *cred;
struct nfs4_state *state;
+ fmode_t fmode = openflags & (FMODE_READ | FMODE_WRITE);
cred = rpc_lookup_cred();
if (IS_ERR(cred))
return PTR_ERR(cred);
- state = nfs4_do_open(dir, &path, openflags, NULL, cred);
+ state = nfs4_do_open(dir, &path, fmode, openflags, NULL, cred);
put_rpccred(cred);
if (IS_ERR(state)) {
switch (PTR_ERR(state)) {
@@ -1458,10 +1571,10 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st
}
if (state->inode == dentry->d_inode) {
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
- nfs4_intent_set_file(nd, &path, state);
+ nfs4_intent_set_file(nd, &path, state, fmode);
return 1;
}
- nfs4_close_sync(&path, state, openflags);
+ nfs4_close_sync(&path, state, fmode);
out_drop:
d_drop(dentry);
return 0;
@@ -1887,6 +2000,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
};
struct nfs4_state *state;
struct rpc_cred *cred;
+ fmode_t fmode = flags & (FMODE_READ | FMODE_WRITE);
int status = 0;
cred = rpc_lookup_cred();
@@ -1894,7 +2008,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
status = PTR_ERR(cred);
goto out;
}
- state = nfs4_do_open(dir, &path, flags, sattr, cred);
+ state = nfs4_do_open(dir, &path, fmode, flags, sattr, cred);
d_drop(dentry);
if (IS_ERR(state)) {
status = PTR_ERR(state);
@@ -1910,9 +2024,9 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
nfs_post_op_update_inode(state->inode, &fattr);
}
if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0)
- status = nfs4_intent_set_file(nd, &path, state);
+ status = nfs4_intent_set_file(nd, &path, state, fmode);
else
- nfs4_close_sync(&path, state, flags);
+ nfs4_close_sync(&path, state, fmode);
out_putcred:
put_rpccred(cred);
out:
@@ -1974,7 +2088,7 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
{
struct nfs_removeres *res = task->tk_msg.rpc_resp;
- if (nfs4_async_handle_error(task, res->server) == -EAGAIN)
+ if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN)
return 0;
update_changeattr(dir, &res->cinfo);
nfs_post_op_update_inode(dir, &res->dir_attr);
@@ -2402,7 +2516,7 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data)
{
struct nfs_server *server = NFS_SERVER(data->inode);
- if (nfs4_async_handle_error(task, server) == -EAGAIN) {
+ if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) {
rpc_restart_call(task);
return -EAGAIN;
}
@@ -2423,7 +2537,7 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data)
{
struct inode *inode = data->inode;
- if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) {
+ if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) {
rpc_restart_call(task);
return -EAGAIN;
}
@@ -2449,7 +2563,7 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data)
{
struct inode *inode = data->inode;
- if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) {
+ if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) {
rpc_restart_call(task);
return -EAGAIN;
}
@@ -2742,19 +2856,25 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen
}
static int
-nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server)
+nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state)
{
struct nfs_client *clp = server->nfs_client;
if (!clp || task->tk_status >= 0)
return 0;
switch(task->tk_status) {
+ case -NFS4ERR_ADMIN_REVOKED:
+ case -NFS4ERR_BAD_STATEID:
+ case -NFS4ERR_OPENMODE:
+ if (state == NULL)
+ break;
+ nfs4_state_mark_reclaim_nograce(clp, state);
case -NFS4ERR_STALE_CLIENTID:
case -NFS4ERR_STALE_STATEID:
case -NFS4ERR_EXPIRED:
rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL);
nfs4_schedule_state_recovery(clp);
- if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) == 0)
+ if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0)
rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task);
task->tk_status = 0;
return -EAGAIN;
@@ -2772,79 +2892,6 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server)
return 0;
}
-static int nfs4_wait_bit_killable(void *word)
-{
- if (fatal_signal_pending(current))
- return -ERESTARTSYS;
- schedule();
- return 0;
-}
-
-static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp)
-{
- int res;
-
- might_sleep();
-
- rwsem_acquire(&clp->cl_sem.dep_map, 0, 0, _RET_IP_);
-
- res = wait_on_bit(&clp->cl_state, NFS4CLNT_STATE_RECOVER,
- nfs4_wait_bit_killable, TASK_KILLABLE);
-
- rwsem_release(&clp->cl_sem.dep_map, 1, _RET_IP_);
- return res;
-}
-
-static int nfs4_delay(struct rpc_clnt *clnt, long *timeout)
-{
- int res = 0;
-
- might_sleep();
-
- if (*timeout <= 0)
- *timeout = NFS4_POLL_RETRY_MIN;
- if (*timeout > NFS4_POLL_RETRY_MAX)
- *timeout = NFS4_POLL_RETRY_MAX;
- schedule_timeout_killable(*timeout);
- if (fatal_signal_pending(current))
- res = -ERESTARTSYS;
- *timeout <<= 1;
- return res;
-}
-
-/* This is the error handling routine for processes that are allowed
- * to sleep.
- */
-static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception)
-{
- struct nfs_client *clp = server->nfs_client;
- int ret = errorcode;
-
- exception->retry = 0;
- switch(errorcode) {
- case 0:
- return 0;
- case -NFS4ERR_STALE_CLIENTID:
- case -NFS4ERR_STALE_STATEID:
- case -NFS4ERR_EXPIRED:
- nfs4_schedule_state_recovery(clp);
- ret = nfs4_wait_clnt_recover(server->client, clp);
- if (ret == 0)
- exception->retry = 1;
- break;
- case -NFS4ERR_FILE_OPEN:
- case -NFS4ERR_GRACE:
- case -NFS4ERR_DELAY:
- ret = nfs4_delay(server->client, &exception->timeout);
- if (ret != 0)
- break;
- case -NFS4ERR_OLD_STATEID:
- exception->retry = 1;
- }
- /* We failed to handle the error */
- return nfs4_map_errors(ret);
-}
-
int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short port, struct rpc_cred *cred)
{
nfs4_verifier sc_verifier;
@@ -2916,7 +2963,6 @@ static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cre
spin_lock(&clp->cl_lock);
clp->cl_lease_time = fsinfo.lease_time * HZ;
clp->cl_last_renewal = now;
- clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
spin_unlock(&clp->cl_lock);
}
return status;
@@ -3074,7 +3120,6 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock
struct nfs4_lock_state *lsp;
int status;
- down_read(&clp->cl_sem);
arg.lock_owner.clientid = clp->cl_clientid;
status = nfs4_set_lock_state(state, request);
if (status != 0)
@@ -3091,7 +3136,6 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock
}
request->fl_ops->fl_release_private(request);
out:
- up_read(&clp->cl_sem);
return status;
}
@@ -3181,11 +3225,13 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)
sizeof(calldata->lsp->ls_stateid.data));
renew_lease(calldata->server, calldata->timestamp);
break;
+ case -NFS4ERR_BAD_STATEID:
+ case -NFS4ERR_OLD_STATEID:
case -NFS4ERR_STALE_STATEID:
case -NFS4ERR_EXPIRED:
break;
default:
- if (nfs4_async_handle_error(task, calldata->server) == -EAGAIN)
+ if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN)
rpc_restart_call(task);
}
}
@@ -3248,6 +3294,7 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl,
static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request)
{
+ struct nfs_inode *nfsi = NFS_I(state->inode);
struct nfs_seqid *seqid;
struct nfs4_lock_state *lsp;
struct rpc_task *task;
@@ -3257,8 +3304,12 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *
status = nfs4_set_lock_state(state, request);
/* Unlock _before_ we do the RPC call */
request->fl_flags |= FL_EXISTS;
- if (do_vfs_lock(request->fl_file, request) == -ENOENT)
+ down_read(&nfsi->rwsem);
+ if (do_vfs_lock(request->fl_file, request) == -ENOENT) {
+ up_read(&nfsi->rwsem);
goto out;
+ }
+ up_read(&nfsi->rwsem);
if (status != 0)
goto out;
/* Is this a delegated lock? */
@@ -3484,7 +3535,7 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request
static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
{
- struct nfs_client *clp = state->owner->so_client;
+ struct nfs_inode *nfsi = NFS_I(state->inode);
unsigned char fl_flags = request->fl_flags;
int status;
@@ -3496,19 +3547,13 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock
status = do_vfs_lock(request->fl_file, request);
if (status < 0)
goto out;
- down_read(&clp->cl_sem);
+ down_read(&nfsi->rwsem);
if (test_bit(NFS_DELEGATED_STATE, &state->flags)) {
- struct nfs_inode *nfsi = NFS_I(state->inode);
/* Yes: cache locks! */
- down_read(&nfsi->rwsem);
/* ...but avoid races with delegation recall... */
- if (test_bit(NFS_DELEGATED_STATE, &state->flags)) {
- request->fl_flags = fl_flags & ~FL_SLEEP;
- status = do_vfs_lock(request->fl_file, request);
- up_read(&nfsi->rwsem);
- goto out_unlock;
- }
- up_read(&nfsi->rwsem);
+ request->fl_flags = fl_flags & ~FL_SLEEP;
+ status = do_vfs_lock(request->fl_file, request);
+ goto out_unlock;
}
status = _nfs4_do_setlk(state, cmd, request, 0);
if (status != 0)
@@ -3518,7 +3563,7 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock
if (do_vfs_lock(request->fl_file, request) < 0)
printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __func__);
out_unlock:
- up_read(&clp->cl_sem);
+ up_read(&nfsi->rwsem);
out:
request->fl_flags = fl_flags;
return status;
@@ -3664,11 +3709,15 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
}
struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = {
+ .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT,
+ .state_flag_bit = NFS_STATE_RECLAIM_REBOOT,
.recover_open = nfs4_open_reclaim,
.recover_lock = nfs4_lock_reclaim,
};
-struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops = {
+struct nfs4_state_recovery_ops nfs4_nograce_recovery_ops = {
+ .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE,
+ .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE,
.recover_open = nfs4_open_expired,
.recover_lock = nfs4_lock_expired,
};
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c
index 3305acbbe2a..f524e932ff7 100644
--- a/fs/nfs/nfs4renewd.c
+++ b/fs/nfs/nfs4renewd.c
@@ -65,7 +65,6 @@ nfs4_renew_state(struct work_struct *work)
long lease, timeout;
unsigned long last, now;
- down_read(&clp->cl_sem);
dprintk("%s: start\n", __func__);
/* Are there any active superblocks? */
if (list_empty(&clp->cl_superblocks))
@@ -77,17 +76,19 @@ nfs4_renew_state(struct work_struct *work)
timeout = (2 * lease) / 3 + (long)last - (long)now;
/* Are we close to a lease timeout? */
if (time_after(now, last + lease/3)) {
- cred = nfs4_get_renew_cred(clp);
+ cred = nfs4_get_renew_cred_locked(clp);
+ spin_unlock(&clp->cl_lock);
if (cred == NULL) {
- set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
- spin_unlock(&clp->cl_lock);
+ if (list_empty(&clp->cl_delegations)) {
+ set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
+ goto out;
+ }
nfs_expire_all_delegations(clp);
- goto out;
+ } else {
+ /* Queue an asynchronous RENEW. */
+ nfs4_proc_async_renew(clp, cred);
+ put_rpccred(cred);
}
- spin_unlock(&clp->cl_lock);
- /* Queue an asynchronous RENEW. */
- nfs4_proc_async_renew(clp, cred);
- put_rpccred(cred);
timeout = (2 * lease) / 3;
spin_lock(&clp->cl_lock);
} else
@@ -100,12 +101,11 @@ nfs4_renew_state(struct work_struct *work)
cancel_delayed_work(&clp->cl_renewd);
schedule_delayed_work(&clp->cl_renewd, timeout);
spin_unlock(&clp->cl_lock);
+ nfs_expire_unreferenced_delegations(clp);
out:
- up_read(&clp->cl_sem);
dprintk("%s: done\n", __func__);
}
-/* Must be called with clp->cl_sem locked for writes */
void
nfs4_schedule_state_renewal(struct nfs_client *clp)
{
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 401ef8b28f9..2022fe47966 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -71,14 +71,12 @@ static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred)
return status;
}
-static struct rpc_cred *nfs4_get_machine_cred(struct nfs_client *clp)
+static struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp)
{
struct rpc_cred *cred = NULL;
- spin_lock(&clp->cl_lock);
if (clp->cl_machine_cred != NULL)
cred = get_rpccred(clp->cl_machine_cred);
- spin_unlock(&clp->cl_lock);
return cred;
}
@@ -94,7 +92,7 @@ static void nfs4_clear_machine_cred(struct nfs_client *clp)
put_rpccred(cred);
}
-struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp)
+struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp)
{
struct nfs4_state_owner *sp;
struct rb_node *pos;
@@ -110,13 +108,24 @@ struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp)
return cred;
}
+static struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp)
+{
+ struct rpc_cred *cred;
+
+ spin_lock(&clp->cl_lock);
+ cred = nfs4_get_renew_cred_locked(clp);
+ spin_unlock(&clp->cl_lock);
+ return cred;
+}
+
static struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp)
{
struct nfs4_state_owner *sp;
struct rb_node *pos;
struct rpc_cred *cred;
- cred = nfs4_get_machine_cred(clp);
+ spin_lock(&clp->cl_lock);
+ cred = nfs4_get_machine_cred_locked(clp);
if (cred != NULL)
goto out;
pos = rb_first(&clp->cl_state_owners);
@@ -125,6 +134,7 @@ static struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp)
cred = get_rpccred(sp->so_cred);
}
out:
+ spin_unlock(&clp->cl_lock);
return cred;
}
@@ -295,10 +305,6 @@ nfs4_drop_state_owner(struct nfs4_state_owner *sp)
}
}
-/*
- * Note: must be called with clp->cl_sem held in order to prevent races
- * with reboot recovery!
- */
struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct rpc_cred *cred)
{
struct nfs_client *clp = server->nfs_client;
@@ -327,10 +333,6 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct
return sp;
}
-/*
- * Must be called with clp->cl_sem held in order to avoid races
- * with state recovery...
- */
void nfs4_put_state_owner(struct nfs4_state_owner *sp)
{
struct nfs_client *clp = sp->so_client;
@@ -361,18 +363,18 @@ nfs4_alloc_open_state(void)
}
void
-nfs4_state_set_mode_locked(struct nfs4_state *state, mode_t mode)
+nfs4_state_set_mode_locked(struct nfs4_state *state, fmode_t fmode)
{
- if (state->state == mode)
+ if (state->state == fmode)
return;
/* NB! List reordering - see the reclaim code for why. */
- if ((mode & FMODE_WRITE) != (state->state & FMODE_WRITE)) {
- if (mode & FMODE_WRITE)
+ if ((fmode & FMODE_WRITE) != (state->state & FMODE_WRITE)) {
+ if (fmode & FMODE_WRITE)
list_move(&state->open_states, &state->owner->so_states);
else
list_move_tail(&state->open_states, &state->owner->so_states);
}
- state->state = mode;
+ state->state = fmode;
}
static struct nfs4_state *
@@ -432,10 +434,6 @@ out:
return state;
}
-/*
- * Beware! Caller must be holding exactly one
- * reference to clp->cl_sem!
- */
void nfs4_put_open_state(struct nfs4_state *state)
{
struct inode *inode = state->inode;
@@ -456,16 +454,16 @@ void nfs4_put_open_state(struct nfs4_state *state)
/*
* Close the current file.
*/
-static void __nfs4_close(struct path *path, struct nfs4_state *state, mode_t mode, int wait)
+static void __nfs4_close(struct path *path, struct nfs4_state *state, fmode_t fmode, int wait)
{
struct nfs4_state_owner *owner = state->owner;
int call_close = 0;
- int newstate;
+ fmode_t newstate;
atomic_inc(&owner->so_count);
/* Protect against nfs4_find_state() */
spin_lock(&owner->so_lock);
- switch (mode & (FMODE_READ | FMODE_WRITE)) {
+ switch (fmode & (FMODE_READ | FMODE_WRITE)) {
case FMODE_READ:
state->n_rdonly--;
break;
@@ -500,14 +498,14 @@ static void __nfs4_close(struct path *path, struct nfs4_state *state, mode_t mod
nfs4_do_close(path, state, wait);
}
-void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode)
+void nfs4_close_state(struct path *path, struct nfs4_state *state, fmode_t fmode)
{
- __nfs4_close(path, state, mode, 0);
+ __nfs4_close(path, state, fmode, 0);
}
-void nfs4_close_sync(struct path *path, struct nfs4_state *state, mode_t mode)
+void nfs4_close_sync(struct path *path, struct nfs4_state *state, fmode_t fmode)
{
- __nfs4_close(path, state, mode, 1);
+ __nfs4_close(path, state, fmode, 1);
}
/*
@@ -568,7 +566,6 @@ static void nfs4_free_lock_state(struct nfs4_lock_state *lsp)
* Return a compatible lock_state. If no initialized lock_state structure
* exists, return an uninitialized one.
*
- * The caller must be holding clp->cl_sem
*/
static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner)
{
@@ -770,32 +767,34 @@ unlock:
return status;
}
-static int reclaimer(void *);
+static int nfs4_run_state_manager(void *);
-static inline void nfs4_clear_recover_bit(struct nfs_client *clp)
+static void nfs4_clear_state_manager_bit(struct nfs_client *clp)
{
smp_mb__before_clear_bit();
- clear_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state);
+ clear_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state);
smp_mb__after_clear_bit();
- wake_up_bit(&clp->cl_state, NFS4CLNT_STATE_RECOVER);
+ wake_up_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING);
rpc_wake_up(&clp->cl_rpcwaitq);
}
/*
- * State recovery routine
+ * Schedule the nfs_client asynchronous state management routine
*/
-static void nfs4_recover_state(struct nfs_client *clp)
+void nfs4_schedule_state_manager(struct nfs_client *clp)
{
struct task_struct *task;
+ if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
+ return;
__module_get(THIS_MODULE);
atomic_inc(&clp->cl_count);
- task = kthread_run(reclaimer, clp, "%s-reclaim",
+ task = kthread_run(nfs4_run_state_manager, clp, "%s-manager",
rpc_peeraddr2str(clp->cl_rpcclient,
RPC_DISPLAY_ADDR));
if (!IS_ERR(task))
return;
- nfs4_clear_recover_bit(clp);
+ nfs4_clear_state_manager_bit(clp);
nfs_put_client(clp);
module_put(THIS_MODULE);
}
@@ -807,16 +806,42 @@ void nfs4_schedule_state_recovery(struct nfs_client *clp)
{
if (!clp)
return;
- if (test_and_set_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) == 0)
- nfs4_recover_state(clp);
+ if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
+ set_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
+ nfs4_schedule_state_manager(clp);
}
-static int nfs4_reclaim_locks(struct nfs4_state_recovery_ops *ops, struct nfs4_state *state)
+static int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state)
+{
+
+ set_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags);
+ /* Don't recover state that expired before the reboot */
+ if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags)) {
+ clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags);
+ return 0;
+ }
+ set_bit(NFS_OWNER_RECLAIM_REBOOT, &state->owner->so_flags);
+ set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state);
+ return 1;
+}
+
+int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state)
+{
+ set_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags);
+ clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags);
+ set_bit(NFS_OWNER_RECLAIM_NOGRACE, &state->owner->so_flags);
+ set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state);
+ return 1;
+}
+
+static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops)
{
struct inode *inode = state->inode;
+ struct nfs_inode *nfsi = NFS_I(inode);
struct file_lock *fl;
int status = 0;
+ down_write(&nfsi->rwsem);
for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
continue;
@@ -839,12 +864,14 @@ static int nfs4_reclaim_locks(struct nfs4_state_recovery_ops *ops, struct nfs4_s
goto out_err;
}
}
+ up_write(&nfsi->rwsem);
return 0;
out_err:
+ up_write(&nfsi->rwsem);
return status;
}
-static int nfs4_reclaim_open_state(struct nfs4_state_recovery_ops *ops, struct nfs4_state_owner *sp)
+static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs4_state_recovery_ops *ops)
{
struct nfs4_state *state;
struct nfs4_lock_state *lock;
@@ -858,28 +885,34 @@ static int nfs4_reclaim_open_state(struct nfs4_state_recovery_ops *ops, struct n
* recovering after a network partition or a reboot from a
* server that doesn't support a grace period.
*/
+restart:
+ spin_lock(&sp->so_lock);
list_for_each_entry(state, &sp->so_states, open_states) {
+ if (!test_and_clear_bit(ops->state_flag_bit, &state->flags))
+ continue;
if (state->state == 0)
continue;
+ atomic_inc(&state->count);
+ spin_unlock(&sp->so_lock);
status = ops->recover_open(sp, state);
if (status >= 0) {
- status = nfs4_reclaim_locks(ops, state);
- if (status < 0)
- goto out_err;
- list_for_each_entry(lock, &state->lock_states, ls_locks) {
- if (!(lock->ls_flags & NFS_LOCK_INITIALIZED))
- printk("%s: Lock reclaim failed!\n",
+ status = nfs4_reclaim_locks(state, ops);
+ if (status >= 0) {
+ list_for_each_entry(lock, &state->lock_states, ls_locks) {
+ if (!(lock->ls_flags & NFS_LOCK_INITIALIZED))
+ printk("%s: Lock reclaim failed!\n",
__func__);
+ }
+ nfs4_put_open_state(state);
+ goto restart;
}
- continue;
}
switch (status) {
default:
printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n",
__func__, status);
case -ENOENT:
- case -NFS4ERR_RECLAIM_BAD:
- case -NFS4ERR_RECLAIM_CONFLICT:
+ case -ESTALE:
/*
* Open state on this file cannot be recovered
* All we can do is revert to using the zero stateid.
@@ -889,84 +922,176 @@ static int nfs4_reclaim_open_state(struct nfs4_state_recovery_ops *ops, struct n
/* Mark the file as being 'closed' */
state->state = 0;
break;
+ case -NFS4ERR_RECLAIM_BAD:
+ case -NFS4ERR_RECLAIM_CONFLICT:
+ nfs4_state_mark_reclaim_nograce(sp->so_client, state);
+ break;
case -NFS4ERR_EXPIRED:
case -NFS4ERR_NO_GRACE:
+ nfs4_state_mark_reclaim_nograce(sp->so_client, state);
case -NFS4ERR_STALE_CLIENTID:
goto out_err;
}
+ nfs4_put_open_state(state);
+ goto restart;
}
+ spin_unlock(&sp->so_lock);
return 0;
out_err:
+ nfs4_put_open_state(state);
return status;
}
-static void nfs4_state_mark_reclaim(struct nfs_client *clp)
+static void nfs4_clear_open_state(struct nfs4_state *state)
+{
+ struct nfs4_lock_state *lock;
+
+ clear_bit(NFS_DELEGATED_STATE, &state->flags);
+ clear_bit(NFS_O_RDONLY_STATE, &state->flags);
+ clear_bit(NFS_O_WRONLY_STATE, &state->flags);
+ clear_bit(NFS_O_RDWR_STATE, &state->flags);
+ list_for_each_entry(lock, &state->lock_states, ls_locks) {
+ lock->ls_seqid.flags = 0;
+ lock->ls_flags &= ~NFS_LOCK_INITIALIZED;
+ }
+}
+
+static void nfs4_state_mark_reclaim_helper(struct nfs_client *clp, int (*mark_reclaim)(struct nfs_client *clp, struct nfs4_state *state))
{
struct nfs4_state_owner *sp;
struct rb_node *pos;
struct nfs4_state *state;
- struct nfs4_lock_state *lock;
/* Reset all sequence ids to zero */
for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) {
sp = rb_entry(pos, struct nfs4_state_owner, so_client_node);
- sp->so_seqid.counter = 0;
sp->so_seqid.flags = 0;
spin_lock(&sp->so_lock);
list_for_each_entry(state, &sp->so_states, open_states) {
- clear_bit(NFS_DELEGATED_STATE, &state->flags);
- clear_bit(NFS_O_RDONLY_STATE, &state->flags);
- clear_bit(NFS_O_WRONLY_STATE, &state->flags);
- clear_bit(NFS_O_RDWR_STATE, &state->flags);
- list_for_each_entry(lock, &state->lock_states, ls_locks) {
- lock->ls_seqid.counter = 0;
- lock->ls_seqid.flags = 0;
- lock->ls_flags &= ~NFS_LOCK_INITIALIZED;
- }
+ if (mark_reclaim(clp, state))
+ nfs4_clear_open_state(state);
}
spin_unlock(&sp->so_lock);
}
}
-static int reclaimer(void *ptr)
+static void nfs4_state_start_reclaim_reboot(struct nfs_client *clp)
+{
+ /* Mark all delegations for reclaim */
+ nfs_delegation_mark_reclaim(clp);
+ nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_reboot);
+}
+
+static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp)
{
- struct nfs_client *clp = ptr;
struct nfs4_state_owner *sp;
struct rb_node *pos;
- struct nfs4_state_recovery_ops *ops;
- struct rpc_cred *cred;
+ struct nfs4_state *state;
+
+ if (!test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state))
+ return;
+
+ for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) {
+ sp = rb_entry(pos, struct nfs4_state_owner, so_client_node);
+ spin_lock(&sp->so_lock);
+ list_for_each_entry(state, &sp->so_states, open_states) {
+ if (!test_and_clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags))
+ continue;
+ nfs4_state_mark_reclaim_nograce(clp, state);
+ }
+ spin_unlock(&sp->so_lock);
+ }
+
+ nfs_delegation_reap_unclaimed(clp);
+}
+
+static void nfs_delegation_clear_all(struct nfs_client *clp)
+{
+ nfs_delegation_mark_reclaim(clp);
+ nfs_delegation_reap_unclaimed(clp);
+}
+
+static void nfs4_state_start_reclaim_nograce(struct nfs_client *clp)
+{
+ nfs_delegation_clear_all(clp);
+ nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_nograce);
+}
+
+static void nfs4_state_end_reclaim_nograce(struct nfs_client *clp)
+{
+ clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state);
+}
+
+static void nfs4_recovery_handle_error(struct nfs_client *clp, int error)
+{
+ switch (error) {
+ case -NFS4ERR_CB_PATH_DOWN:
+ nfs_handle_cb_pathdown(clp);
+ break;
+ case -NFS4ERR_STALE_CLIENTID:
+ case -NFS4ERR_LEASE_MOVED:
+ set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
+ nfs4_state_start_reclaim_reboot(clp);
+ break;
+ case -NFS4ERR_EXPIRED:
+ set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
+ nfs4_state_start_reclaim_nograce(clp);
+ }
+}
+
+static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recovery_ops *ops)
+{
+ struct rb_node *pos;
int status = 0;
- allow_signal(SIGKILL);
+restart:
+ spin_lock(&clp->cl_lock);
+ for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) {
+ struct nfs4_state_owner *sp = rb_entry(pos, struct nfs4_state_owner, so_client_node);
+ if (!test_and_clear_bit(ops->owner_flag_bit, &sp->so_flags))
+ continue;
+ atomic_inc(&sp->so_count);
+ spin_unlock(&clp->cl_lock);
+ status = nfs4_reclaim_open_state(sp, ops);
+ if (status < 0) {
+ set_bit(ops->owner_flag_bit, &sp->so_flags);
+ nfs4_put_state_owner(sp);
+ nfs4_recovery_handle_error(clp, status);
+ return status;
+ }
+ nfs4_put_state_owner(sp);
+ goto restart;
+ }
+ spin_unlock(&clp->cl_lock);
+ return status;
+}
- /* Ensure exclusive access to NFSv4 state */
- down_write(&clp->cl_sem);
- /* Are there any NFS mounts out there? */
- if (list_empty(&clp->cl_superblocks))
- goto out;
-restart_loop:
- ops = &nfs4_network_partition_recovery_ops;
- /* Are there any open files on this volume? */
+static int nfs4_check_lease(struct nfs_client *clp)
+{
+ struct rpc_cred *cred;
+ int status = -NFS4ERR_EXPIRED;
+
+ /* Is the client already known to have an expired lease? */
+ if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
+ return 0;
cred = nfs4_get_renew_cred(clp);
- if (cred != NULL) {
- /* Yes there are: try to renew the old lease */
- status = nfs4_proc_renew(clp, cred);
- put_rpccred(cred);
- switch (status) {
- case 0:
- case -NFS4ERR_CB_PATH_DOWN:
- goto out;
- case -NFS4ERR_STALE_CLIENTID:
- case -NFS4ERR_LEASE_MOVED:
- ops = &nfs4_reboot_recovery_ops;
- }
- } else {
- /* "reboot" to ensure we clear all state on the server */
- clp->cl_boot_time = CURRENT_TIME;
+ if (cred == NULL) {
+ cred = nfs4_get_setclientid_cred(clp);
+ if (cred == NULL)
+ goto out;
}
- /* We're going to have to re-establish a clientid */
- nfs4_state_mark_reclaim(clp);
- status = -ENOENT;
+ status = nfs4_proc_renew(clp, cred);
+ put_rpccred(cred);
+out:
+ nfs4_recovery_handle_error(clp, status);
+ return status;
+}
+
+static int nfs4_reclaim_lease(struct nfs_client *clp)
+{
+ struct rpc_cred *cred;
+ int status = -ENOENT;
+
cred = nfs4_get_setclientid_cred(clp);
if (cred != NULL) {
status = nfs4_init_client(clp, cred);
@@ -974,42 +1099,90 @@ restart_loop:
/* Handle case where the user hasn't set up machine creds */
if (status == -EACCES && cred == clp->cl_machine_cred) {
nfs4_clear_machine_cred(clp);
- goto restart_loop;
+ status = -EAGAIN;
}
}
- if (status)
- goto out_error;
- /* Mark all delegations for reclaim */
- nfs_delegation_mark_reclaim(clp);
- /* Note: list is protected by exclusive lock on cl->cl_sem */
- for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) {
- sp = rb_entry(pos, struct nfs4_state_owner, so_client_node);
- status = nfs4_reclaim_open_state(ops, sp);
- if (status < 0) {
- if (status == -NFS4ERR_NO_GRACE) {
- ops = &nfs4_network_partition_recovery_ops;
- status = nfs4_reclaim_open_state(ops, sp);
+ return status;
+}
+
+static void nfs4_state_manager(struct nfs_client *clp)
+{
+ int status = 0;
+
+ /* Ensure exclusive access to NFSv4 state */
+ for(;;) {
+ if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) {
+ /* We're going to have to re-establish a clientid */
+ status = nfs4_reclaim_lease(clp);
+ if (status) {
+ set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
+ if (status == -EAGAIN)
+ continue;
+ goto out_error;
}
+ clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
+ }
+
+ if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) {
+ status = nfs4_check_lease(clp);
+ if (status != 0)
+ continue;
+ }
+
+ /* First recover reboot state... */
+ if (test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) {
+ status = nfs4_do_reclaim(clp, &nfs4_reboot_recovery_ops);
if (status == -NFS4ERR_STALE_CLIENTID)
- goto restart_loop;
- if (status == -NFS4ERR_EXPIRED)
- goto restart_loop;
+ continue;
+ nfs4_state_end_reclaim_reboot(clp);
+ continue;
+ }
+
+ /* Now recover expired state... */
+ if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) {
+ status = nfs4_do_reclaim(clp, &nfs4_nograce_recovery_ops);
+ if (status < 0) {
+ set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state);
+ if (status == -NFS4ERR_STALE_CLIENTID)
+ continue;
+ if (status == -NFS4ERR_EXPIRED)
+ continue;
+ goto out_error;
+ } else
+ nfs4_state_end_reclaim_nograce(clp);
+ continue;
}
+
+ if (test_and_clear_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) {
+ nfs_client_return_marked_delegations(clp);
+ continue;
+ }
+
+ nfs4_clear_state_manager_bit(clp);
+ /* Did we race with an attempt to give us more work? */
+ if (clp->cl_state == 0)
+ break;
+ if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
+ break;
}
- nfs_delegation_reap_unclaimed(clp);
-out:
- up_write(&clp->cl_sem);
- if (status == -NFS4ERR_CB_PATH_DOWN)
- nfs_handle_cb_pathdown(clp);
- nfs4_clear_recover_bit(clp);
+ return;
+out_error:
+ printk(KERN_WARNING "Error: state manager failed on NFSv4 server %s"
+ " with error %d\n", clp->cl_hostname, -status);
+ if (test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state))
+ nfs4_state_end_reclaim_reboot(clp);
+ nfs4_clear_state_manager_bit(clp);
+}
+
+static int nfs4_run_state_manager(void *ptr)
+{
+ struct nfs_client *clp = ptr;
+
+ allow_signal(SIGKILL);
+ nfs4_state_manager(clp);
nfs_put_client(clp);
module_put_and_exit(0);
return 0;
-out_error:
- printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %s"
- " with error %d\n", clp->cl_hostname, -status);
- set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
- goto out;
}
/*
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index b916297d233..d1e4c8f8a0a 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -8,7 +8,7 @@
*
* Kendrick Smith <kmsmith@umich.edu>
* Andy Adamson <andros@umich.edu>
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -67,7 +67,7 @@ static int nfs4_stat_to_errno(int);
#define NFS4_MAXTAGLEN 0
#endif
-/* lock,open owner id:
+/* lock,open owner id:
* we currently use size 2 (u64) out of (NFS4_OPAQUE_LIMIT >> 2)
*/
#define open_owner_id_maxsz (1 + 4)
@@ -541,6 +541,7 @@ static struct {
struct compound_hdr {
int32_t status;
uint32_t nops;
+ __be32 * nops_p;
uint32_t taglen;
char * tag;
};
@@ -578,7 +579,7 @@ static void encode_string(struct xdr_stream *xdr, unsigned int len, const char *
xdr_encode_opaque(p, str, len);
}
-static int encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
+static void encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
{
__be32 *p;
@@ -588,8 +589,13 @@ static int encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
WRITE32(hdr->taglen);
WRITEMEM(hdr->tag, hdr->taglen);
WRITE32(NFS4_MINOR_VERSION);
+ hdr->nops_p = p;
WRITE32(hdr->nops);
- return 0;
+}
+
+static void encode_nops(struct compound_hdr *hdr)
+{
+ *hdr->nops_p = htonl(hdr->nops);
}
static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *verf)
@@ -601,7 +607,7 @@ static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *ve
xdr_encode_opaque_fixed(p, verf->data, NFS4_VERIFIER_SIZE);
}
-static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server)
+static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server)
{
char owner_name[IDMAP_NAMESZ];
char owner_group[IDMAP_NAMESZ];
@@ -612,7 +618,6 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
int len;
uint32_t bmval0 = 0;
uint32_t bmval1 = 0;
- int status;
/*
* We reserve enough space to write the entire attribute buffer at once.
@@ -709,7 +714,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
WRITE32(NFS4_SET_TO_SERVER_TIME);
}
-
+
/*
* Now we backfill the bitmap and the attribute buffer length.
*/
@@ -723,23 +728,20 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
*q++ = htonl(bmval1);
*q++ = htonl(len);
- status = 0;
/* out: */
- return status;
}
-static int encode_access(struct xdr_stream *xdr, u32 access)
+static void encode_access(struct xdr_stream *xdr, u32 access, struct compound_hdr *hdr)
{
__be32 *p;
RESERVE_SPACE(8);
WRITE32(OP_ACCESS);
WRITE32(access);
-
- return 0;
+ hdr->nops++;
}
-static int encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg)
+static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr)
{
__be32 *p;
@@ -747,26 +749,24 @@ static int encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg)
WRITE32(OP_CLOSE);
WRITE32(arg->seqid->sequence->counter);
WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE);
-
- return 0;
+ hdr->nops++;
}
-static int encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args)
+static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr)
{
__be32 *p;
-
- RESERVE_SPACE(16);
- WRITE32(OP_COMMIT);
- WRITE64(args->offset);
- WRITE32(args->count);
- return 0;
+ RESERVE_SPACE(16);
+ WRITE32(OP_COMMIT);
+ WRITE64(args->offset);
+ WRITE32(args->count);
+ hdr->nops++;
}
-static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create)
+static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create, struct compound_hdr *hdr)
{
__be32 *p;
-
+
RESERVE_SPACE(8);
WRITE32(OP_CREATE);
WRITE32(create->ftype);
@@ -791,64 +791,62 @@ static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *c
RESERVE_SPACE(4 + create->name->len);
WRITE32(create->name->len);
WRITEMEM(create->name->name, create->name->len);
+ hdr->nops++;
- return encode_attrs(xdr, create->attrs, create->server);
+ encode_attrs(xdr, create->attrs, create->server);
}
-static int encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap)
+static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct compound_hdr *hdr)
{
- __be32 *p;
+ __be32 *p;
- RESERVE_SPACE(12);
- WRITE32(OP_GETATTR);
- WRITE32(1);
- WRITE32(bitmap);
- return 0;
+ RESERVE_SPACE(12);
+ WRITE32(OP_GETATTR);
+ WRITE32(1);
+ WRITE32(bitmap);
+ hdr->nops++;
}
-static int encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1)
+static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1, struct compound_hdr *hdr)
{
- __be32 *p;
+ __be32 *p;
- RESERVE_SPACE(16);
- WRITE32(OP_GETATTR);
- WRITE32(2);
- WRITE32(bm0);
- WRITE32(bm1);
- return 0;
+ RESERVE_SPACE(16);
+ WRITE32(OP_GETATTR);
+ WRITE32(2);
+ WRITE32(bm0);
+ WRITE32(bm1);
+ hdr->nops++;
}
-static int encode_getfattr(struct xdr_stream *xdr, const u32* bitmask)
+static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
{
- return encode_getattr_two(xdr,
- bitmask[0] & nfs4_fattr_bitmap[0],
- bitmask[1] & nfs4_fattr_bitmap[1]);
+ encode_getattr_two(xdr, bitmask[0] & nfs4_fattr_bitmap[0],
+ bitmask[1] & nfs4_fattr_bitmap[1], hdr);
}
-static int encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask)
+static void encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
{
- return encode_getattr_two(xdr, bitmask[0] & nfs4_fsinfo_bitmap[0],
- bitmask[1] & nfs4_fsinfo_bitmap[1]);
+ encode_getattr_two(xdr, bitmask[0] & nfs4_fsinfo_bitmap[0],
+ bitmask[1] & nfs4_fsinfo_bitmap[1], hdr);
}
-static int encode_fs_locations(struct xdr_stream *xdr, const u32* bitmask)
+static void encode_fs_locations(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
{
- return encode_getattr_two(xdr,
- bitmask[0] & nfs4_fs_locations_bitmap[0],
- bitmask[1] & nfs4_fs_locations_bitmap[1]);
+ encode_getattr_two(xdr, bitmask[0] & nfs4_fs_locations_bitmap[0],
+ bitmask[1] & nfs4_fs_locations_bitmap[1], hdr);
}
-static int encode_getfh(struct xdr_stream *xdr)
+static void encode_getfh(struct xdr_stream *xdr, struct compound_hdr *hdr)
{
__be32 *p;
RESERVE_SPACE(4);
WRITE32(OP_GETFH);
-
- return 0;
+ hdr->nops++;
}
-static int encode_link(struct xdr_stream *xdr, const struct qstr *name)
+static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
{
__be32 *p;
@@ -856,8 +854,7 @@ static int encode_link(struct xdr_stream *xdr, const struct qstr *name)
WRITE32(OP_LINK);
WRITE32(name->len);
WRITEMEM(name->name, name->len);
-
- return 0;
+ hdr->nops++;
}
static inline int nfs4_lock_type(struct file_lock *fl, int block)
@@ -878,7 +875,7 @@ static inline uint64_t nfs4_lock_length(struct file_lock *fl)
* opcode,type,reclaim,offset,length,new_lock_owner = 32
* open_seqid,open_stateid,lock_seqid,lock_owner.clientid, lock_owner.id = 40
*/
-static int encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args)
+static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args, struct compound_hdr *hdr)
{
__be32 *p;
@@ -904,11 +901,10 @@ static int encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args)
WRITEMEM(args->lock_stateid->data, NFS4_STATEID_SIZE);
WRITE32(args->lock_seqid->sequence->counter);
}
-
- return 0;
+ hdr->nops++;
}
-static int encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args)
+static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args, struct compound_hdr *hdr)
{
__be32 *p;
@@ -921,11 +917,10 @@ static int encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *arg
WRITE32(16);
WRITEMEM("lock id:", 8);
WRITE64(args->lock_owner.id);
-
- return 0;
+ hdr->nops++;
}
-static int encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args)
+static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args, struct compound_hdr *hdr)
{
__be32 *p;
@@ -936,11 +931,10 @@ static int encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *arg
WRITEMEM(args->stateid->data, NFS4_STATEID_SIZE);
WRITE64(args->fl->fl_start);
WRITE64(nfs4_lock_length(args->fl));
-
- return 0;
+ hdr->nops++;
}
-static int encode_lookup(struct xdr_stream *xdr, const struct qstr *name)
+static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
{
int len = name->len;
__be32 *p;
@@ -949,27 +943,26 @@ static int encode_lookup(struct xdr_stream *xdr, const struct qstr *name)
WRITE32(OP_LOOKUP);
WRITE32(len);
WRITEMEM(name->name, len);
-
- return 0;
+ hdr->nops++;
}
-static void encode_share_access(struct xdr_stream *xdr, int open_flags)
+static void encode_share_access(struct xdr_stream *xdr, fmode_t fmode)
{
__be32 *p;
RESERVE_SPACE(8);
- switch (open_flags & (FMODE_READ|FMODE_WRITE)) {
- case FMODE_READ:
- WRITE32(NFS4_SHARE_ACCESS_READ);
- break;
- case FMODE_WRITE:
- WRITE32(NFS4_SHARE_ACCESS_WRITE);
- break;
- case FMODE_READ|FMODE_WRITE:
- WRITE32(NFS4_SHARE_ACCESS_BOTH);
- break;
- default:
- BUG();
+ switch (fmode & (FMODE_READ|FMODE_WRITE)) {
+ case FMODE_READ:
+ WRITE32(NFS4_SHARE_ACCESS_READ);
+ break;
+ case FMODE_WRITE:
+ WRITE32(NFS4_SHARE_ACCESS_WRITE);
+ break;
+ case FMODE_READ|FMODE_WRITE:
+ WRITE32(NFS4_SHARE_ACCESS_BOTH);
+ break;
+ default:
+ WRITE32(0);
}
WRITE32(0); /* for linux, share_deny = 0 always */
}
@@ -984,7 +977,7 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena
RESERVE_SPACE(8);
WRITE32(OP_OPEN);
WRITE32(arg->seqid->sequence->counter);
- encode_share_access(xdr, arg->open_flags);
+ encode_share_access(xdr, arg->fmode);
RESERVE_SPACE(28);
WRITE64(arg->clientid);
WRITE32(16);
@@ -998,13 +991,13 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op
RESERVE_SPACE(4);
switch(arg->open_flags & O_EXCL) {
- case 0:
- WRITE32(NFS4_CREATE_UNCHECKED);
- encode_attrs(xdr, arg->u.attrs, arg->server);
- break;
- default:
- WRITE32(NFS4_CREATE_EXCLUSIVE);
- encode_nfs4_verifier(xdr, &arg->u.verifier);
+ case 0:
+ WRITE32(NFS4_CREATE_UNCHECKED);
+ encode_attrs(xdr, arg->u.attrs, arg->server);
+ break;
+ default:
+ WRITE32(NFS4_CREATE_EXCLUSIVE);
+ encode_nfs4_verifier(xdr, &arg->u.verifier);
}
}
@@ -1014,33 +1007,33 @@ static void encode_opentype(struct xdr_stream *xdr, const struct nfs_openargs *a
RESERVE_SPACE(4);
switch (arg->open_flags & O_CREAT) {
- case 0:
- WRITE32(NFS4_OPEN_NOCREATE);
- break;
- default:
- BUG_ON(arg->claim != NFS4_OPEN_CLAIM_NULL);
- WRITE32(NFS4_OPEN_CREATE);
- encode_createmode(xdr, arg);
+ case 0:
+ WRITE32(NFS4_OPEN_NOCREATE);
+ break;
+ default:
+ BUG_ON(arg->claim != NFS4_OPEN_CLAIM_NULL);
+ WRITE32(NFS4_OPEN_CREATE);
+ encode_createmode(xdr, arg);
}
}
-static inline void encode_delegation_type(struct xdr_stream *xdr, int delegation_type)
+static inline void encode_delegation_type(struct xdr_stream *xdr, fmode_t delegation_type)
{
__be32 *p;
RESERVE_SPACE(4);
switch (delegation_type) {
- case 0:
- WRITE32(NFS4_OPEN_DELEGATE_NONE);
- break;
- case FMODE_READ:
- WRITE32(NFS4_OPEN_DELEGATE_READ);
- break;
- case FMODE_WRITE|FMODE_READ:
- WRITE32(NFS4_OPEN_DELEGATE_WRITE);
- break;
- default:
- BUG();
+ case 0:
+ WRITE32(NFS4_OPEN_DELEGATE_NONE);
+ break;
+ case FMODE_READ:
+ WRITE32(NFS4_OPEN_DELEGATE_READ);
+ break;
+ case FMODE_WRITE|FMODE_READ:
+ WRITE32(NFS4_OPEN_DELEGATE_WRITE);
+ break;
+ default:
+ BUG();
}
}
@@ -1053,7 +1046,7 @@ static inline void encode_claim_null(struct xdr_stream *xdr, const struct qstr *
encode_string(xdr, name->len, name->name);
}
-static inline void encode_claim_previous(struct xdr_stream *xdr, int type)
+static inline void encode_claim_previous(struct xdr_stream *xdr, fmode_t type)
{
__be32 *p;
@@ -1072,27 +1065,27 @@ static inline void encode_claim_delegate_cur(struct xdr_stream *xdr, const struc
encode_string(xdr, name->len, name->name);
}
-static int encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg)
+static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg, struct compound_hdr *hdr)
{
encode_openhdr(xdr, arg);
encode_opentype(xdr, arg);
switch (arg->claim) {
- case NFS4_OPEN_CLAIM_NULL:
- encode_claim_null(xdr, arg->name);
- break;
- case NFS4_OPEN_CLAIM_PREVIOUS:
- encode_claim_previous(xdr, arg->u.delegation_type);
- break;
- case NFS4_OPEN_CLAIM_DELEGATE_CUR:
- encode_claim_delegate_cur(xdr, arg->name, &arg->u.delegation);
- break;
- default:
- BUG();
+ case NFS4_OPEN_CLAIM_NULL:
+ encode_claim_null(xdr, arg->name);
+ break;
+ case NFS4_OPEN_CLAIM_PREVIOUS:
+ encode_claim_previous(xdr, arg->u.delegation_type);
+ break;
+ case NFS4_OPEN_CLAIM_DELEGATE_CUR:
+ encode_claim_delegate_cur(xdr, arg->name, &arg->u.delegation);
+ break;
+ default:
+ BUG();
}
- return 0;
+ hdr->nops++;
}
-static int encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg)
+static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg, struct compound_hdr *hdr)
{
__be32 *p;
@@ -1100,11 +1093,10 @@ static int encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_con
WRITE32(OP_OPEN_CONFIRM);
WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE);
WRITE32(arg->seqid->sequence->counter);
-
- return 0;
+ hdr->nops++;
}
-static int encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg)
+static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr)
{
__be32 *p;
@@ -1112,12 +1104,12 @@ static int encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closea
WRITE32(OP_OPEN_DOWNGRADE);
WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE);
WRITE32(arg->seqid->sequence->counter);
- encode_share_access(xdr, arg->open_flags);
- return 0;
+ encode_share_access(xdr, arg->fmode);
+ hdr->nops++;
}
-static int
-encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh)
+static void
+encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh, struct compound_hdr *hdr)
{
int len = fh->size;
__be32 *p;
@@ -1126,18 +1118,16 @@ encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh)
WRITE32(OP_PUTFH);
WRITE32(len);
WRITEMEM(fh->data, len);
-
- return 0;
+ hdr->nops++;
}
-static int encode_putrootfh(struct xdr_stream *xdr)
+static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr)
{
- __be32 *p;
-
- RESERVE_SPACE(4);
- WRITE32(OP_PUTROOTFH);
+ __be32 *p;
- return 0;
+ RESERVE_SPACE(4);
+ WRITE32(OP_PUTROOTFH);
+ hdr->nops++;
}
static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx)
@@ -1153,7 +1143,7 @@ static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context
WRITEMEM(zero_stateid.data, NFS4_STATEID_SIZE);
}
-static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args)
+static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, struct compound_hdr *hdr)
{
__be32 *p;
@@ -1165,11 +1155,10 @@ static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args)
RESERVE_SPACE(12);
WRITE64(args->offset);
WRITE32(args->count);
-
- return 0;
+ hdr->nops++;
}
-static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req)
+static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr)
{
uint32_t attrs[2] = {
FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID,
@@ -1191,6 +1180,7 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
WRITE32(attrs[0] & readdir->bitmask[0]);
WRITE32(attrs[1] & readdir->bitmask[1]);
+ hdr->nops++;
dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n",
__func__,
(unsigned long long)readdir->cookie,
@@ -1198,21 +1188,18 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
((u32 *)readdir->verifier.data)[1],
attrs[0] & readdir->bitmask[0],
attrs[1] & readdir->bitmask[1]);
-
- return 0;
}
-static int encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req)
+static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req, struct compound_hdr *hdr)
{
__be32 *p;
RESERVE_SPACE(4);
WRITE32(OP_READLINK);
-
- return 0;
+ hdr->nops++;
}
-static int encode_remove(struct xdr_stream *xdr, const struct qstr *name)
+static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
{
__be32 *p;
@@ -1220,11 +1207,10 @@ static int encode_remove(struct xdr_stream *xdr, const struct qstr *name)
WRITE32(OP_REMOVE);
WRITE32(name->len);
WRITEMEM(name->name, name->len);
-
- return 0;
+ hdr->nops++;
}
-static int encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname)
+static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname, struct compound_hdr *hdr)
{
__be32 *p;
@@ -1232,38 +1218,35 @@ static int encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, con
WRITE32(OP_RENAME);
WRITE32(oldname->len);
WRITEMEM(oldname->name, oldname->len);
-
+
RESERVE_SPACE(4 + newname->len);
WRITE32(newname->len);
WRITEMEM(newname->name, newname->len);
-
- return 0;
+ hdr->nops++;
}
-static int encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid)
+static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid, struct compound_hdr *hdr)
{
__be32 *p;
RESERVE_SPACE(12);
WRITE32(OP_RENEW);
WRITE64(client_stateid->cl_clientid);
-
- return 0;
+ hdr->nops++;
}
-static int
-encode_restorefh(struct xdr_stream *xdr)
+static void
+encode_restorefh(struct xdr_stream *xdr, struct compound_hdr *hdr)
{
__be32 *p;
RESERVE_SPACE(4);
WRITE32(OP_RESTOREFH);
-
- return 0;
+ hdr->nops++;
}
static int
-encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg)
+encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compound_hdr *hdr)
{
__be32 *p;
@@ -1278,36 +1261,32 @@ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg)
RESERVE_SPACE(4);
WRITE32(arg->acl_len);
xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len);
+ hdr->nops++;
return 0;
}
-static int
-encode_savefh(struct xdr_stream *xdr)
+static void
+encode_savefh(struct xdr_stream *xdr, struct compound_hdr *hdr)
{
__be32 *p;
RESERVE_SPACE(4);
WRITE32(OP_SAVEFH);
-
- return 0;
+ hdr->nops++;
}
-static int encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server)
+static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server, struct compound_hdr *hdr)
{
- int status;
__be32 *p;
-
- RESERVE_SPACE(4+NFS4_STATEID_SIZE);
- WRITE32(OP_SETATTR);
- WRITEMEM(arg->stateid.data, NFS4_STATEID_SIZE);
- if ((status = encode_attrs(xdr, arg->iap, server)))
- return status;
-
- return 0;
+ RESERVE_SPACE(4+NFS4_STATEID_SIZE);
+ WRITE32(OP_SETATTR);
+ WRITEMEM(arg->stateid.data, NFS4_STATEID_SIZE);
+ hdr->nops++;
+ encode_attrs(xdr, arg->iap, server);
}
-static int encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid)
+static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid, struct compound_hdr *hdr)
{
__be32 *p;
@@ -1322,23 +1301,21 @@ static int encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclien
encode_string(xdr, setclientid->sc_uaddr_len, setclientid->sc_uaddr);
RESERVE_SPACE(4);
WRITE32(setclientid->sc_cb_ident);
-
- return 0;
+ hdr->nops++;
}
-static int encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state)
+static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state, struct compound_hdr *hdr)
{
- __be32 *p;
-
- RESERVE_SPACE(12 + NFS4_VERIFIER_SIZE);
- WRITE32(OP_SETCLIENTID_CONFIRM);
- WRITE64(client_state->cl_clientid);
- WRITEMEM(client_state->cl_confirm.data, NFS4_VERIFIER_SIZE);
+ __be32 *p;
- return 0;
+ RESERVE_SPACE(12 + NFS4_VERIFIER_SIZE);
+ WRITE32(OP_SETCLIENTID_CONFIRM);
+ WRITE64(client_state->cl_clientid);
+ WRITEMEM(client_state->cl_confirm.data, NFS4_VERIFIER_SIZE);
+ hdr->nops++;
}
-static int encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args)
+static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr)
{
__be32 *p;
@@ -1353,11 +1330,10 @@ static int encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args
WRITE32(args->count);
xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
-
- return 0;
+ hdr->nops++;
}
-static int encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid)
+static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid, struct compound_hdr *hdr)
{
__be32 *p;
@@ -1365,8 +1341,7 @@ static int encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *statei
WRITE32(OP_DELEGRETURN);
WRITEMEM(stateid->data, NFS4_STATEID_SIZE);
- return 0;
-
+ hdr->nops++;
}
/*
* END OF "GENERIC" ENCODE ROUTINES.
@@ -1379,21 +1354,16 @@ static int nfs4_xdr_enc_access(struct rpc_rqst *req, __be32 *p, const struct nfs
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 3,
+ .nops = 0,
};
- int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- status = encode_putfh(&xdr, args->fh);
- if (status != 0)
- goto out;
- status = encode_access(&xdr, args->access);
- if (status != 0)
- goto out;
- status = encode_getfattr(&xdr, args->bitmask);
-out:
- return status;
+ encode_putfh(&xdr, args->fh, &hdr);
+ encode_access(&xdr, args->access, &hdr);
+ encode_getfattr(&xdr, args->bitmask, &hdr);
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -1403,21 +1373,17 @@ static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, __be32 *p, const struct nfs
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 4,
+ .nops = 0,
};
- int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
- goto out;
- if ((status = encode_lookup(&xdr, args->name)) != 0)
- goto out;
- if ((status = encode_getfh(&xdr)) != 0)
- goto out;
- status = encode_getfattr(&xdr, args->bitmask);
-out:
- return status;
+ encode_putfh(&xdr, args->dir_fh, &hdr);
+ encode_lookup(&xdr, args->name, &hdr);
+ encode_getfh(&xdr, &hdr);
+ encode_getfattr(&xdr, args->bitmask, &hdr);
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -1427,18 +1393,16 @@ static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, __be32 *p, const struc
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 3,
+ .nops = 0,
};
- int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- if ((status = encode_putrootfh(&xdr)) != 0)
- goto out;
- if ((status = encode_getfh(&xdr)) == 0)
- status = encode_getfattr(&xdr, args->bitmask);
-out:
- return status;
+ encode_putrootfh(&xdr, &hdr);
+ encode_getfh(&xdr, &hdr);
+ encode_getfattr(&xdr, args->bitmask, &hdr);
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -1448,19 +1412,16 @@ static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 3,
+ .nops = 0,
};
- int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- if ((status = encode_putfh(&xdr, args->fh)) != 0)
- goto out;
- if ((status = encode_remove(&xdr, &args->name)) != 0)
- goto out;
- status = encode_getfattr(&xdr, args->bitmask);
-out:
- return status;
+ encode_putfh(&xdr, args->fh, &hdr);
+ encode_remove(&xdr, &args->name, &hdr);
+ encode_getfattr(&xdr, args->bitmask, &hdr);
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -1470,27 +1431,20 @@ static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 7,
+ .nops = 0,
};
- int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- if ((status = encode_putfh(&xdr, args->old_dir)) != 0)
- goto out;
- if ((status = encode_savefh(&xdr)) != 0)
- goto out;
- if ((status = encode_putfh(&xdr, args->new_dir)) != 0)
- goto out;
- if ((status = encode_rename(&xdr, args->old_name, args->new_name)) != 0)
- goto out;
- if ((status = encode_getfattr(&xdr, args->bitmask)) != 0)
- goto out;
- if ((status = encode_restorefh(&xdr)) != 0)
- goto out;
- status = encode_getfattr(&xdr, args->bitmask);
-out:
- return status;
+ encode_putfh(&xdr, args->old_dir, &hdr);
+ encode_savefh(&xdr, &hdr);
+ encode_putfh(&xdr, args->new_dir, &hdr);
+ encode_rename(&xdr, args->old_name, args->new_name, &hdr);
+ encode_getfattr(&xdr, args->bitmask, &hdr);
+ encode_restorefh(&xdr, &hdr);
+ encode_getfattr(&xdr, args->bitmask, &hdr);
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -1500,27 +1454,20 @@ static int nfs4_xdr_enc_link(struct rpc_rqst *req, __be32 *p, const struct nfs4_
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 7,
+ .nops = 0,
};
- int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- if ((status = encode_putfh(&xdr, args->fh)) != 0)
- goto out;
- if ((status = encode_savefh(&xdr)) != 0)
- goto out;
- if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
- goto out;
- if ((status = encode_link(&xdr, args->name)) != 0)
- goto out;
- if ((status = encode_getfattr(&xdr, args->bitmask)) != 0)
- goto out;
- if ((status = encode_restorefh(&xdr)) != 0)
- goto out;
- status = encode_getfattr(&xdr, args->bitmask);
-out:
- return status;
+ encode_putfh(&xdr, args->fh, &hdr);
+ encode_savefh(&xdr, &hdr);
+ encode_putfh(&xdr, args->dir_fh, &hdr);
+ encode_link(&xdr, args->name, &hdr);
+ encode_getfattr(&xdr, args->bitmask, &hdr);
+ encode_restorefh(&xdr, &hdr);
+ encode_getfattr(&xdr, args->bitmask, &hdr);
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -1530,27 +1477,20 @@ static int nfs4_xdr_enc_create(struct rpc_rqst *req, __be32 *p, const struct nfs
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 7,
+ .nops = 0,
};
- int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
- goto out;
- if ((status = encode_savefh(&xdr)) != 0)
- goto out;
- if ((status = encode_create(&xdr, args)) != 0)
- goto out;
- if ((status = encode_getfh(&xdr)) != 0)
- goto out;
- if ((status = encode_getfattr(&xdr, args->bitmask)) != 0)
- goto out;
- if ((status = encode_restorefh(&xdr)) != 0)
- goto out;
- status = encode_getfattr(&xdr, args->bitmask);
-out:
- return status;
+ encode_putfh(&xdr, args->dir_fh, &hdr);
+ encode_savefh(&xdr, &hdr);
+ encode_create(&xdr, args, &hdr);
+ encode_getfh(&xdr, &hdr);
+ encode_getfattr(&xdr, args->bitmask, &hdr);
+ encode_restorefh(&xdr, &hdr);
+ encode_getfattr(&xdr, args->bitmask, &hdr);
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -1568,15 +1508,15 @@ static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, __be32 *p, const struct nf
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 2,
+ .nops = 0,
};
- int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- if ((status = encode_putfh(&xdr, args->fh)) == 0)
- status = encode_getfattr(&xdr, args->bitmask);
- return status;
+ encode_putfh(&xdr, args->fh, &hdr);
+ encode_getfattr(&xdr, args->bitmask, &hdr);
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -1584,23 +1524,18 @@ static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, __be32 *p, const struct nf
*/
static int nfs4_xdr_enc_close(struct rpc_rqst *req, __be32 *p, struct nfs_closeargs *args)
{
- struct xdr_stream xdr;
- struct compound_hdr hdr = {
- .nops = 3,
- };
- int status;
-
- xdr_init_encode(&xdr, &req->rq_snd_buf, p);
- encode_compound_hdr(&xdr, &hdr);
- status = encode_putfh(&xdr, args->fh);
- if(status)
- goto out;
- status = encode_close(&xdr, args);
- if (status != 0)
- goto out;
- status = encode_getfattr(&xdr, args->bitmask);
-out:
- return status;
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+ .nops = 0,
+ };
+
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+ encode_compound_hdr(&xdr, &hdr);
+ encode_putfh(&xdr, args->fh, &hdr);
+ encode_close(&xdr, args, &hdr);
+ encode_getfattr(&xdr, args->bitmask, &hdr);
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -1610,33 +1545,20 @@ static int nfs4_xdr_enc_open(struct rpc_rqst *req, __be32 *p, struct nfs_openarg
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 7,
+ .nops = 0,
};
- int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- status = encode_putfh(&xdr, args->fh);
- if (status)
- goto out;
- status = encode_savefh(&xdr);
- if (status)
- goto out;
- status = encode_open(&xdr, args);
- if (status)
- goto out;
- status = encode_getfh(&xdr);
- if (status)
- goto out;
- status = encode_getfattr(&xdr, args->bitmask);
- if (status)
- goto out;
- status = encode_restorefh(&xdr);
- if (status)
- goto out;
- status = encode_getfattr(&xdr, args->bitmask);
-out:
- return status;
+ encode_putfh(&xdr, args->fh, &hdr);
+ encode_savefh(&xdr, &hdr);
+ encode_open(&xdr, args, &hdr);
+ encode_getfh(&xdr, &hdr);
+ encode_getfattr(&xdr, args->bitmask, &hdr);
+ encode_restorefh(&xdr, &hdr);
+ encode_getfattr(&xdr, args->bitmask, &hdr);
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -1646,18 +1568,15 @@ static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, __be32 *p, struct nfs
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 2,
+ .nops = 0,
};
- int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- status = encode_putfh(&xdr, args->fh);
- if(status)
- goto out;
- status = encode_open_confirm(&xdr, args);
-out:
- return status;
+ encode_putfh(&xdr, args->fh, &hdr);
+ encode_open_confirm(&xdr, args, &hdr);
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -1667,21 +1586,16 @@ static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, __be32 *p, struct nfs_
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 3,
+ .nops = 0,
};
- int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- status = encode_putfh(&xdr, args->fh);
- if (status)
- goto out;
- status = encode_open(&xdr, args);
- if (status)
- goto out;
- status = encode_getfattr(&xdr, args->bitmask);
-out:
- return status;
+ encode_putfh(&xdr, args->fh, &hdr);
+ encode_open(&xdr, args, &hdr);
+ encode_getfattr(&xdr, args->bitmask, &hdr);
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -1691,21 +1605,16 @@ static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, __be32 *p, struct n
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 3,
+ .nops = 0,
};
- int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- status = encode_putfh(&xdr, args->fh);
- if (status)
- goto out;
- status = encode_open_downgrade(&xdr, args);
- if (status != 0)
- goto out;
- status = encode_getfattr(&xdr, args->bitmask);
-out:
- return status;
+ encode_putfh(&xdr, args->fh, &hdr);
+ encode_open_downgrade(&xdr, args, &hdr);
+ encode_getfattr(&xdr, args->bitmask, &hdr);
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -1715,18 +1624,15 @@ static int nfs4_xdr_enc_lock(struct rpc_rqst *req, __be32 *p, struct nfs_lock_ar
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 2,
+ .nops = 0,
};
- int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- status = encode_putfh(&xdr, args->fh);
- if(status)
- goto out;
- status = encode_lock(&xdr, args);
-out:
- return status;
+ encode_putfh(&xdr, args->fh, &hdr);
+ encode_lock(&xdr, args, &hdr);
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -1736,18 +1642,15 @@ static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, __be32 *p, struct nfs_lockt_
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 2,
+ .nops = 0,
};
- int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- status = encode_putfh(&xdr, args->fh);
- if(status)
- goto out;
- status = encode_lockt(&xdr, args);
-out:
- return status;
+ encode_putfh(&xdr, args->fh, &hdr);
+ encode_lockt(&xdr, args, &hdr);
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -1757,18 +1660,15 @@ static int nfs4_xdr_enc_locku(struct rpc_rqst *req, __be32 *p, struct nfs_locku_
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 2,
+ .nops = 0,
};
- int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- status = encode_putfh(&xdr, args->fh);
- if(status)
- goto out;
- status = encode_locku(&xdr, args);
-out:
- return status;
+ encode_putfh(&xdr, args->fh, &hdr);
+ encode_locku(&xdr, args, &hdr);
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -1778,18 +1678,15 @@ static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, __be32 *p, const struct n
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 2,
+ .nops = 0,
};
struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
unsigned int replen;
- int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- status = encode_putfh(&xdr, args->fh);
- if(status)
- goto out;
- status = encode_readlink(&xdr, args, req);
+ encode_putfh(&xdr, args->fh, &hdr);
+ encode_readlink(&xdr, args, req, &hdr);
/* set up reply kvec
* toplevel_status + taglen + rescount + OP_PUTFH + status
@@ -1798,9 +1695,8 @@ static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, __be32 *p, const struct n
replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_readlink_sz) << 2;
xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages,
args->pgbase, args->pglen);
-
-out:
- return status;
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -1810,18 +1706,15 @@ static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nf
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 2,
+ .nops = 0,
};
struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
int replen;
- int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- status = encode_putfh(&xdr, args->fh);
- if(status)
- goto out;
- status = encode_readdir(&xdr, args, req);
+ encode_putfh(&xdr, args->fh, &hdr);
+ encode_readdir(&xdr, args, req, &hdr);
/* set up reply kvec
* toplevel_status + taglen + rescount + OP_PUTFH + status
@@ -1833,9 +1726,8 @@ static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nf
dprintk("%s: inlined page args = (%u, %p, %u, %u)\n",
__func__, replen, args->pages,
args->pgbase, args->count);
-
-out:
- return status;
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -1846,18 +1738,14 @@ static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readarg
struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 2,
+ .nops = 0,
};
- int replen, status;
+ int replen;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- status = encode_putfh(&xdr, args->fh);
- if (status)
- goto out;
- status = encode_read(&xdr, args);
- if (status)
- goto out;
+ encode_putfh(&xdr, args->fh, &hdr);
+ encode_read(&xdr, args, &hdr);
/* set up reply kvec
* toplevel status + taglen=0 + rescount + OP_PUTFH + status
@@ -1867,33 +1755,27 @@ static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readarg
xdr_inline_pages(&req->rq_rcv_buf, replen,
args->pages, args->pgbase, args->count);
req->rq_rcv_buf.flags |= XDRBUF_READ;
-out:
- return status;
+ encode_nops(&hdr);
+ return 0;
}
/*
* Encode an SETATTR request
*/
static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, __be32 *p, struct nfs_setattrargs *args)
-
{
- struct xdr_stream xdr;
- struct compound_hdr hdr = {
- .nops = 3,
- };
- int status;
-
- xdr_init_encode(&xdr, &req->rq_snd_buf, p);
- encode_compound_hdr(&xdr, &hdr);
- status = encode_putfh(&xdr, args->fh);
- if(status)
- goto out;
- status = encode_setattr(&xdr, args, args->server);
- if(status)
- goto out;
- status = encode_getfattr(&xdr, args->bitmask);
-out:
- return status;
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+ .nops = 0,
+ };
+
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+ encode_compound_hdr(&xdr, &hdr);
+ encode_putfh(&xdr, args->fh, &hdr);
+ encode_setattr(&xdr, args, args->server, &hdr);
+ encode_getfattr(&xdr, args->bitmask, &hdr);
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -1906,22 +1788,21 @@ nfs4_xdr_enc_getacl(struct rpc_rqst *req, __be32 *p,
struct xdr_stream xdr;
struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
struct compound_hdr hdr = {
- .nops = 2,
+ .nops = 0,
};
- int replen, status;
+ int replen;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- status = encode_putfh(&xdr, args->fh);
- if (status)
- goto out;
- status = encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0);
+ encode_putfh(&xdr, args->fh, &hdr);
+ encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0, &hdr);
+
/* set up reply buffer: */
replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_getacl_sz) << 2;
xdr_inline_pages(&req->rq_rcv_buf, replen,
args->acl_pages, args->acl_pgbase, args->acl_len);
-out:
- return status;
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -1931,22 +1812,17 @@ static int nfs4_xdr_enc_write(struct rpc_rqst *req, __be32 *p, struct nfs_writea
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 3,
+ .nops = 0,
};
- int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- status = encode_putfh(&xdr, args->fh);
- if (status)
- goto out;
- status = encode_write(&xdr, args);
- if (status)
- goto out;
+ encode_putfh(&xdr, args->fh, &hdr);
+ encode_write(&xdr, args, &hdr);
req->rq_snd_buf.flags |= XDRBUF_WRITE;
- status = encode_getfattr(&xdr, args->bitmask);
-out:
- return status;
+ encode_getfattr(&xdr, args->bitmask, &hdr);
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -1956,21 +1832,16 @@ static int nfs4_xdr_enc_commit(struct rpc_rqst *req, __be32 *p, struct nfs_write
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 3,
+ .nops = 0,
};
- int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- status = encode_putfh(&xdr, args->fh);
- if (status)
- goto out;
- status = encode_commit(&xdr, args);
- if (status)
- goto out;
- status = encode_getfattr(&xdr, args->bitmask);
-out:
- return status;
+ encode_putfh(&xdr, args->fh, &hdr);
+ encode_commit(&xdr, args, &hdr);
+ encode_getfattr(&xdr, args->bitmask, &hdr);
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -1980,16 +1851,15 @@ static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs4_fsin
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 2,
+ .nops = 0,
};
- int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- status = encode_putfh(&xdr, args->fh);
- if (!status)
- status = encode_fsinfo(&xdr, args->bitmask);
- return status;
+ encode_putfh(&xdr, args->fh, &hdr);
+ encode_fsinfo(&xdr, args->bitmask, &hdr);
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -1999,17 +1869,16 @@ static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, __be32 *p, const struct n
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 2,
+ .nops = 0,
};
- int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- status = encode_putfh(&xdr, args->fh);
- if (!status)
- status = encode_getattr_one(&xdr,
- args->bitmask[0] & nfs4_pathconf_bitmap[0]);
- return status;
+ encode_putfh(&xdr, args->fh, &hdr);
+ encode_getattr_one(&xdr, args->bitmask[0] & nfs4_pathconf_bitmap[0],
+ &hdr);
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -2019,18 +1888,16 @@ static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, __be32 *p, const struct nfs
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 2,
+ .nops = 0,
};
- int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- status = encode_putfh(&xdr, args->fh);
- if (status == 0)
- status = encode_getattr_two(&xdr,
- args->bitmask[0] & nfs4_statfs_bitmap[0],
- args->bitmask[1] & nfs4_statfs_bitmap[1]);
- return status;
+ encode_putfh(&xdr, args->fh, &hdr);
+ encode_getattr_two(&xdr, args->bitmask[0] & nfs4_statfs_bitmap[0],
+ args->bitmask[1] & nfs4_statfs_bitmap[1], &hdr);
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -2040,19 +1907,18 @@ static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, __be32 *p, const struc
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 2,
+ .nops = 0,
};
- int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- status = encode_putfh(&xdr, fhandle);
- if (status == 0)
- status = encode_getattr_one(&xdr, FATTR4_WORD0_SUPPORTED_ATTRS|
- FATTR4_WORD0_LINK_SUPPORT|
- FATTR4_WORD0_SYMLINK_SUPPORT|
- FATTR4_WORD0_ACLSUPPORT);
- return status;
+ encode_putfh(&xdr, fhandle, &hdr);
+ encode_getattr_one(&xdr, FATTR4_WORD0_SUPPORTED_ATTRS|
+ FATTR4_WORD0_LINK_SUPPORT|
+ FATTR4_WORD0_SYMLINK_SUPPORT|
+ FATTR4_WORD0_ACLSUPPORT, &hdr);
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -2062,12 +1928,14 @@ static int nfs4_xdr_enc_renew(struct rpc_rqst *req, __be32 *p, struct nfs_client
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 1,
+ .nops = 0,
};
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- return encode_renew(&xdr, clp);
+ encode_renew(&xdr, clp, &hdr);
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -2077,12 +1945,14 @@ static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, __be32 *p, struct nfs4
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 1,
+ .nops = 0,
};
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- return encode_setclientid(&xdr, sc);
+ encode_setclientid(&xdr, sc, &hdr);
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -2092,19 +1962,17 @@ static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, str
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 3,
+ .nops = 0,
};
const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 };
- int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- status = encode_setclientid_confirm(&xdr, clp);
- if (!status)
- status = encode_putrootfh(&xdr);
- if (!status)
- status = encode_fsinfo(&xdr, lease_bitmap);
- return status;
+ encode_setclientid_confirm(&xdr, clp, &hdr);
+ encode_putrootfh(&xdr, &hdr);
+ encode_fsinfo(&xdr, lease_bitmap, &hdr);
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -2114,21 +1982,16 @@ static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, __be32 *p, const struc
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 3,
+ .nops = 0,
};
- int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- status = encode_putfh(&xdr, args->fhandle);
- if (status != 0)
- goto out;
- status = encode_delegreturn(&xdr, args->stateid);
- if (status != 0)
- goto out;
- status = encode_getfattr(&xdr, args->bitmask);
-out:
- return status;
+ encode_putfh(&xdr, args->fhandle, &hdr);
+ encode_delegreturn(&xdr, args->stateid, &hdr);
+ encode_getfattr(&xdr, args->bitmask, &hdr);
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -2138,20 +2001,17 @@ static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
- .nops = 3,
+ .nops = 0,
};
struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
int replen;
- int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
encode_compound_hdr(&xdr, &hdr);
- if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
- goto out;
- if ((status = encode_lookup(&xdr, args->name)) != 0)
- goto out;
- if ((status = encode_fs_locations(&xdr, args->bitmask)) != 0)
- goto out;
+ encode_putfh(&xdr, args->dir_fh, &hdr);
+ encode_lookup(&xdr, args->name, &hdr);
+ encode_fs_locations(&xdr, args->bitmask, &hdr);
+
/* set up reply
* toplevel_status + OP_PUTFH + status
* + OP_LOOKUP + status + OP_GETATTR + status = 7
@@ -2159,8 +2019,8 @@ static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs
replen = (RPC_REPHDRSIZE + auth->au_rslack + 7) << 2;
xdr_inline_pages(&req->rq_rcv_buf, replen, &args->page,
0, PAGE_SIZE);
-out:
- return status;
+ encode_nops(&hdr);
+ return 0;
}
/*
@@ -2217,11 +2077,13 @@ static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
READ_BUF(8);
READ32(hdr->status);
READ32(hdr->taglen);
-
+
READ_BUF(hdr->taglen + 4);
hdr->tag = (char *)p;
p += XDR_QUADLEN(hdr->taglen);
READ32(hdr->nops);
+ if (unlikely(hdr->nops < 1))
+ return nfs4_stat_to_errno(hdr->status);
return 0;
}
@@ -3047,8 +2909,7 @@ static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res)
{
__be32 *savep;
- uint32_t attrlen,
- bitmap[2] = {0};
+ uint32_t attrlen, bitmap[2] = {0};
int status;
if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
@@ -3070,14 +2931,13 @@ xdr_error:
dprintk("%s: xdr returned %d!\n", __func__, -status);
return status;
}
-
+
static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat)
{
__be32 *savep;
- uint32_t attrlen,
- bitmap[2] = {0};
+ uint32_t attrlen, bitmap[2] = {0};
int status;
-
+
if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
goto xdr_error;
if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
@@ -3107,10 +2967,9 @@ xdr_error:
static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf)
{
__be32 *savep;
- uint32_t attrlen,
- bitmap[2] = {0};
+ uint32_t attrlen, bitmap[2] = {0};
int status;
-
+
if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
goto xdr_error;
if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
@@ -3256,7 +3115,7 @@ static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh)
static int decode_link(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
{
int status;
-
+
status = decode_op_hdr(xdr, OP_LINK);
if (status)
return status;
@@ -3344,27 +3203,27 @@ static int decode_lookup(struct xdr_stream *xdr)
/* This is too sick! */
static int decode_space_limit(struct xdr_stream *xdr, u64 *maxsize)
{
- __be32 *p;
+ __be32 *p;
uint32_t limit_type, nblocks, blocksize;
READ_BUF(12);
READ32(limit_type);
switch (limit_type) {
- case 1:
- READ64(*maxsize);
- break;
- case 2:
- READ32(nblocks);
- READ32(blocksize);
- *maxsize = (uint64_t)nblocks * (uint64_t)blocksize;
+ case 1:
+ READ64(*maxsize);
+ break;
+ case 2:
+ READ32(nblocks);
+ READ32(blocksize);
+ *maxsize = (uint64_t)nblocks * (uint64_t)blocksize;
}
return 0;
}
static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
{
- __be32 *p;
- uint32_t delegation_type;
+ __be32 *p;
+ uint32_t delegation_type;
READ_BUF(4);
READ32(delegation_type);
@@ -3375,13 +3234,14 @@ static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
READ_BUF(NFS4_STATEID_SIZE+4);
COPYMEM(res->delegation.data, NFS4_STATEID_SIZE);
READ32(res->do_recall);
+
switch (delegation_type) {
- case NFS4_OPEN_DELEGATE_READ:
- res->delegation_type = FMODE_READ;
- break;
- case NFS4_OPEN_DELEGATE_WRITE:
- res->delegation_type = FMODE_WRITE|FMODE_READ;
- if (decode_space_limit(xdr, &res->maxsize) < 0)
+ case NFS4_OPEN_DELEGATE_READ:
+ res->delegation_type = FMODE_READ;
+ break;
+ case NFS4_OPEN_DELEGATE_WRITE:
+ res->delegation_type = FMODE_WRITE|FMODE_READ;
+ if (decode_space_limit(xdr, &res->maxsize) < 0)
return -EIO;
}
return decode_ace(xdr, NULL, res->server->nfs_client);
@@ -3389,27 +3249,27 @@ static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
{
- __be32 *p;
+ __be32 *p;
uint32_t savewords, bmlen, i;
- int status;
+ int status;
- status = decode_op_hdr(xdr, OP_OPEN);
+ status = decode_op_hdr(xdr, OP_OPEN);
if (status != -EIO)
nfs_increment_open_seqid(status, res->seqid);
- if (status)
- return status;
- READ_BUF(NFS4_STATEID_SIZE);
- COPYMEM(res->stateid.data, NFS4_STATEID_SIZE);
+ if (status)
+ return status;
+ READ_BUF(NFS4_STATEID_SIZE);
+ COPYMEM(res->stateid.data, NFS4_STATEID_SIZE);
- decode_change_info(xdr, &res->cinfo);
+ decode_change_info(xdr, &res->cinfo);
- READ_BUF(8);
- READ32(res->rflags);
- READ32(bmlen);
- if (bmlen > 10)
- goto xdr_error;
+ READ_BUF(8);
+ READ32(res->rflags);
+ READ32(bmlen);
+ if (bmlen > 10)
+ goto xdr_error;
- READ_BUF(bmlen << 2);
+ READ_BUF(bmlen << 2);
savewords = min_t(uint32_t, bmlen, NFS4_BITMAP_SIZE);
for (i = 0; i < savewords; ++i)
READ32(res->attrset[i]);
@@ -3424,17 +3284,17 @@ xdr_error:
static int decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res)
{
- __be32 *p;
+ __be32 *p;
int status;
- status = decode_op_hdr(xdr, OP_OPEN_CONFIRM);
+ status = decode_op_hdr(xdr, OP_OPEN_CONFIRM);
if (status != -EIO)
nfs_increment_open_seqid(status, res->seqid);
- if (status)
- return status;
- READ_BUF(NFS4_STATEID_SIZE);
- COPYMEM(res->stateid.data, NFS4_STATEID_SIZE);
- return 0;
+ if (status)
+ return status;
+ READ_BUF(NFS4_STATEID_SIZE);
+ COPYMEM(res->stateid.data, NFS4_STATEID_SIZE);
+ return 0;
}
static int decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *res)
@@ -3562,7 +3422,7 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
dprintk("NFS: readdir reply truncated!\n");
entry[1] = 1;
}
-out:
+out:
kunmap_atomic(kaddr, KM_USER0);
return 0;
short_pkt:
@@ -3718,7 +3578,6 @@ static int decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res)
uint32_t bmlen;
int status;
-
status = decode_op_hdr(xdr, OP_SETATTR);
if (status)
return status;
@@ -3738,7 +3597,7 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp)
READ32(opnum);
if (opnum != OP_SETCLIENTID) {
dprintk("nfs: decode_setclientid: Server returned operation"
- " %d\n", opnum);
+ " %d\n", opnum);
return -EIO;
}
READ32(nfserr);
@@ -3792,34 +3651,34 @@ static int decode_delegreturn(struct xdr_stream *xdr)
}
/*
+ * END OF "GENERIC" DECODE ROUTINES.
+ */
+
+/*
* Decode OPEN_DOWNGRADE response
*/
static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res)
{
- struct xdr_stream xdr;
- struct compound_hdr hdr;
- int status;
-
- xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
- status = decode_compound_hdr(&xdr, &hdr);
- if (status)
- goto out;
- status = decode_putfh(&xdr);
- if (status)
- goto out;
- status = decode_open_downgrade(&xdr, res);
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+ int status;
+
+ xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+ status = decode_compound_hdr(&xdr, &hdr);
+ if (status)
+ goto out;
+ status = decode_putfh(&xdr);
+ if (status)
+ goto out;
+ status = decode_open_downgrade(&xdr, res);
if (status != 0)
goto out;
decode_getfattr(&xdr, res->fattr, res->server);
out:
- return status;
+ return status;
}
/*
- * END OF "GENERIC" DECODE ROUTINES.
- */
-
-/*
* Decode ACCESS response
*/
static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_accessres *res)
@@ -3827,7 +3686,7 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_ac
struct xdr_stream xdr;
struct compound_hdr hdr;
int status;
-
+
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
goto out;
@@ -3850,7 +3709,7 @@ static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lo
struct xdr_stream xdr;
struct compound_hdr hdr;
int status;
-
+
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
goto out;
@@ -3873,7 +3732,7 @@ static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, __be32 *p, struct nf
struct xdr_stream xdr;
struct compound_hdr hdr;
int status;
-
+
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
goto out;
@@ -3893,7 +3752,7 @@ static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs_rem
struct xdr_stream xdr;
struct compound_hdr hdr;
int status;
-
+
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
goto out;
@@ -3914,7 +3773,7 @@ static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_re
struct xdr_stream xdr;
struct compound_hdr hdr;
int status;
-
+
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
goto out;
@@ -3944,7 +3803,7 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_link
struct xdr_stream xdr;
struct compound_hdr hdr;
int status;
-
+
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
goto out;
@@ -3977,7 +3836,7 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_cr
struct xdr_stream xdr;
struct compound_hdr hdr;
int status;
-
+
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
goto out;
@@ -4014,7 +3873,7 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_g
struct xdr_stream xdr;
struct compound_hdr hdr;
int status;
-
+
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
status = decode_compound_hdr(&xdr, &hdr);
if (status)
@@ -4025,7 +3884,6 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_g
status = decode_getfattr(&xdr, res->fattr, res->server);
out:
return status;
-
}
/*
@@ -4034,21 +3892,20 @@ out:
static int
nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args)
{
- struct xdr_stream xdr;
- struct compound_hdr hdr = {
- .nops = 2,
- };
- int status;
-
- xdr_init_encode(&xdr, &req->rq_snd_buf, p);
- encode_compound_hdr(&xdr, &hdr);
- status = encode_putfh(&xdr, args->fh);
- if (status)
- goto out;
- status = encode_setacl(&xdr, args);
-out:
- return status;
+ struct xdr_stream xdr;
+ struct compound_hdr hdr = {
+ .nops = 0,
+ };
+ int status;
+
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+ encode_compound_hdr(&xdr, &hdr);
+ encode_putfh(&xdr, args->fh, &hdr);
+ status = encode_setacl(&xdr, args, &hdr);
+ encode_nops(&hdr);
+ return status;
}
+
/*
* Decode SETACL response
*/
@@ -4099,18 +3956,18 @@ out:
*/
static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res)
{
- struct xdr_stream xdr;
- struct compound_hdr hdr;
- int status;
-
- xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
- status = decode_compound_hdr(&xdr, &hdr);
- if (status)
- goto out;
- status = decode_putfh(&xdr);
- if (status)
- goto out;
- status = decode_close(&xdr, res);
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+ int status;
+
+ xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+ status = decode_compound_hdr(&xdr, &hdr);
+ if (status)
+ goto out;
+ status = decode_putfh(&xdr);
+ if (status)
+ goto out;
+ status = decode_close(&xdr, res);
if (status != 0)
goto out;
/*
@@ -4121,7 +3978,7 @@ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, __be32 *p, struct nfs_clos
*/
decode_getfattr(&xdr, res->fattr, res->server);
out:
- return status;
+ return status;
}
/*
@@ -4129,23 +3986,23 @@ out:
*/
static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res)
{
- struct xdr_stream xdr;
- struct compound_hdr hdr;
- int status;
-
- xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
- status = decode_compound_hdr(&xdr, &hdr);
- if (status)
- goto out;
- status = decode_putfh(&xdr);
- if (status)
- goto out;
- status = decode_savefh(&xdr);
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+ int status;
+
+ xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+ status = decode_compound_hdr(&xdr, &hdr);
+ if (status)
+ goto out;
+ status = decode_putfh(&xdr);
+ if (status)
+ goto out;
+ status = decode_savefh(&xdr);
+ if (status)
+ goto out;
+ status = decode_open(&xdr, res);
if (status)
goto out;
- status = decode_open(&xdr, res);
- if (status)
- goto out;
if (decode_getfh(&xdr, &res->fh) != 0)
goto out;
if (decode_getfattr(&xdr, res->f_attr, res->server) != 0)
@@ -4154,7 +4011,7 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openr
goto out;
decode_getfattr(&xdr, res->dir_attr, res->server);
out:
- return status;
+ return status;
}
/*
@@ -4162,20 +4019,20 @@ out:
*/
static int nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, __be32 *p, struct nfs_open_confirmres *res)
{
- struct xdr_stream xdr;
- struct compound_hdr hdr;
- int status;
-
- xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
- status = decode_compound_hdr(&xdr, &hdr);
- if (status)
- goto out;
- status = decode_putfh(&xdr);
- if (status)
- goto out;
- status = decode_open_confirm(&xdr, res);
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+ int status;
+
+ xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+ status = decode_compound_hdr(&xdr, &hdr);
+ if (status)
+ goto out;
+ status = decode_putfh(&xdr);
+ if (status)
+ goto out;
+ status = decode_open_confirm(&xdr, res);
out:
- return status;
+ return status;
}
/*
@@ -4183,23 +4040,23 @@ out:
*/
static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res)
{
- struct xdr_stream xdr;
- struct compound_hdr hdr;
- int status;
-
- xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
- status = decode_compound_hdr(&xdr, &hdr);
- if (status)
- goto out;
- status = decode_putfh(&xdr);
- if (status)
- goto out;
- status = decode_open(&xdr, res);
- if (status)
- goto out;
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+ int status;
+
+ xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+ status = decode_compound_hdr(&xdr, &hdr);
+ if (status)
+ goto out;
+ status = decode_putfh(&xdr);
+ if (status)
+ goto out;
+ status = decode_open(&xdr, res);
+ if (status)
+ goto out;
decode_getfattr(&xdr, res->f_attr, res->server);
out:
- return status;
+ return status;
}
/*
@@ -4207,25 +4064,25 @@ out:
*/
static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_setattrres *res)
{
- struct xdr_stream xdr;
- struct compound_hdr hdr;
- int status;
-
- xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
- status = decode_compound_hdr(&xdr, &hdr);
- if (status)
- goto out;
- status = decode_putfh(&xdr);
- if (status)
- goto out;
- status = decode_setattr(&xdr, res);
- if (status)
- goto out;
+ struct xdr_stream xdr;
+ struct compound_hdr hdr;
+ int status;
+
+ xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+ status = decode_compound_hdr(&xdr, &hdr);
+ if (status)
+ goto out;
+ status = decode_putfh(&xdr);
+ if (status)
+ goto out;
+ status = decode_setattr(&xdr, res);
+ if (status)
+ goto out;
status = decode_getfattr(&xdr, res->fattr, res->server);
if (status == NFS4ERR_DELAY)
status = 0;
out:
- return status;
+ return status;
}
/*
@@ -4421,8 +4278,6 @@ static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs_fsinf
status = decode_putfh(&xdr);
if (!status)
status = decode_fsinfo(&xdr, fsinfo);
- if (!status)
- status = nfs4_stat_to_errno(hdr.status);
return status;
}
@@ -4511,8 +4366,6 @@ static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p,
status = decode_compound_hdr(&xdr, &hdr);
if (!status)
status = decode_setclientid(&xdr, clp);
- if (!status)
- status = nfs4_stat_to_errno(hdr.status);
return status;
}
@@ -4533,8 +4386,6 @@ static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, __be32 *p, str
status = decode_putrootfh(&xdr);
if (!status)
status = decode_fsinfo(&xdr, fsinfo);
- if (!status)
- status = nfs4_stat_to_errno(hdr.status);
return status;
}
@@ -4715,7 +4566,7 @@ nfs4_stat_to_errno(int stat)
.p_replen = NFS4_##restype##_sz, \
.p_statidx = NFSPROC4_CLNT_##proc, \
.p_name = #proc, \
- }
+}
struct rpc_procinfo nfs4_procedures[] = {
PROC(READ, enc_read, dec_read),
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index 8478fc25dae..d9ef602fbc5 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -86,6 +86,8 @@
#include <net/ipconfig.h>
#include <linux/parser.h>
+#include "internal.h"
+
/* Define this to allow debugging output */
#undef NFSROOT_DEBUG
#define NFSDBG_FACILITY NFSDBG_ROOT
@@ -100,7 +102,7 @@ static char nfs_root_name[256] __initdata = "";
static __be32 servaddr __initdata = 0;
/* Name of directory to mount */
-static char nfs_path[NFS_MAXPATHLEN] __initdata = { 0, };
+static char nfs_export_path[NFS_MAXPATHLEN] __initdata = { 0, };
/* NFS-related data */
static struct nfs_mount_data nfs_data __initdata = { 0, };/* NFS mount info */
@@ -312,7 +314,7 @@ static int __init root_nfs_name(char *name)
printk(KERN_ERR "Root-NFS: Pathname for remote directory too long.\n");
return -1;
}
- sprintf(nfs_path, buf, cp);
+ sprintf(nfs_export_path, buf, cp);
return 1;
}
@@ -329,7 +331,7 @@ static int __init root_nfs_addr(void)
}
snprintf(nfs_data.hostname, sizeof(nfs_data.hostname),
- "%u.%u.%u.%u", NIPQUAD(servaddr));
+ "%pI4", &servaddr);
return 0;
}
@@ -340,7 +342,7 @@ static int __init root_nfs_addr(void)
static void __init root_nfs_print(void)
{
printk(KERN_NOTICE "Root-NFS: Mounting %s on server %s as root\n",
- nfs_path, nfs_data.hostname);
+ nfs_export_path, nfs_data.hostname);
printk(KERN_NOTICE "Root-NFS: rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
nfs_data.rsize, nfs_data.wsize, nfs_data.timeo, nfs_data.retrans);
printk(KERN_NOTICE "Root-NFS: acreg (min,max) = (%d,%d), acdir (min,max) = (%d,%d)\n",
@@ -421,8 +423,8 @@ static int __init root_nfs_getport(int program, int version, int proto)
{
struct sockaddr_in sin;
- printk(KERN_NOTICE "Looking up port of RPC %d/%d on %u.%u.%u.%u\n",
- program, version, NIPQUAD(servaddr));
+ printk(KERN_NOTICE "Looking up port of RPC %d/%d on %pI4\n",
+ program, version, &servaddr);
set_sockaddr(&sin, servaddr, 0);
return rpcb_getport_sync(&sin, program, version, proto);
}
@@ -485,18 +487,23 @@ static int __init root_nfs_get_handle(void)
{
struct nfs_fh fh;
struct sockaddr_in sin;
+ struct nfs_mount_request request = {
+ .sap = (struct sockaddr *)&sin,
+ .salen = sizeof(sin),
+ .dirpath = nfs_export_path,
+ .version = (nfs_data.flags & NFS_MOUNT_VER3) ?
+ NFS_MNT3_VERSION : NFS_MNT_VERSION,
+ .protocol = (nfs_data.flags & NFS_MOUNT_TCP) ?
+ XPRT_TRANSPORT_TCP : XPRT_TRANSPORT_UDP,
+ .fh = &fh,
+ };
int status;
- int protocol = (nfs_data.flags & NFS_MOUNT_TCP) ?
- XPRT_TRANSPORT_TCP : XPRT_TRANSPORT_UDP;
- int version = (nfs_data.flags & NFS_MOUNT_VER3) ?
- NFS_MNT3_VERSION : NFS_MNT_VERSION;
set_sockaddr(&sin, servaddr, htons(mount_port));
- status = nfs_mount((struct sockaddr *) &sin, sizeof(sin), NULL,
- nfs_path, version, protocol, &fh);
+ status = nfs_mount(&request);
if (status < 0)
printk(KERN_ERR "Root-NFS: Server returned error %d "
- "while mounting %s\n", status, nfs_path);
+ "while mounting %s\n", status, nfs_export_path);
else {
nfs_data.root.size = fh.size;
memcpy(nfs_data.root.data, fh.data, fh.size);
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 40d17987d0e..f856004bb7f 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -533,12 +533,6 @@ readpage_async_filler(void *data, struct page *page)
unsigned int len;
int error;
- error = nfs_wb_page(inode, page);
- if (error)
- goto out_unlock;
- if (PageUptodate(page))
- goto out_unlock;
-
len = nfs_page_length(page);
if (len == 0)
return nfs_return_empty_page(page);
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index f48db679a1c..d6686f4786d 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -75,6 +75,7 @@ enum {
Opt_acl, Opt_noacl,
Opt_rdirplus, Opt_nordirplus,
Opt_sharecache, Opt_nosharecache,
+ Opt_resvport, Opt_noresvport,
/* Mount options that take integer arguments */
Opt_port,
@@ -129,6 +130,8 @@ static const match_table_t nfs_mount_option_tokens = {
{ Opt_nordirplus, "nordirplus" },
{ Opt_sharecache, "sharecache" },
{ Opt_nosharecache, "nosharecache" },
+ { Opt_resvport, "resvport" },
+ { Opt_noresvport, "noresvport" },
{ Opt_port, "port=%u" },
{ Opt_rsize, "rsize=%u" },
@@ -462,14 +465,12 @@ static void nfs_show_mountd_options(struct seq_file *m, struct nfs_server *nfss,
switch (sap->sa_family) {
case AF_INET: {
struct sockaddr_in *sin = (struct sockaddr_in *)sap;
- seq_printf(m, ",mountaddr=" NIPQUAD_FMT,
- NIPQUAD(sin->sin_addr.s_addr));
+ seq_printf(m, ",mountaddr=%pI4", &sin->sin_addr.s_addr);
break;
}
case AF_INET6: {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
- seq_printf(m, ",mountaddr=" NIP6_FMT,
- NIP6(sin6->sin6_addr));
+ seq_printf(m, ",mountaddr=%pI6", &sin6->sin6_addr);
break;
}
default:
@@ -514,7 +515,8 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
{ NFS_MOUNT_NONLM, ",nolock", "" },
{ NFS_MOUNT_NOACL, ",noacl", "" },
{ NFS_MOUNT_NORDIRPLUS, ",nordirplus", "" },
- { NFS_MOUNT_UNSHARED, ",nosharecache", ""},
+ { NFS_MOUNT_UNSHARED, ",nosharecache", "" },
+ { NFS_MOUNT_NORESVPORT, ",noresvport", "" },
{ 0, NULL, NULL }
};
const struct proc_nfs_info *nfs_infop;
@@ -1035,6 +1037,12 @@ static int nfs_parse_mount_options(char *raw,
case Opt_nosharecache:
mnt->flags |= NFS_MOUNT_UNSHARED;
break;
+ case Opt_resvport:
+ mnt->flags &= ~NFS_MOUNT_NORESVPORT;
+ break;
+ case Opt_noresvport:
+ mnt->flags |= NFS_MOUNT_NORESVPORT;
+ break;
/*
* options that take numeric values
@@ -1329,8 +1337,14 @@ out_security_failure:
static int nfs_try_mount(struct nfs_parsed_mount_data *args,
struct nfs_fh *root_fh)
{
- struct sockaddr *sap = (struct sockaddr *)&args->mount_server.address;
- char *hostname;
+ struct nfs_mount_request request = {
+ .sap = (struct sockaddr *)
+ &args->mount_server.address,
+ .dirpath = args->nfs_server.export_path,
+ .protocol = args->mount_server.protocol,
+ .fh = root_fh,
+ .noresvport = args->flags & NFS_MOUNT_NORESVPORT,
+ };
int status;
if (args->mount_server.version == 0) {
@@ -1339,42 +1353,38 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args,
else
args->mount_server.version = NFS_MNT_VERSION;
}
+ request.version = args->mount_server.version;
if (args->mount_server.hostname)
- hostname = args->mount_server.hostname;
+ request.hostname = args->mount_server.hostname;
else
- hostname = args->nfs_server.hostname;
+ request.hostname = args->nfs_server.hostname;
/*
* Construct the mount server's address.
*/
if (args->mount_server.address.ss_family == AF_UNSPEC) {
- memcpy(sap, &args->nfs_server.address,
+ memcpy(request.sap, &args->nfs_server.address,
args->nfs_server.addrlen);
args->mount_server.addrlen = args->nfs_server.addrlen;
}
+ request.salen = args->mount_server.addrlen;
/*
* autobind will be used if mount_server.port == 0
*/
- nfs_set_port(sap, args->mount_server.port);
+ nfs_set_port(request.sap, args->mount_server.port);
/*
* Now ask the mount server to map our export path
* to a file handle.
*/
- status = nfs_mount(sap,
- args->mount_server.addrlen,
- hostname,
- args->nfs_server.export_path,
- args->mount_server.version,
- args->mount_server.protocol,
- root_fh);
+ status = nfs_mount(&request);
if (status == 0)
return 0;
dfprintk(MOUNT, "NFS: unable to mount server %s, error %d\n",
- hostname, status);
+ request.hostname, status);
return status;
}
@@ -2421,7 +2431,7 @@ static void nfs4_kill_super(struct super_block *sb)
{
struct nfs_server *server = NFS_SB(sb);
- nfs_return_all_delegations(sb);
+ nfs_super_return_all_delegations(sb);
kill_anon_super(sb);
nfs4_renewd_prepare_shutdown(server);
diff --git a/fs/nfs_common/nfsacl.c b/fs/nfs_common/nfsacl.c
index c11f5375d7c..04133aacb1e 100644
--- a/fs/nfs_common/nfsacl.c
+++ b/fs/nfs_common/nfsacl.c
@@ -29,8 +29,8 @@
MODULE_LICENSE("GPL");
-EXPORT_SYMBOL(nfsacl_encode);
-EXPORT_SYMBOL(nfsacl_decode);
+EXPORT_SYMBOL_GPL(nfsacl_encode);
+EXPORT_SYMBOL_GPL(nfsacl_decode);
struct nfsacl_encode_desc {
struct xdr_array2_desc desc;
diff --git a/fs/nfsctl.c b/fs/nfsctl.c
index aed8145d908..b27451909df 100644
--- a/fs/nfsctl.c
+++ b/fs/nfsctl.c
@@ -10,6 +10,8 @@
#include <linux/sunrpc/svc.h>
#include <linux/nfsd/nfsd.h>
#include <linux/nfsd/syscall.h>
+#include <linux/cred.h>
+#include <linux/sched.h>
#include <linux/linkage.h>
#include <linux/namei.h>
#include <linux/mount.h>
@@ -36,12 +38,14 @@ static struct file *do_open(char *name, int flags)
return ERR_PTR(error);
if (flags == O_RDWR)
- error = may_open(&nd,MAY_READ|MAY_WRITE,FMODE_READ|FMODE_WRITE);
+ error = may_open(&nd.path, MAY_READ|MAY_WRITE,
+ FMODE_READ|FMODE_WRITE);
else
- error = may_open(&nd, MAY_WRITE, FMODE_WRITE);
+ error = may_open(&nd.path, MAY_WRITE, FMODE_WRITE);
if (!error)
- return dentry_open(nd.path.dentry, nd.path.mnt, flags);
+ return dentry_open(nd.path.dentry, nd.path.mnt, flags,
+ current_cred());
path_put(&nd.path);
return ERR_PTR(error);
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c
index 294992e9bf6..0184fe9b514 100644
--- a/fs/nfsd/auth.c
+++ b/fs/nfsd/auth.c
@@ -27,53 +27,70 @@ int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp)
int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
{
- struct svc_cred cred = rqstp->rq_cred;
+ struct group_info *rqgi;
+ struct group_info *gi;
+ struct cred *new;
int i;
int flags = nfsexp_flags(rqstp, exp);
int ret;
+ /* discard any old override before preparing the new set */
+ revert_creds(get_cred(current->real_cred));
+ new = prepare_creds();
+ if (!new)
+ return -ENOMEM;
+
+ new->fsuid = rqstp->rq_cred.cr_uid;
+ new->fsgid = rqstp->rq_cred.cr_gid;
+
+ rqgi = rqstp->rq_cred.cr_group_info;
+
if (flags & NFSEXP_ALLSQUASH) {
- cred.cr_uid = exp->ex_anon_uid;
- cred.cr_gid = exp->ex_anon_gid;
- cred.cr_group_info = groups_alloc(0);
+ new->fsuid = exp->ex_anon_uid;
+ new->fsgid = exp->ex_anon_gid;
+ gi = groups_alloc(0);
} else if (flags & NFSEXP_ROOTSQUASH) {
- struct group_info *gi;
- if (!cred.cr_uid)
- cred.cr_uid = exp->ex_anon_uid;
- if (!cred.cr_gid)
- cred.cr_gid = exp->ex_anon_gid;
- gi = groups_alloc(cred.cr_group_info->ngroups);
- if (gi)
- for (i = 0; i < cred.cr_group_info->ngroups; i++) {
- if (!GROUP_AT(cred.cr_group_info, i))
- GROUP_AT(gi, i) = exp->ex_anon_gid;
- else
- GROUP_AT(gi, i) = GROUP_AT(cred.cr_group_info, i);
- }
- cred.cr_group_info = gi;
- } else
- get_group_info(cred.cr_group_info);
-
- if (cred.cr_uid != (uid_t) -1)
- current->fsuid = cred.cr_uid;
- else
- current->fsuid = exp->ex_anon_uid;
- if (cred.cr_gid != (gid_t) -1)
- current->fsgid = cred.cr_gid;
- else
- current->fsgid = exp->ex_anon_gid;
+ if (!new->fsuid)
+ new->fsuid = exp->ex_anon_uid;
+ if (!new->fsgid)
+ new->fsgid = exp->ex_anon_gid;
- if (!cred.cr_group_info)
- return -ENOMEM;
- ret = set_current_groups(cred.cr_group_info);
- put_group_info(cred.cr_group_info);
- if ((cred.cr_uid)) {
- current->cap_effective =
- cap_drop_nfsd_set(current->cap_effective);
+ gi = groups_alloc(rqgi->ngroups);
+ if (!gi)
+ goto oom;
+
+ for (i = 0; i < rqgi->ngroups; i++) {
+ if (!GROUP_AT(rqgi, i))
+ GROUP_AT(gi, i) = exp->ex_anon_gid;
+ else
+ GROUP_AT(gi, i) = GROUP_AT(rqgi, i);
+ }
} else {
- current->cap_effective =
- cap_raise_nfsd_set(current->cap_effective,
- current->cap_permitted);
+ gi = get_group_info(rqgi);
}
+
+ if (new->fsuid == (uid_t) -1)
+ new->fsuid = exp->ex_anon_uid;
+ if (new->fsgid == (gid_t) -1)
+ new->fsgid = exp->ex_anon_gid;
+
+ ret = set_groups(new, gi);
+ put_group_info(gi);
+ if (!ret)
+ goto error;
+
+ if (new->uid)
+ new->cap_effective = cap_drop_nfsd_set(new->cap_effective);
+ else
+ new->cap_effective = cap_raise_nfsd_set(new->cap_effective,
+ new->cap_permitted);
+ put_cred(override_creds(new));
+ return 0;
+
+oom:
+ ret = -ENOMEM;
+error:
+ abort_creds(new);
return ret;
}
+
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 094747a1227..6d7d8c02c19 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -358,6 +358,7 @@ static struct rpc_program cb_program = {
.nrvers = ARRAY_SIZE(nfs_cb_version),
.version = nfs_cb_version,
.stats = &cb_stats,
+ .pipe_dir_name = "/nfsd4_cb",
};
/* Reference counting, callback cleanup, etc., all look racy as heck.
@@ -382,8 +383,9 @@ static int do_probe_callback(void *data)
.program = &cb_program,
.prognumber = cb->cb_prog,
.version = nfs_cb_version[1]->number,
- .authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */
+ .authflavor = clp->cl_flavor,
.flags = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET),
+ .client_name = clp->cl_principal,
};
struct rpc_message msg = {
.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
@@ -392,6 +394,11 @@ static int do_probe_callback(void *data)
struct rpc_clnt *client;
int status;
+ if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5)) {
+ status = nfserr_cb_path_down;
+ goto out_err;
+ }
+
/* Initialize address */
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index bb93946ace2..0f9d6efaa62 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -54,20 +54,26 @@
static struct path rec_dir;
static int rec_dir_init = 0;
-static void
-nfs4_save_user(uid_t *saveuid, gid_t *savegid)
+static int
+nfs4_save_creds(const struct cred **original_creds)
{
- *saveuid = current->fsuid;
- *savegid = current->fsgid;
- current->fsuid = 0;
- current->fsgid = 0;
+ struct cred *new;
+
+ new = prepare_creds();
+ if (!new)
+ return -ENOMEM;
+
+ new->fsuid = 0;
+ new->fsgid = 0;
+ *original_creds = override_creds(new);
+ put_cred(new);
+ return 0;
}
static void
-nfs4_reset_user(uid_t saveuid, gid_t savegid)
+nfs4_reset_creds(const struct cred *original)
{
- current->fsuid = saveuid;
- current->fsgid = savegid;
+ revert_creds(original);
}
static void
@@ -129,10 +135,9 @@ nfsd4_sync_rec_dir(void)
int
nfsd4_create_clid_dir(struct nfs4_client *clp)
{
+ const struct cred *original_cred;
char *dname = clp->cl_recdir;
struct dentry *dentry;
- uid_t uid;
- gid_t gid;
int status;
dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname);
@@ -140,7 +145,9 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
if (!rec_dir_init || clp->cl_firststate)
return 0;
- nfs4_save_user(&uid, &gid);
+ status = nfs4_save_creds(&original_cred);
+ if (status < 0)
+ return status;
/* lock the parent */
mutex_lock(&rec_dir.dentry->d_inode->i_mutex);
@@ -168,7 +175,7 @@ out_unlock:
clp->cl_firststate = 1;
nfsd4_sync_rec_dir();
}
- nfs4_reset_user(uid, gid);
+ nfs4_reset_creds(original_cred);
dprintk("NFSD: nfsd4_create_clid_dir returns %d\n", status);
return status;
}
@@ -211,22 +218,25 @@ nfsd4_build_dentrylist(void *arg, const char *name, int namlen,
static int
nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f)
{
+ const struct cred *original_cred;
struct file *filp;
struct dentry_list_arg dla = {
.parent = dir,
};
struct list_head *dentries = &dla.dentries;
struct dentry_list *child;
- uid_t uid;
- gid_t gid;
int status;
if (!rec_dir_init)
return 0;
- nfs4_save_user(&uid, &gid);
+ status = nfs4_save_creds(&original_cred);
+ if (status < 0)
+ return status;
+ INIT_LIST_HEAD(dentries);
- filp = dentry_open(dget(dir), mntget(rec_dir.mnt), O_RDONLY);
+ filp = dentry_open(dget(dir), mntget(rec_dir.mnt), O_RDONLY,
+ current_cred());
status = PTR_ERR(filp);
if (IS_ERR(filp))
goto out;
@@ -249,7 +259,7 @@ out:
dput(child->dentry);
kfree(child);
}
- nfs4_reset_user(uid, gid);
+ nfs4_reset_creds(original_cred);
return status;
}
@@ -311,8 +321,7 @@ out:
void
nfsd4_remove_clid_dir(struct nfs4_client *clp)
{
- uid_t uid;
- gid_t gid;
+ const struct cred *original_cred;
int status;
if (!rec_dir_init || !clp->cl_firststate)
@@ -322,9 +331,13 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
if (status)
goto out;
clp->cl_firststate = 0;
- nfs4_save_user(&uid, &gid);
+
+ status = nfs4_save_creds(&original_cred);
+ if (status < 0)
+ goto out;
+
status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1);
- nfs4_reset_user(uid, gid);
+ nfs4_reset_creds(original_cred);
if (status == 0)
nfsd4_sync_rec_dir();
mnt_drop_write(rec_dir.mnt);
@@ -401,16 +414,21 @@ nfsd4_recdir_load(void) {
void
nfsd4_init_recdir(char *rec_dirname)
{
- uid_t uid = 0;
- gid_t gid = 0;
- int status;
+ const struct cred *original_cred;
+ int status;
printk("NFSD: Using %s as the NFSv4 state recovery directory\n",
rec_dirname);
BUG_ON(rec_dir_init);
- nfs4_save_user(&uid, &gid);
+ status = nfs4_save_creds(&original_cred);
+ if (status < 0) {
+ printk("NFSD: Unable to change credentials to find recovery"
+ " directory: error %d\n",
+ status);
+ return;
+ }
status = kern_path(rec_dirname, LOOKUP_FOLLOW | LOOKUP_DIRECTORY,
&rec_dir);
@@ -420,7 +438,7 @@ nfsd4_init_recdir(char *rec_dirname)
if (!status)
rec_dir_init = 1;
- nfs4_reset_user(uid, gid);
+ nfs4_reset_creds(original_cred);
}
void
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index b0bebc552a1..13e0e074dbb 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -54,6 +54,7 @@
#include <linux/mutex.h>
#include <linux/lockd/bind.h>
#include <linux/module.h>
+#include <linux/sunrpc/svcauth_gss.h>
#define NFSDDBG_FACILITY NFSDDBG_PROC
@@ -377,6 +378,7 @@ free_client(struct nfs4_client *clp)
shutdown_callback_client(clp);
if (clp->cl_cred.cr_group_info)
put_group_info(clp->cl_cred.cr_group_info);
+ kfree(clp->cl_principal);
kfree(clp->cl_name.data);
kfree(clp);
}
@@ -696,6 +698,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
unsigned int strhashval;
struct nfs4_client *conf, *unconf, *new;
__be32 status;
+ char *princ;
char dname[HEXDIR_LEN];
if (!check_name(clname))
@@ -719,8 +722,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
status = nfserr_clid_inuse;
if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)
|| conf->cl_addr != sin->sin_addr.s_addr) {
- dprintk("NFSD: setclientid: string in use by client"
- "at %u.%u.%u.%u\n", NIPQUAD(conf->cl_addr));
+ dprintk("NFSD: setclientid: string in use by clientat %pI4\n",
+ &conf->cl_addr);
goto out;
}
}
@@ -783,6 +786,15 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
}
copy_verf(new, &clverifier);
new->cl_addr = sin->sin_addr.s_addr;
+ new->cl_flavor = rqstp->rq_flavor;
+ princ = svc_gss_principal(rqstp);
+ if (princ) {
+ new->cl_principal = kstrdup(princ, GFP_KERNEL);
+ if (new->cl_principal == NULL) {
+ free_client(new);
+ goto out;
+ }
+ }
copy_cred(&new->cl_cred, &rqstp->rq_cred);
gen_confirm(new);
gen_callback(new, setclid);
@@ -3261,6 +3273,7 @@ nfs4_state_shutdown(void)
{
cancel_rearming_delayed_workqueue(laundry_wq, &laundromat_work);
destroy_workqueue(laundry_wq);
+ locks_end_grace(&nfsd4_manager);
nfs4_lock_state();
nfs4_release_reclaim();
__nfs4_state_shutdown();
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index e3f9783fdcf..77d7b8c531a 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -330,7 +330,7 @@ static ssize_t failover_unlock_ip(struct file *file, char *buf, size_t size)
return -EINVAL;
/* get ipv4 address */
- if (sscanf(fo_path, NIPQUAD_FMT "%c", &b1, &b2, &b3, &b4, &c) != 4)
+ if (sscanf(fo_path, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4)
return -EINVAL;
if (b1 > 255 || b2 > 255 || b3 > 255 || b4 > 255)
return -EINVAL;
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index cd25d91895a..f0da7d9c3a9 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -186,9 +186,14 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
* access control settings being in effect, we cannot
* fix that case easily.
*/
- current->cap_effective =
- cap_raise_nfsd_set(current->cap_effective,
- current->cap_permitted);
+ struct cred *new = prepare_creds();
+ if (!new)
+ return nfserrno(-ENOMEM);
+ new->cap_effective =
+ cap_raise_nfsd_set(new->cap_effective,
+ new->cap_permitted);
+ put_cred(override_creds(new));
+ put_cred(new);
} else {
error = nfsd_setuser_and_check_port(rqstp, exp);
if (error)
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 4433c8f0016..d1c5f787b36 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -671,6 +671,7 @@ __be32
nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
int access, struct file **filp)
{
+ const struct cred *cred = current_cred();
struct dentry *dentry;
struct inode *inode;
int flags = O_RDONLY|O_LARGEFILE;
@@ -725,7 +726,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
DQUOT_INIT(inode);
}
*filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_path.mnt),
- flags);
+ flags, cred);
if (IS_ERR(*filp))
host_err = PTR_ERR(*filp);
out_nfserr:
@@ -1169,7 +1170,7 @@ nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp,
* send along the gid on create when it tries to implement
* setgid directories via NFS:
*/
- if (current->fsuid != 0)
+ if (current_fsuid() != 0)
iap->ia_valid &= ~(ATTR_UID|ATTR_GID);
if (iap->ia_valid)
return nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
@@ -2001,7 +2002,7 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
IS_APPEND(inode)? " append" : "",
__mnt_is_readonly(exp->ex_path.mnt)? " ro" : "");
dprintk(" owner %d/%d user %d/%d\n",
- inode->i_uid, inode->i_gid, current->fsuid, current->fsgid);
+ inode->i_uid, inode->i_gid, current_fsuid(), current_fsgid());
#endif
/* Normally we reject any write/sattr etc access on a read-only file
@@ -2044,7 +2045,7 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
* with NFSv3.
*/
if ((acc & NFSD_MAY_OWNER_OVERRIDE) &&
- inode->i_uid == current->fsuid)
+ inode->i_uid == current_fsuid())
return 0;
/* This assumes NFSD_MAY_{READ,WRITE,EXEC} == MAY_{READ,WRITE,EXEC} */
diff --git a/fs/notify/Kconfig b/fs/notify/Kconfig
new file mode 100644
index 00000000000..50914d7303c
--- /dev/null
+++ b/fs/notify/Kconfig
@@ -0,0 +1,2 @@
+source "fs/notify/dnotify/Kconfig"
+source "fs/notify/inotify/Kconfig"
diff --git a/fs/notify/Makefile b/fs/notify/Makefile
new file mode 100644
index 00000000000..5a95b6010ce
--- /dev/null
+++ b/fs/notify/Makefile
@@ -0,0 +1,2 @@
+obj-y += dnotify/
+obj-y += inotify/
diff --git a/fs/notify/dnotify/Kconfig b/fs/notify/dnotify/Kconfig
new file mode 100644
index 00000000000..26adf5dfa64
--- /dev/null
+++ b/fs/notify/dnotify/Kconfig
@@ -0,0 +1,10 @@
+config DNOTIFY
+ bool "Dnotify support"
+ default y
+ help
+ Dnotify is a directory-based per-fd file change notification system
+ that uses signals to communicate events to user-space. There exist
+ superior alternatives, but some applications may still rely on
+ dnotify.
+
+ If unsure, say Y.
diff --git a/fs/notify/dnotify/Makefile b/fs/notify/dnotify/Makefile
new file mode 100644
index 00000000000..f145251dcad
--- /dev/null
+++ b/fs/notify/dnotify/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_DNOTIFY) += dnotify.o
diff --git a/fs/dnotify.c b/fs/notify/dnotify/dnotify.c
index 676073b8dda..b0aa2cde80b 100644
--- a/fs/dnotify.c
+++ b/fs/notify/dnotify/dnotify.c
@@ -115,9 +115,6 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
dn->dn_next = inode->i_dnotify;
inode->i_dnotify = dn;
spin_unlock(&inode->i_lock);
-
- if (filp->f_op && filp->f_op->dir_notify)
- return filp->f_op->dir_notify(filp, arg);
return 0;
out_free:
diff --git a/fs/notify/inotify/Kconfig b/fs/notify/inotify/Kconfig
new file mode 100644
index 00000000000..44679284102
--- /dev/null
+++ b/fs/notify/inotify/Kconfig
@@ -0,0 +1,27 @@
+config INOTIFY
+ bool "Inotify file change notification support"
+ default y
+ ---help---
+ Say Y here to enable inotify support. Inotify is a file change
+ notification system and a replacement for dnotify. Inotify fixes
+ numerous shortcomings in dnotify and introduces several new features
+ including multiple file events, one-shot support, and unmount
+ notification.
+
+ For more information, see <file:Documentation/filesystems/inotify.txt>
+
+ If unsure, say Y.
+
+config INOTIFY_USER
+ bool "Inotify support for userspace"
+ depends on INOTIFY
+ default y
+ ---help---
+ Say Y here to enable inotify support for userspace, including the
+ associated system calls. Inotify allows monitoring of both files and
+ directories via a single open fd. Events are read from the file
+ descriptor, which is also select()- and poll()-able.
+
+ For more information, see <file:Documentation/filesystems/inotify.txt>
+
+ If unsure, say Y.
diff --git a/fs/notify/inotify/Makefile b/fs/notify/inotify/Makefile
new file mode 100644
index 00000000000..e290f3bb9d8
--- /dev/null
+++ b/fs/notify/inotify/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_INOTIFY) += inotify.o
+obj-$(CONFIG_INOTIFY_USER) += inotify_user.o
diff --git a/fs/inotify.c b/fs/notify/inotify/inotify.c
index 7bbed1b8982..dae3f28f30d 100644
--- a/fs/inotify.c
+++ b/fs/notify/inotify/inotify.c
@@ -428,11 +428,13 @@ void inotify_unmount_inodes(struct list_head *list)
watches = &inode->inotify_watches;
list_for_each_entry_safe(watch, next_w, watches, i_list) {
struct inotify_handle *ih= watch->ih;
+ get_inotify_watch(watch);
mutex_lock(&ih->mutex);
ih->in_ops->handle_event(watch, watch->wd, IN_UNMOUNT, 0,
NULL, NULL);
inotify_remove_watch_locked(ih, watch);
mutex_unlock(&ih->mutex);
+ put_inotify_watch(watch);
}
mutex_unlock(&inode->inotify_mutex);
iput(inode);
diff --git a/fs/inotify_user.c b/fs/notify/inotify/inotify_user.c
index d367e9b9286..400f8064a54 100644
--- a/fs/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -76,10 +76,10 @@ struct inotify_device {
struct mutex ev_mutex; /* protects event queue */
struct mutex up_mutex; /* synchronizes watch updates */
struct list_head events; /* list of queued events */
- atomic_t count; /* reference count */
struct user_struct *user; /* user who opened this dev */
struct inotify_handle *ih; /* inotify handle */
struct fasync_struct *fa; /* async notification */
+ atomic_t count; /* reference count */
unsigned int queue_size; /* size of the queue (bytes) */
unsigned int event_count; /* number of pending events */
unsigned int max_events; /* maximum number of events */
@@ -601,7 +601,7 @@ asmlinkage long sys_inotify_init1(int flags)
goto out_put_fd;
}
- user = get_uid(current->user);
+ user = get_current_user();
if (unlikely(atomic_read(&user->inotify_devs) >=
inotify_max_user_instances)) {
ret = -EMFILE;
diff --git a/fs/ocfs2/cluster/netdebug.c b/fs/ocfs2/cluster/netdebug.c
index 52276c02f71..f8424874fa0 100644
--- a/fs/ocfs2/cluster/netdebug.c
+++ b/fs/ocfs2/cluster/netdebug.c
@@ -304,8 +304,8 @@ static int sc_seq_show(struct seq_file *seq, void *v)
* use of it here generates a warning with -Wbitwise */
seq_printf(seq, "%p:\n"
" krefs: %d\n"
- " sock: %u.%u.%u.%u:%u -> "
- "%u.%u.%u.%u:%u\n"
+ " sock: %pI4:%u -> "
+ "%pI4:%u\n"
" remote node: %s\n"
" page off: %zu\n"
" handshake ok: %u\n"
@@ -319,8 +319,8 @@ static int sc_seq_show(struct seq_file *seq, void *v)
" func type: %u\n",
sc,
atomic_read(&sc->sc_kref.refcount),
- NIPQUAD(saddr), inet ? ntohs(sport) : 0,
- NIPQUAD(daddr), inet ? ntohs(dport) : 0,
+ &saddr, inet ? ntohs(sport) : 0,
+ &daddr, inet ? ntohs(dport) : 0,
sc->sc_node->nd_name,
sc->sc_page_off,
sc->sc_handshake_ok,
diff --git a/fs/ocfs2/cluster/nodemanager.c b/fs/ocfs2/cluster/nodemanager.c
index 816a3f61330..70e8fa9e253 100644
--- a/fs/ocfs2/cluster/nodemanager.c
+++ b/fs/ocfs2/cluster/nodemanager.c
@@ -250,7 +250,7 @@ static ssize_t o2nm_node_ipv4_port_write(struct o2nm_node *node,
static ssize_t o2nm_node_ipv4_address_read(struct o2nm_node *node, char *page)
{
- return sprintf(page, "%u.%u.%u.%u\n", NIPQUAD(node->nd_ipv4_address));
+ return sprintf(page, "%pI4\n", &node->nd_ipv4_address);
}
static ssize_t o2nm_node_ipv4_address_write(struct o2nm_node *node,
diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c
index 2bcf706d9dd..9fbe849f634 100644
--- a/fs/ocfs2/cluster/tcp.c
+++ b/fs/ocfs2/cluster/tcp.c
@@ -1597,8 +1597,8 @@ static void o2net_start_connect(struct work_struct *work)
ret = sock->ops->bind(sock, (struct sockaddr *)&myaddr,
sizeof(myaddr));
if (ret) {
- mlog(ML_ERROR, "bind failed with %d at address %u.%u.%u.%u\n",
- ret, NIPQUAD(mynode->nd_ipv4_address));
+ mlog(ML_ERROR, "bind failed with %d at address %pI4\n",
+ ret, &mynode->nd_ipv4_address);
goto out;
}
@@ -1790,17 +1790,16 @@ static int o2net_accept_one(struct socket *sock)
node = o2nm_get_node_by_ip(sin.sin_addr.s_addr);
if (node == NULL) {
- mlog(ML_NOTICE, "attempt to connect from unknown node at "
- "%u.%u.%u.%u:%d\n", NIPQUAD(sin.sin_addr.s_addr),
- ntohs(sin.sin_port));
+ mlog(ML_NOTICE, "attempt to connect from unknown node at %pI4:%d\n",
+ &sin.sin_addr.s_addr, ntohs(sin.sin_port));
ret = -EINVAL;
goto out;
}
if (o2nm_this_node() > node->nd_num) {
mlog(ML_NOTICE, "unexpected connect attempted from a lower "
- "numbered node '%s' at " "%u.%u.%u.%u:%d with num %u\n",
- node->nd_name, NIPQUAD(sin.sin_addr.s_addr),
+ "numbered node '%s' at " "%pI4:%d with num %u\n",
+ node->nd_name, &sin.sin_addr.s_addr,
ntohs(sin.sin_port), node->nd_num);
ret = -EINVAL;
goto out;
@@ -1810,8 +1809,8 @@ static int o2net_accept_one(struct socket *sock)
* and tries to connect before we see their heartbeat */
if (!o2hb_check_node_heartbeating_from_callback(node->nd_num)) {
mlog(ML_CONN, "attempt to connect from node '%s' at "
- "%u.%u.%u.%u:%d but it isn't heartbeating\n",
- node->nd_name, NIPQUAD(sin.sin_addr.s_addr),
+ "%pI4:%d but it isn't heartbeating\n",
+ node->nd_name, &sin.sin_addr.s_addr,
ntohs(sin.sin_port));
ret = -EINVAL;
goto out;
@@ -1827,8 +1826,8 @@ static int o2net_accept_one(struct socket *sock)
spin_unlock(&nn->nn_lock);
if (ret) {
mlog(ML_NOTICE, "attempt to connect from node '%s' at "
- "%u.%u.%u.%u:%d but it already has an open connection\n",
- node->nd_name, NIPQUAD(sin.sin_addr.s_addr),
+ "%pI4:%d but it already has an open connection\n",
+ node->nd_name, &sin.sin_addr.s_addr,
ntohs(sin.sin_port));
goto out;
}
@@ -1924,15 +1923,15 @@ static int o2net_open_listening_sock(__be32 addr, __be16 port)
sock->sk->sk_reuse = 1;
ret = sock->ops->bind(sock, (struct sockaddr *)&sin, sizeof(sin));
if (ret < 0) {
- mlog(ML_ERROR, "unable to bind socket at %u.%u.%u.%u:%u, "
- "ret=%d\n", NIPQUAD(addr), ntohs(port), ret);
+ mlog(ML_ERROR, "unable to bind socket at %pI4:%u, "
+ "ret=%d\n", &addr, ntohs(port), ret);
goto out;
}
ret = sock->ops->listen(sock, 64);
if (ret < 0) {
- mlog(ML_ERROR, "unable to listen on %u.%u.%u.%u:%u, ret=%d\n",
- NIPQUAD(addr), ntohs(port), ret);
+ mlog(ML_ERROR, "unable to listen on %pI4:%u, ret=%d\n",
+ &addr, ntohs(port), ret);
}
out:
diff --git a/fs/ocfs2/dlm/dlmfs.c b/fs/ocfs2/dlm/dlmfs.c
index ba962d71b34..6f7a77d5402 100644
--- a/fs/ocfs2/dlm/dlmfs.c
+++ b/fs/ocfs2/dlm/dlmfs.c
@@ -339,8 +339,8 @@ static struct inode *dlmfs_get_root_inode(struct super_block *sb)
ip = DLMFS_I(inode);
inode->i_mode = mode;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
inode->i_blocks = 0;
inode->i_mapping->backing_dev_info = &dlmfs_backing_dev_info;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
@@ -365,8 +365,8 @@ static struct inode *dlmfs_get_inode(struct inode *parent,
return NULL;
inode->i_mode = mode;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
inode->i_blocks = 0;
inode->i_mapping->backing_dev_info = &dlmfs_backing_dev_info;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index f4967e634ff..2545e7402ef 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -421,13 +421,13 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb,
fe->i_blkno = cpu_to_le64(fe_blkno);
fe->i_suballoc_bit = cpu_to_le16(suballoc_bit);
fe->i_suballoc_slot = cpu_to_le16(inode_ac->ac_alloc_slot);
- fe->i_uid = cpu_to_le32(current->fsuid);
+ fe->i_uid = cpu_to_le32(current_fsuid());
if (dir->i_mode & S_ISGID) {
fe->i_gid = cpu_to_le32(dir->i_gid);
if (S_ISDIR(mode))
mode |= S_ISGID;
} else
- fe->i_gid = cpu_to_le32(current->fsgid);
+ fe->i_gid = cpu_to_le32(current_fsgid());
fe->i_mode = cpu_to_le16(mode);
if (S_ISCHR(mode) || S_ISBLK(mode))
fe->id1.dev1.i_rdev = cpu_to_le64(huge_encode_dev(dev));
diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h
index 5f180cf7abb..5e0c0d0aef7 100644
--- a/fs/ocfs2/ocfs2_fs.h
+++ b/fs/ocfs2/ocfs2_fs.h
@@ -86,7 +86,8 @@
#define OCFS2_CLEAR_INCOMPAT_FEATURE(sb,mask) \
OCFS2_SB(sb)->s_feature_incompat &= ~(mask)
-#define OCFS2_FEATURE_COMPAT_SUPP OCFS2_FEATURE_COMPAT_BACKUP_SB
+#define OCFS2_FEATURE_COMPAT_SUPP (OCFS2_FEATURE_COMPAT_BACKUP_SB \
+ | OCFS2_FEATURE_COMPAT_JBD2_SB)
#define OCFS2_FEATURE_INCOMPAT_SUPP (OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT \
| OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC \
| OCFS2_FEATURE_INCOMPAT_INLINE_DATA \
@@ -153,6 +154,11 @@
#define OCFS2_FEATURE_COMPAT_BACKUP_SB 0x0001
/*
+ * The filesystem will correctly handle journal feature bits.
+ */
+#define OCFS2_FEATURE_COMPAT_JBD2_SB 0x0002
+
+/*
* Unwritten extents support.
*/
#define OCFS2_FEATURE_RO_COMPAT_UNWRITTEN 0x0001
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c
index 054e2efb0b7..74d7367ade1 100644
--- a/fs/ocfs2/xattr.c
+++ b/fs/ocfs2/xattr.c
@@ -2645,9 +2645,9 @@ static int ocfs2_xattr_update_xattr_search(struct inode *inode,
return ret;
}
- i = xs->here - old_xh->xh_entries;
- xs->here = &xs->header->xh_entries[i];
}
+ i = xs->here - old_xh->xh_entries;
+ xs->here = &xs->header->xh_entries[i];
}
return ret;
diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c
index cbf047a847c..6afe57c84f8 100644
--- a/fs/omfs/inode.c
+++ b/fs/omfs/inode.c
@@ -37,8 +37,8 @@ struct inode *omfs_new_inode(struct inode *dir, int mode)
inode->i_ino = new_block;
inode->i_mode = mode;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
inode->i_blocks = 0;
inode->i_mapping->a_ops = &omfs_aops;
@@ -420,8 +420,8 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent)
sb->s_fs_info = sbi;
- sbi->s_uid = current->uid;
- sbi->s_gid = current->gid;
+ sbi->s_uid = current_uid();
+ sbi->s_gid = current_gid();
sbi->s_dmask = sbi->s_fmask = current->fs->umask;
if (!parse_options((char *) data, sbi))
diff --git a/fs/open.c b/fs/open.c
index 83cdb9dee0c..1cd7d40e999 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -272,6 +272,8 @@ static long do_sys_truncate(const char __user *pathname, loff_t length)
goto put_write_and_out;
error = locks_verify_truncate(inode, NULL, length);
+ if (!error)
+ error = security_path_truncate(&path, length, 0);
if (!error) {
DQUOT_INIT(inode);
error = do_truncate(path.dentry, length, 0, NULL);
@@ -329,6 +331,9 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
error = locks_verify_truncate(inode, file, length);
if (!error)
+ error = security_path_truncate(&file->f_path, length,
+ ATTR_MTIME|ATTR_CTIME);
+ if (!error)
error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file);
out_putf:
fput(file);
@@ -425,39 +430,33 @@ out:
*/
asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
{
+ const struct cred *old_cred;
+ struct cred *override_cred;
struct path path;
struct inode *inode;
- int old_fsuid, old_fsgid;
- kernel_cap_t uninitialized_var(old_cap); /* !SECURE_NO_SETUID_FIXUP */
int res;
if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
return -EINVAL;
- old_fsuid = current->fsuid;
- old_fsgid = current->fsgid;
+ override_cred = prepare_creds();
+ if (!override_cred)
+ return -ENOMEM;
- current->fsuid = current->uid;
- current->fsgid = current->gid;
+ override_cred->fsuid = override_cred->uid;
+ override_cred->fsgid = override_cred->gid;
if (!issecure(SECURE_NO_SETUID_FIXUP)) {
- /*
- * Clear the capabilities if we switch to a non-root user
- */
-#ifndef CONFIG_SECURITY_FILE_CAPABILITIES
- /*
- * FIXME: There is a race here against sys_capset. The
- * capabilities can change yet we will restore the old
- * value below. We should hold task_capabilities_lock,
- * but we cannot because user_path_at can sleep.
- */
-#endif /* ndef CONFIG_SECURITY_FILE_CAPABILITIES */
- if (current->uid)
- old_cap = cap_set_effective(__cap_empty_set);
+ /* Clear the capabilities if we switch to a non-root user */
+ if (override_cred->uid)
+ cap_clear(override_cred->cap_effective);
else
- old_cap = cap_set_effective(current->cap_permitted);
+ override_cred->cap_effective =
+ override_cred->cap_permitted;
}
+ old_cred = override_creds(override_cred);
+
res = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path);
if (res)
goto out;
@@ -494,12 +493,8 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
out_path_release:
path_put(&path);
out:
- current->fsuid = old_fsuid;
- current->fsgid = old_fsgid;
-
- if (!issecure(SECURE_NO_SETUID_FIXUP))
- cap_set_effective(old_cap);
-
+ revert_creds(old_cred);
+ put_cred(override_cred);
return res;
}
@@ -792,7 +787,8 @@ static inline int __get_file_write_access(struct inode *inode,
static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
int flags, struct file *f,
- int (*open)(struct inode *, struct file *))
+ int (*open)(struct inode *, struct file *),
+ const struct cred *cred)
{
struct inode *inode;
int error;
@@ -816,7 +812,7 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
f->f_op = fops_get(inode->i_fop);
file_move(f, &inode->i_sb->s_files);
- error = security_dentry_open(f);
+ error = security_dentry_open(f, cred);
if (error)
goto cleanup_all;
@@ -891,6 +887,8 @@ cleanup_file:
struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry,
int (*open)(struct inode *, struct file *))
{
+ const struct cred *cred = current_cred();
+
if (IS_ERR(nd->intent.open.file))
goto out;
if (IS_ERR(dentry))
@@ -898,7 +896,7 @@ struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry
nd->intent.open.file = __dentry_open(dget(dentry), mntget(nd->path.mnt),
nd->intent.open.flags - 1,
nd->intent.open.file,
- open);
+ open, cred);
out:
return nd->intent.open.file;
out_err:
@@ -917,6 +915,7 @@ EXPORT_SYMBOL_GPL(lookup_instantiate_filp);
*/
struct file *nameidata_to_filp(struct nameidata *nd, int flags)
{
+ const struct cred *cred = current_cred();
struct file *filp;
/* Pick up the filp from the open intent */
@@ -924,7 +923,7 @@ struct file *nameidata_to_filp(struct nameidata *nd, int flags)
/* Has the filesystem initialised the file for us? */
if (filp->f_path.dentry == NULL)
filp = __dentry_open(nd->path.dentry, nd->path.mnt, flags, filp,
- NULL);
+ NULL, cred);
else
path_put(&nd->path);
return filp;
@@ -934,7 +933,8 @@ struct file *nameidata_to_filp(struct nameidata *nd, int flags)
* dentry_open() will have done dput(dentry) and mntput(mnt) if it returns an
* error.
*/
-struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
+struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags,
+ const struct cred *cred)
{
int error;
struct file *f;
@@ -959,7 +959,7 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
return ERR_PTR(error);
}
- return __dentry_open(dentry, mnt, flags, f, NULL);
+ return __dentry_open(dentry, mnt, flags, f, NULL, cred);
}
EXPORT_SYMBOL(dentry_open);
diff --git a/fs/pipe.c b/fs/pipe.c
index 7aea8b89baa..aaf797bd57b 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -899,8 +899,8 @@ static struct inode * get_pipe_inode(void)
*/
inode->i_state = I_DIRTY;
inode->i_mode = S_IFIFO | S_IRUSR | S_IWUSR;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
return inode;
diff --git a/fs/posix_acl.c b/fs/posix_acl.c
index aec931e0997..39df95a0ec2 100644
--- a/fs/posix_acl.c
+++ b/fs/posix_acl.c
@@ -217,11 +217,11 @@ posix_acl_permission(struct inode *inode, const struct posix_acl *acl, int want)
switch(pa->e_tag) {
case ACL_USER_OBJ:
/* (May have been checked already) */
- if (inode->i_uid == current->fsuid)
+ if (inode->i_uid == current_fsuid())
goto check_perm;
break;
case ACL_USER:
- if (pa->e_id == current->fsuid)
+ if (pa->e_id == current_fsuid())
goto mask;
break;
case ACL_GROUP_OBJ:
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 6af7fba7abb..7e4877d9dcb 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -159,6 +159,7 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
struct group_info *group_info;
int g;
struct fdtable *fdt = NULL;
+ const struct cred *cred;
pid_t ppid, tpid;
rcu_read_lock();
@@ -170,6 +171,7 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
if (tracer)
tpid = task_pid_nr_ns(tracer, ns);
}
+ cred = get_cred((struct cred *) __task_cred(p));
seq_printf(m,
"State:\t%s\n"
"Tgid:\t%d\n"
@@ -182,8 +184,8 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
task_tgid_nr_ns(p, ns),
pid_nr_ns(pid, ns),
ppid, tpid,
- p->uid, p->euid, p->suid, p->fsuid,
- p->gid, p->egid, p->sgid, p->fsgid);
+ cred->uid, cred->euid, cred->suid, cred->fsuid,
+ cred->gid, cred->egid, cred->sgid, cred->fsgid);
task_lock(p);
if (p->files)
@@ -194,13 +196,12 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
fdt ? fdt->max_fds : 0);
rcu_read_unlock();
- group_info = p->group_info;
- get_group_info(group_info);
+ group_info = cred->group_info;
task_unlock(p);
for (g = 0; g < min(group_info->ngroups, NGROUPS_SMALL); g++)
seq_printf(m, "%d ", GROUP_AT(group_info, g));
- put_group_info(group_info);
+ put_cred(cred);
seq_printf(m, "\n");
}
@@ -262,7 +263,7 @@ static inline void task_sig(struct seq_file *m, struct task_struct *p)
blocked = p->blocked;
collect_sigign_sigcatch(p, &ignored, &caught);
num_threads = atomic_read(&p->signal->count);
- qsize = atomic_read(&p->user->sigpending);
+ qsize = atomic_read(&__task_cred(p)->user->sigpending);
qlim = p->signal->rlim[RLIMIT_SIGPENDING].rlim_cur;
unlock_task_sighand(p, &flags);
}
@@ -293,10 +294,21 @@ static void render_cap_t(struct seq_file *m, const char *header,
static inline void task_cap(struct seq_file *m, struct task_struct *p)
{
- render_cap_t(m, "CapInh:\t", &p->cap_inheritable);
- render_cap_t(m, "CapPrm:\t", &p->cap_permitted);
- render_cap_t(m, "CapEff:\t", &p->cap_effective);
- render_cap_t(m, "CapBnd:\t", &p->cap_bset);
+ const struct cred *cred;
+ kernel_cap_t cap_inheritable, cap_permitted, cap_effective, cap_bset;
+
+ rcu_read_lock();
+ cred = __task_cred(p);
+ cap_inheritable = cred->cap_inheritable;
+ cap_permitted = cred->cap_permitted;
+ cap_effective = cred->cap_effective;
+ cap_bset = cred->cap_bset;
+ rcu_read_unlock();
+
+ render_cap_t(m, "CapInh:\t", &cap_inheritable);
+ render_cap_t(m, "CapPrm:\t", &cap_permitted);
+ render_cap_t(m, "CapEff:\t", &cap_effective);
+ render_cap_t(m, "CapBnd:\t", &cap_bset);
}
static inline void task_context_switch_counts(struct seq_file *m,
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 486cf3fe713..cad92c1ac2b 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -347,8 +347,8 @@ static int proc_pid_wchan(struct task_struct *task, char *buffer)
static int proc_pid_schedstat(struct task_struct *task, char *buffer)
{
return sprintf(buffer, "%llu %llu %lu\n",
- task->sched_info.cpu_time,
- task->sched_info.run_delay,
+ (unsigned long long)task->se.sum_exec_runtime,
+ (unsigned long long)task->sched_info.run_delay,
task->sched_info.pcount);
}
#endif
@@ -371,7 +371,7 @@ static int lstats_show_proc(struct seq_file *m, void *v)
task->latency_record[i].time,
task->latency_record[i].max);
for (q = 0; q < LT_BACKTRACEDEPTH; q++) {
- char sym[KSYM_NAME_LEN];
+ char sym[KSYM_SYMBOL_LEN];
char *c;
if (!task->latency_record[i].backtrace[q])
break;
@@ -1406,6 +1406,7 @@ static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_st
{
struct inode * inode;
struct proc_inode *ei;
+ const struct cred *cred;
/* We need a new inode */
@@ -1428,8 +1429,11 @@ static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_st
inode->i_uid = 0;
inode->i_gid = 0;
if (task_dumpable(task)) {
- inode->i_uid = task->euid;
- inode->i_gid = task->egid;
+ rcu_read_lock();
+ cred = __task_cred(task);
+ inode->i_uid = cred->euid;
+ inode->i_gid = cred->egid;
+ rcu_read_unlock();
}
security_task_to_inode(task, inode);
@@ -1445,6 +1449,8 @@ static int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat
{
struct inode *inode = dentry->d_inode;
struct task_struct *task;
+ const struct cred *cred;
+
generic_fillattr(inode, stat);
rcu_read_lock();
@@ -1454,8 +1460,9 @@ static int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat
if (task) {
if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) ||
task_dumpable(task)) {
- stat->uid = task->euid;
- stat->gid = task->egid;
+ cred = __task_cred(task);
+ stat->uid = cred->euid;
+ stat->gid = cred->egid;
}
}
rcu_read_unlock();
@@ -1483,11 +1490,16 @@ static int pid_revalidate(struct dentry *dentry, struct nameidata *nd)
{
struct inode *inode = dentry->d_inode;
struct task_struct *task = get_proc_task(inode);
+ const struct cred *cred;
+
if (task) {
if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) ||
task_dumpable(task)) {
- inode->i_uid = task->euid;
- inode->i_gid = task->egid;
+ rcu_read_lock();
+ cred = __task_cred(task);
+ inode->i_uid = cred->euid;
+ inode->i_gid = cred->egid;
+ rcu_read_unlock();
} else {
inode->i_uid = 0;
inode->i_gid = 0;
@@ -1649,6 +1661,7 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
struct task_struct *task = get_proc_task(inode);
int fd = proc_fd(inode);
struct files_struct *files;
+ const struct cred *cred;
if (task) {
files = get_files_struct(task);
@@ -1658,8 +1671,11 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
rcu_read_unlock();
put_files_struct(files);
if (task_dumpable(task)) {
- inode->i_uid = task->euid;
- inode->i_gid = task->egid;
+ rcu_read_lock();
+ cred = __task_cred(task);
+ inode->i_uid = cred->euid;
+ inode->i_gid = cred->egid;
+ rcu_read_unlock();
} else {
inode->i_uid = 0;
inode->i_gid = 0;
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c
index d777789b7a8..de2bba5a344 100644
--- a/fs/proc/proc_devtree.c
+++ b/fs/proc/proc_devtree.c
@@ -218,8 +218,7 @@ void proc_device_tree_add_node(struct device_node *np,
void __init proc_device_tree_init(void)
{
struct device_node *root;
- if ( !have_of )
- return;
+
proc_device_tree = proc_mkdir("device-tree", NULL);
if (proc_device_tree == 0)
return;
diff --git a/fs/proc/stat.c b/fs/proc/stat.c
index 81904f07679..f75efa22df5 100644
--- a/fs/proc/stat.c
+++ b/fs/proc/stat.c
@@ -9,6 +9,7 @@
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/time.h>
+#include <linux/irqnr.h>
#include <asm/cputime.h>
#ifndef arch_irq_stat_cpu
@@ -44,10 +45,9 @@ static int show_stat(struct seq_file *p, void *v)
softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq);
steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal);
guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest);
-
- for_each_irq_nr(j)
+ for_each_irq_nr(j) {
sum += kstat_irqs_cpu(j, i);
-
+ }
sum += arch_irq_stat_cpu(i);
}
sum += arch_irq_stat();
@@ -92,7 +92,6 @@ static int show_stat(struct seq_file *p, void *v)
/* sum again ? it could be updated? */
for_each_irq_nr(j) {
per_irq_sum = 0;
-
for_each_possible_cpu(i)
per_irq_sum += kstat_irqs_cpu(j, i);
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index b770c095e45..3a8bdd7f575 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -557,9 +557,9 @@ static u64 swap_pte_to_pagemap_entry(pte_t pte)
return swp_type(e) | (swp_offset(e) << MAX_SWAPFILES_SHIFT);
}
-static unsigned long pte_to_pagemap_entry(pte_t pte)
+static u64 pte_to_pagemap_entry(pte_t pte)
{
- unsigned long pme = 0;
+ u64 pme = 0;
if (is_swap_pte(pte))
pme = PM_PFRAME(swap_pte_to_pagemap_entry(pte))
| PM_PSHIFT(PAGE_SHIFT) | PM_SWAP;
diff --git a/fs/quota.c b/fs/quota.c
index 7f4386ebc23..b7fe44e0161 100644
--- a/fs/quota.c
+++ b/fs/quota.c
@@ -79,7 +79,7 @@ static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, qid
/* Check privileges */
if (cmd == Q_GETQUOTA) {
- if (((type == USRQUOTA && current->euid != id) ||
+ if (((type == USRQUOTA && current_euid() != id) ||
(type == GRPQUOTA && !in_egroup_p(id))) &&
!capable(CAP_SYS_ADMIN))
return -EPERM;
@@ -130,7 +130,7 @@ static int xqm_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t i
/* Check privileges */
if (cmd == Q_XGETQUOTA) {
- if (((type == XQM_USRQUOTA && current->euid != id) ||
+ if (((type == XQM_USRQUOTA && current_euid() != id) ||
(type == XQM_GRPQUOTA && !in_egroup_p(id))) &&
!capable(CAP_SYS_ADMIN))
return -EPERM;
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
index f031d1c925f..a83a3518ae3 100644
--- a/fs/ramfs/inode.c
+++ b/fs/ramfs/inode.c
@@ -55,8 +55,8 @@ struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev)
if (inode) {
inode->i_mode = mode;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
inode->i_blocks = 0;
inode->i_mapping->a_ops = &ramfs_aops;
inode->i_mapping->backing_dev_info = &ramfs_backing_dev_info;
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index 6c4c2c69449..145c2d3e5e0 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -1753,6 +1753,7 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
struct inode *inode)
{
struct super_block *sb;
+ struct reiserfs_iget_args args;
INITIALIZE_PATH(path_to_key);
struct cpu_key key;
struct item_head ih;
@@ -1780,6 +1781,14 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
err = -ENOMEM;
goto out_bad_inode;
}
+ args.objectid = inode->i_ino = le32_to_cpu(ih.ih_key.k_objectid);
+ memcpy(INODE_PKEY(inode), &(ih.ih_key), KEY_SIZE);
+ args.dirid = le32_to_cpu(ih.ih_key.k_dir_id);
+ if (insert_inode_locked4(inode, args.objectid,
+ reiserfs_find_actor, &args) < 0) {
+ err = -EINVAL;
+ goto out_bad_inode;
+ }
if (old_format_only(sb))
/* not a perfect generation count, as object ids can be reused, but
** this is as good as reiserfs can do right now.
@@ -1859,13 +1868,9 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
} else {
inode2sd(&sd, inode, inode->i_size);
}
- // these do not go to on-disk stat data
- inode->i_ino = le32_to_cpu(ih.ih_key.k_objectid);
-
// store in in-core inode the key of stat data and version all
// object items will have (directory items will have old offset
// format, other new objects will consist of new items)
- memcpy(INODE_PKEY(inode), &(ih.ih_key), KEY_SIZE);
if (old_format_only(sb) || S_ISDIR(mode) || S_ISLNK(mode))
set_inode_item_key_version(inode, KEY_FORMAT_3_5);
else
@@ -1929,7 +1934,6 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
reiserfs_mark_inode_private(inode);
}
- insert_inode_hash(inode);
reiserfs_update_sd(th, inode);
reiserfs_check_path(&path_to_key);
@@ -1956,6 +1960,7 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
out_inserted_sd:
inode->i_nlink = 0;
th->t_trans_id = 0; /* so the caller can't use this handle later */
+ unlock_new_inode(inode); /* OK to do even if we hadn't locked it */
/* If we were inheriting an ACL, we need to release the lock so that
* iput doesn't deadlock in reiserfs_delete_xattrs. The locking
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
index f89ebb943f3..738967f6c8e 100644
--- a/fs/reiserfs/namei.c
+++ b/fs/reiserfs/namei.c
@@ -573,7 +573,7 @@ static int new_inode_init(struct inode *inode, struct inode *dir, int mode)
/* the quota init calls have to know who to charge the quota to, so
** we have to set uid and gid here
*/
- inode->i_uid = current->fsuid;
+ inode->i_uid = current_fsuid();
inode->i_mode = mode;
/* Make inode invalid - just in case we are going to drop it before
* the initialization happens */
@@ -584,7 +584,7 @@ static int new_inode_init(struct inode *inode, struct inode *dir, int mode)
if (S_ISDIR(mode))
inode->i_mode |= S_ISGID;
} else {
- inode->i_gid = current->fsgid;
+ inode->i_gid = current_fsgid();
}
DQUOT_INIT(inode);
return 0;
@@ -646,6 +646,7 @@ static int reiserfs_create(struct inode *dir, struct dentry *dentry, int mode,
err = journal_end(&th, dir->i_sb, jbegin_count);
if (err)
retval = err;
+ unlock_new_inode(inode);
iput(inode);
goto out_failed;
}
@@ -653,6 +654,7 @@ static int reiserfs_create(struct inode *dir, struct dentry *dentry, int mode,
reiserfs_update_inode_transaction(dir);
d_instantiate(dentry, inode);
+ unlock_new_inode(inode);
retval = journal_end(&th, dir->i_sb, jbegin_count);
out_failed:
@@ -727,11 +729,13 @@ static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, int mode,
err = journal_end(&th, dir->i_sb, jbegin_count);
if (err)
retval = err;
+ unlock_new_inode(inode);
iput(inode);
goto out_failed;
}
d_instantiate(dentry, inode);
+ unlock_new_inode(inode);
retval = journal_end(&th, dir->i_sb, jbegin_count);
out_failed:
@@ -812,6 +816,7 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
err = journal_end(&th, dir->i_sb, jbegin_count);
if (err)
retval = err;
+ unlock_new_inode(inode);
iput(inode);
goto out_failed;
}
@@ -819,6 +824,7 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
reiserfs_update_sd(&th, dir);
d_instantiate(dentry, inode);
+ unlock_new_inode(inode);
retval = journal_end(&th, dir->i_sb, jbegin_count);
out_failed:
if (locked)
@@ -1096,11 +1102,13 @@ static int reiserfs_symlink(struct inode *parent_dir,
err = journal_end(&th, parent_dir->i_sb, jbegin_count);
if (err)
retval = err;
+ unlock_new_inode(inode);
iput(inode);
goto out_failed;
}
d_instantiate(dentry, inode);
+ unlock_new_inode(inode);
retval = journal_end(&th, parent_dir->i_sb, jbegin_count);
out_failed:
reiserfs_write_unlock(parent_dir->i_sb);
diff --git a/fs/seq_file.c b/fs/seq_file.c
index eba2eabcd2b..99d8b8cfc9b 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -357,7 +357,18 @@ int seq_printf(struct seq_file *m, const char *f, ...)
}
EXPORT_SYMBOL(seq_printf);
-static char *mangle_path(char *s, char *p, char *esc)
+/**
+ * mangle_path - mangle and copy path to buffer beginning
+ * @s: buffer start
+ * @p: beginning of path in above buffer
+ * @esc: set of characters that need escaping
+ *
+ * Copy the path from @p to @s, replacing each occurrence of character from
+ * @esc with usual octal escape.
+ * Returns pointer past last written character in @s, or NULL in case of
+ * failure.
+ */
+char *mangle_path(char *s, char *p, char *esc)
{
while (s <= p) {
char c = *p++;
@@ -376,9 +387,16 @@ static char *mangle_path(char *s, char *p, char *esc)
}
return NULL;
}
+EXPORT_SYMBOL(mangle_path);
-/*
- * return the absolute path of 'dentry' residing in mount 'mnt'.
+/**
+ * seq_path - seq_file interface to print a pathname
+ * @m: the seq_file handle
+ * @path: the struct path to print
+ * @esc: set of characters to escape in the output
+ *
+ * return the absolute path of 'path', as represented by the
+ * dentry / mnt pair in the path parameter.
*/
int seq_path(struct seq_file *m, struct path *path, char *esc)
{
diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c
index 48da4fa6b7d..e7ddd0328dd 100644
--- a/fs/smbfs/dir.c
+++ b/fs/smbfs/dir.c
@@ -667,8 +667,7 @@ smb_make_node(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
attr.ia_valid = ATTR_MODE | ATTR_UID | ATTR_GID;
attr.ia_mode = mode;
- attr.ia_uid = current->euid;
- attr.ia_gid = current->egid;
+ current_euid_egid(&attr.ia_uid, &attr.ia_gid);
if (!new_valid_dev(dev))
return -EINVAL;
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index 3528f40ffb0..fc27fbfc539 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -586,7 +586,7 @@ static int smb_fill_super(struct super_block *sb, void *raw_data, int silent)
if (parse_options(mnt, raw_data))
goto out_bad_option;
}
- mnt->mounted_uid = current->uid;
+ mnt->mounted_uid = current_uid();
smb_setcodepage(server, &mnt->codepage);
/*
diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c
index ee536e8a649..9468168b9af 100644
--- a/fs/smbfs/proc.c
+++ b/fs/smbfs/proc.c
@@ -864,7 +864,7 @@ smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt)
goto out;
error = -EACCES;
- if (current->uid != server->mnt->mounted_uid &&
+ if (current_uid() != server->mnt->mounted_uid &&
!capable(CAP_SYS_ADMIN))
goto out;
diff --git a/fs/super.c b/fs/super.c
index 400a7608f15..ddba069d7a9 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -914,7 +914,7 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void
goto out_free_secdata;
BUG_ON(!mnt->mnt_sb);
- error = security_sb_kern_mount(mnt->mnt_sb, secdata);
+ error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata);
if (error)
goto out_sb;
diff --git a/fs/sysv/ialloc.c b/fs/sysv/ialloc.c
index 115ab0d6f4b..241e9765cfa 100644
--- a/fs/sysv/ialloc.c
+++ b/fs/sysv/ialloc.c
@@ -165,9 +165,9 @@ struct inode * sysv_new_inode(const struct inode * dir, mode_t mode)
if (S_ISDIR(mode))
mode |= S_ISGID;
} else
- inode->i_gid = current->fsgid;
+ inode->i_gid = current_fsgid();
- inode->i_uid = current->fsuid;
+ inode->i_uid = current_fsuid();
inode->i_ino = fs16_to_cpu(sbi, ino);
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
inode->i_blocks = 0;
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index df0d435baa4..3d81bf58dae 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -27,6 +27,7 @@
#include <linux/init.h>
#include <linux/buffer_head.h>
#include <linux/vfs.h>
+#include <linux/namei.h>
#include <asm/byteorder.h>
#include "sysv.h"
@@ -163,8 +164,11 @@ void sysv_set_inode(struct inode *inode, dev_t rdev)
if (inode->i_blocks) {
inode->i_op = &sysv_symlink_inode_operations;
inode->i_mapping->a_ops = &sysv_aops;
- } else
+ } else {
inode->i_op = &sysv_fast_symlink_inode_operations;
+ nd_terminate_link(SYSV_I(inode)->i_data, inode->i_size,
+ sizeof(SYSV_I(inode)->i_data) - 1);
+ }
} else
init_special_inode(inode, inode->i_mode, rdev);
}
diff --git a/fs/ubifs/budget.c b/fs/ubifs/budget.c
index 31870d8dab8..0e5e54d8292 100644
--- a/fs/ubifs/budget.c
+++ b/fs/ubifs/budget.c
@@ -300,7 +300,7 @@ long long ubifs_calc_available(const struct ubifs_info *c, int min_idx_lebs)
*/
static int can_use_rp(struct ubifs_info *c)
{
- if (current->fsuid == c->rp_uid || capable(CAP_SYS_RESOURCE) ||
+ if (current_fsuid() == c->rp_uid || capable(CAP_SYS_RESOURCE) ||
(c->rp_gid != 0 && in_group_p(c->rp_gid)))
return 1;
return 0;
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index 0422c98e179..f448ab1f9c3 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -104,13 +104,13 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
*/
inode->i_flags |= (S_NOCMTIME);
- inode->i_uid = current->fsuid;
+ inode->i_uid = current_fsuid();
if (dir->i_mode & S_ISGID) {
inode->i_gid = dir->i_gid;
if (S_ISDIR(mode))
mode |= S_ISGID;
} else
- inode->i_gid = current->fsgid;
+ inode->i_gid = current_fsgid();
inode->i_mode = mode;
inode->i_mtime = inode->i_atime = inode->i_ctime =
ubifs_current_time(inode);
diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c
index a4f2b3ce45b..31fc84297dd 100644
--- a/fs/udf/ialloc.c
+++ b/fs/udf/ialloc.c
@@ -126,13 +126,13 @@ struct inode *udf_new_inode(struct inode *dir, int mode, int *err)
}
mutex_unlock(&sbi->s_alloc_mutex);
inode->i_mode = mode;
- inode->i_uid = current->fsuid;
+ inode->i_uid = current_fsuid();
if (dir->i_mode & S_ISGID) {
inode->i_gid = dir->i_gid;
if (S_ISDIR(mode))
mode |= S_ISGID;
} else {
- inode->i_gid = current->fsgid;
+ inode->i_gid = current_fsgid();
}
iinfo->i_location.logicalBlockNum = block;
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index 082409cd4b8..f84bfaa8d94 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -604,7 +604,7 @@ static int udf_mknod(struct inode *dir, struct dentry *dentry, int mode,
goto out;
iinfo = UDF_I(inode);
- inode->i_uid = current->fsuid;
+ inode->i_uid = current_fsuid();
init_special_inode(inode, mode, rdev);
fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
if (!fi) {
diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c
index ac181f6806a..6f5dcf00609 100644
--- a/fs/ufs/ialloc.c
+++ b/fs/ufs/ialloc.c
@@ -304,13 +304,13 @@ cg_found:
inode->i_ino = cg * uspi->s_ipg + bit;
inode->i_mode = mode;
- inode->i_uid = current->fsuid;
+ inode->i_uid = current_fsuid();
if (dir->i_mode & S_ISGID) {
inode->i_gid = dir->i_gid;
if (S_ISDIR(mode))
inode->i_mode |= S_ISGID;
} else
- inode->i_gid = current->fsgid;
+ inode->i_gid = current_fsgid();
inode->i_blocks = 0;
inode->i_generation = 0;
diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
index 737c9a42536..c3dc491fff8 100644
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -85,13 +85,13 @@ xfs-y += xfs_alloc.o \
xfs_trans_inode.o \
xfs_trans_item.o \
xfs_utils.o \
- xfs_vfsops.o \
xfs_vnodeops.o \
xfs_rw.o \
xfs_dmops.o \
xfs_qmops.o
-xfs-$(CONFIG_XFS_TRACE) += xfs_dir2_trace.o
+xfs-$(CONFIG_XFS_TRACE) += xfs_btree_trace.o \
+ xfs_dir2_trace.o
# Objects in linux/
xfs-y += $(addprefix $(XFS_LINUX)/, \
@@ -106,7 +106,7 @@ xfs-y += $(addprefix $(XFS_LINUX)/, \
xfs_iops.o \
xfs_lrw.o \
xfs_super.o \
- xfs_vnode.o \
+ xfs_sync.o \
xfs_xattr.o)
# Objects in support/
diff --git a/fs/xfs/linux-2.6/sv.h b/fs/xfs/linux-2.6/sv.h
index 351a8f454bd..4dfc7c37081 100644
--- a/fs/xfs/linux-2.6/sv.h
+++ b/fs/xfs/linux-2.6/sv.h
@@ -32,23 +32,15 @@ typedef struct sv_s {
wait_queue_head_t waiters;
} sv_t;
-#define SV_FIFO 0x0 /* sv_t is FIFO type */
-#define SV_LIFO 0x2 /* sv_t is LIFO type */
-#define SV_PRIO 0x4 /* sv_t is PRIO type */
-#define SV_KEYED 0x6 /* sv_t is KEYED type */
-#define SV_DEFAULT SV_FIFO
-
-
-static inline void _sv_wait(sv_t *sv, spinlock_t *lock, int state,
- unsigned long timeout)
+static inline void _sv_wait(sv_t *sv, spinlock_t *lock)
{
DECLARE_WAITQUEUE(wait, current);
add_wait_queue_exclusive(&sv->waiters, &wait);
- __set_current_state(state);
+ __set_current_state(TASK_UNINTERRUPTIBLE);
spin_unlock(lock);
- schedule_timeout(timeout);
+ schedule();
remove_wait_queue(&sv->waiters, &wait);
}
@@ -58,13 +50,7 @@ static inline void _sv_wait(sv_t *sv, spinlock_t *lock, int state,
#define sv_destroy(sv) \
/*NOTHING*/
#define sv_wait(sv, pri, lock, s) \
- _sv_wait(sv, lock, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT)
-#define sv_wait_sig(sv, pri, lock, s) \
- _sv_wait(sv, lock, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT)
-#define sv_timedwait(sv, pri, lock, s, svf, ts, rts) \
- _sv_wait(sv, lock, TASK_UNINTERRUPTIBLE, timespec_to_jiffies(ts))
-#define sv_timedwait_sig(sv, pri, lock, s, svf, ts, rts) \
- _sv_wait(sv, lock, TASK_INTERRUPTIBLE, timespec_to_jiffies(ts))
+ _sv_wait(sv, lock)
#define sv_signal(sv) \
wake_up(&(sv)->waiters)
#define sv_broadcast(sv) \
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
index a44d68eb50b..de3a198f771 100644
--- a/fs/xfs/linux-2.6/xfs_aops.c
+++ b/fs/xfs/linux-2.6/xfs_aops.c
@@ -42,6 +42,40 @@
#include <linux/pagevec.h>
#include <linux/writeback.h>
+
+/*
+ * Prime number of hash buckets since address is used as the key.
+ */
+#define NVSYNC 37
+#define to_ioend_wq(v) (&xfs_ioend_wq[((unsigned long)v) % NVSYNC])
+static wait_queue_head_t xfs_ioend_wq[NVSYNC];
+
+void __init
+xfs_ioend_init(void)
+{
+ int i;
+
+ for (i = 0; i < NVSYNC; i++)
+ init_waitqueue_head(&xfs_ioend_wq[i]);
+}
+
+void
+xfs_ioend_wait(
+ xfs_inode_t *ip)
+{
+ wait_queue_head_t *wq = to_ioend_wq(ip);
+
+ wait_event(*wq, (atomic_read(&ip->i_iocount) == 0));
+}
+
+STATIC void
+xfs_ioend_wake(
+ xfs_inode_t *ip)
+{
+ if (atomic_dec_and_test(&ip->i_iocount))
+ wake_up(to_ioend_wq(ip));
+}
+
STATIC void
xfs_count_page_state(
struct page *page,
@@ -146,16 +180,25 @@ xfs_destroy_ioend(
xfs_ioend_t *ioend)
{
struct buffer_head *bh, *next;
+ struct xfs_inode *ip = XFS_I(ioend->io_inode);
for (bh = ioend->io_buffer_head; bh; bh = next) {
next = bh->b_private;
bh->b_end_io(bh, !ioend->io_error);
}
- if (unlikely(ioend->io_error)) {
- vn_ioerror(XFS_I(ioend->io_inode), ioend->io_error,
- __FILE__,__LINE__);
+
+ /*
+ * Volume managers supporting multiple paths can send back ENODEV
+ * when the final path disappears. In this case continuing to fill
+ * the page cache with dirty data which cannot be written out is
+ * evil, so prevent that.
+ */
+ if (unlikely(ioend->io_error == -ENODEV)) {
+ xfs_do_force_shutdown(ip->i_mount, SHUTDOWN_DEVICE_REQ,
+ __FILE__, __LINE__);
}
- vn_iowake(XFS_I(ioend->io_inode));
+
+ xfs_ioend_wake(ip);
mempool_free(ioend, xfs_ioend_pool);
}
@@ -191,7 +234,7 @@ xfs_setfilesize(
ip->i_d.di_size = isize;
ip->i_update_core = 1;
ip->i_update_size = 1;
- mark_inode_dirty_sync(ioend->io_inode);
+ xfs_mark_inode_dirty_sync(ip);
}
xfs_iunlock(ip, XFS_ILOCK_EXCL);
@@ -317,14 +360,9 @@ xfs_map_blocks(
xfs_iomap_t *mapp,
int flags)
{
- xfs_inode_t *ip = XFS_I(inode);
- int error, nmaps = 1;
-
- error = xfs_iomap(ip, offset, count,
- flags, mapp, &nmaps);
- if (!error && (flags & (BMAPI_WRITE|BMAPI_ALLOCATE)))
- xfs_iflags_set(ip, XFS_IMODIFIED);
- return -error;
+ int nmaps = 1;
+
+ return -xfs_iomap(XFS_I(inode), offset, count, flags, mapp, &nmaps);
}
STATIC_INLINE int
@@ -512,7 +550,7 @@ xfs_cancel_ioend(
unlock_buffer(bh);
} while ((bh = next_bh) != NULL);
- vn_iowake(XFS_I(ioend->io_inode));
+ xfs_ioend_wake(XFS_I(ioend->io_inode));
mempool_free(ioend, xfs_ioend_pool);
} while ((ioend = next) != NULL);
}
diff --git a/fs/xfs/linux-2.6/xfs_aops.h b/fs/xfs/linux-2.6/xfs_aops.h
index 3ba0631a381..7b26f5ff969 100644
--- a/fs/xfs/linux-2.6/xfs_aops.h
+++ b/fs/xfs/linux-2.6/xfs_aops.h
@@ -43,4 +43,7 @@ typedef struct xfs_ioend {
extern const struct address_space_operations xfs_address_space_operations;
extern int xfs_get_blocks(struct inode *, sector_t, struct buffer_head *, int);
+extern void xfs_ioend_init(void);
+extern void xfs_ioend_wait(struct xfs_inode *);
+
#endif /* __XFS_AOPS_H__ */
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c
index 36d5fcd3f59..cb329edc925 100644
--- a/fs/xfs/linux-2.6/xfs_buf.c
+++ b/fs/xfs/linux-2.6/xfs_buf.c
@@ -630,6 +630,29 @@ xfs_buf_get_flags(
return NULL;
}
+STATIC int
+_xfs_buf_read(
+ xfs_buf_t *bp,
+ xfs_buf_flags_t flags)
+{
+ int status;
+
+ XB_TRACE(bp, "_xfs_buf_read", (unsigned long)flags);
+
+ ASSERT(!(flags & (XBF_DELWRI|XBF_WRITE)));
+ ASSERT(bp->b_bn != XFS_BUF_DADDR_NULL);
+
+ bp->b_flags &= ~(XBF_WRITE | XBF_ASYNC | XBF_DELWRI | \
+ XBF_READ_AHEAD | _XBF_RUN_QUEUES);
+ bp->b_flags |= flags & (XBF_READ | XBF_ASYNC | \
+ XBF_READ_AHEAD | _XBF_RUN_QUEUES);
+
+ status = xfs_buf_iorequest(bp);
+ if (!status && !(flags & XBF_ASYNC))
+ status = xfs_buf_iowait(bp);
+ return status;
+}
+
xfs_buf_t *
xfs_buf_read_flags(
xfs_buftarg_t *target,
@@ -646,7 +669,7 @@ xfs_buf_read_flags(
if (!XFS_BUF_ISDONE(bp)) {
XB_TRACE(bp, "read", (unsigned long)flags);
XFS_STATS_INC(xb_get_read);
- xfs_buf_iostart(bp, flags);
+ _xfs_buf_read(bp, flags);
} else if (flags & XBF_ASYNC) {
XB_TRACE(bp, "read_async", (unsigned long)flags);
/*
@@ -1048,50 +1071,39 @@ xfs_buf_ioerror(
XB_TRACE(bp, "ioerror", (unsigned long)error);
}
-/*
- * Initiate I/O on a buffer, based on the flags supplied.
- * The b_iodone routine in the buffer supplied will only be called
- * when all of the subsidiary I/O requests, if any, have been completed.
- */
int
-xfs_buf_iostart(
- xfs_buf_t *bp,
- xfs_buf_flags_t flags)
+xfs_bawrite(
+ void *mp,
+ struct xfs_buf *bp)
{
- int status = 0;
+ XB_TRACE(bp, "bawrite", 0);
- XB_TRACE(bp, "iostart", (unsigned long)flags);
+ ASSERT(bp->b_bn != XFS_BUF_DADDR_NULL);
- if (flags & XBF_DELWRI) {
- bp->b_flags &= ~(XBF_READ | XBF_WRITE | XBF_ASYNC);
- bp->b_flags |= flags & (XBF_DELWRI | XBF_ASYNC);
- xfs_buf_delwri_queue(bp, 1);
- return 0;
- }
+ xfs_buf_delwri_dequeue(bp);
- bp->b_flags &= ~(XBF_READ | XBF_WRITE | XBF_ASYNC | XBF_DELWRI | \
- XBF_READ_AHEAD | _XBF_RUN_QUEUES);
- bp->b_flags |= flags & (XBF_READ | XBF_WRITE | XBF_ASYNC | \
- XBF_READ_AHEAD | _XBF_RUN_QUEUES);
+ bp->b_flags &= ~(XBF_READ | XBF_DELWRI | XBF_READ_AHEAD);
+ bp->b_flags |= (XBF_WRITE | XBF_ASYNC | _XBF_RUN_QUEUES);
+
+ bp->b_mount = mp;
+ bp->b_strat = xfs_bdstrat_cb;
+ return xfs_bdstrat_cb(bp);
+}
- BUG_ON(bp->b_bn == XFS_BUF_DADDR_NULL);
+void
+xfs_bdwrite(
+ void *mp,
+ struct xfs_buf *bp)
+{
+ XB_TRACE(bp, "bdwrite", 0);
- /* For writes allow an alternate strategy routine to precede
- * the actual I/O request (which may not be issued at all in
- * a shutdown situation, for example).
- */
- status = (flags & XBF_WRITE) ?
- xfs_buf_iostrategy(bp) : xfs_buf_iorequest(bp);
+ bp->b_strat = xfs_bdstrat_cb;
+ bp->b_mount = mp;
- /* Wait for I/O if we are not an async request.
- * Note: async I/O request completion will release the buffer,
- * and that can already be done by this point. So using the
- * buffer pointer from here on, after async I/O, is invalid.
- */
- if (!status && !(flags & XBF_ASYNC))
- status = xfs_buf_iowait(bp);
+ bp->b_flags &= ~XBF_READ;
+ bp->b_flags |= (XBF_DELWRI | XBF_ASYNC);
- return status;
+ xfs_buf_delwri_queue(bp, 1);
}
STATIC_INLINE void
@@ -1114,8 +1126,7 @@ xfs_buf_bio_end_io(
unsigned int blocksize = bp->b_target->bt_bsize;
struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
- if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
- bp->b_error = EIO;
+ xfs_buf_ioerror(bp, -error);
do {
struct page *page = bvec->bv_page;
diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h
index 456519a088c..288ae7c4c80 100644
--- a/fs/xfs/linux-2.6/xfs_buf.h
+++ b/fs/xfs/linux-2.6/xfs_buf.h
@@ -168,7 +168,7 @@ typedef struct xfs_buf {
struct completion b_iowait; /* queue for I/O waiters */
void *b_fspriv;
void *b_fspriv2;
- void *b_fspriv3;
+ struct xfs_mount *b_mount;
unsigned short b_error; /* error code on I/O */
unsigned int b_page_count; /* size of page array */
unsigned int b_offset; /* page offset in first page */
@@ -214,9 +214,10 @@ extern void xfs_buf_lock(xfs_buf_t *);
extern void xfs_buf_unlock(xfs_buf_t *);
/* Buffer Read and Write Routines */
+extern int xfs_bawrite(void *mp, xfs_buf_t *bp);
+extern void xfs_bdwrite(void *mp, xfs_buf_t *bp);
extern void xfs_buf_ioend(xfs_buf_t *, int);
extern void xfs_buf_ioerror(xfs_buf_t *, int);
-extern int xfs_buf_iostart(xfs_buf_t *, xfs_buf_flags_t);
extern int xfs_buf_iorequest(xfs_buf_t *);
extern int xfs_buf_iowait(xfs_buf_t *);
extern void xfs_buf_iomove(xfs_buf_t *, size_t, size_t, xfs_caddr_t,
@@ -311,10 +312,6 @@ extern void xfs_buf_trace(xfs_buf_t *, char *, void *, void *);
#define XFS_BUF_UNORDERED(bp) ((bp)->b_flags &= ~XBF_ORDERED)
#define XFS_BUF_ISORDERED(bp) ((bp)->b_flags & XBF_ORDERED)
-#define XFS_BUF_SHUT(bp) do { } while (0)
-#define XFS_BUF_UNSHUT(bp) do { } while (0)
-#define XFS_BUF_ISSHUT(bp) (0)
-
#define XFS_BUF_HOLD(bp) xfs_buf_hold(bp)
#define XFS_BUF_READ(bp) ((bp)->b_flags |= XBF_READ)
#define XFS_BUF_UNREAD(bp) ((bp)->b_flags &= ~XBF_READ)
@@ -334,8 +331,6 @@ extern void xfs_buf_trace(xfs_buf_t *, char *, void *, void *);
#define XFS_BUF_SET_FSPRIVATE(bp, val) ((bp)->b_fspriv = (void*)(val))
#define XFS_BUF_FSPRIVATE2(bp, type) ((type)(bp)->b_fspriv2)
#define XFS_BUF_SET_FSPRIVATE2(bp, val) ((bp)->b_fspriv2 = (void*)(val))
-#define XFS_BUF_FSPRIVATE3(bp, type) ((type)(bp)->b_fspriv3)
-#define XFS_BUF_SET_FSPRIVATE3(bp, val) ((bp)->b_fspriv3 = (void*)(val))
#define XFS_BUF_SET_START(bp) do { } while (0)
#define XFS_BUF_SET_BRELSE_FUNC(bp, func) ((bp)->b_relse = (func))
@@ -366,14 +361,6 @@ extern void xfs_buf_trace(xfs_buf_t *, char *, void *, void *);
#define XFS_BUF_TARGET(bp) ((bp)->b_target)
#define XFS_BUFTARG_NAME(target) xfs_buf_target_name(target)
-static inline int xfs_bawrite(void *mp, xfs_buf_t *bp)
-{
- bp->b_fspriv3 = mp;
- bp->b_strat = xfs_bdstrat_cb;
- xfs_buf_delwri_dequeue(bp);
- return xfs_buf_iostart(bp, XBF_WRITE | XBF_ASYNC | _XBF_RUN_QUEUES);
-}
-
static inline void xfs_buf_relse(xfs_buf_t *bp)
{
if (!bp->b_relse)
@@ -414,17 +401,6 @@ static inline int XFS_bwrite(xfs_buf_t *bp)
return error;
}
-/*
- * No error can be returned from xfs_buf_iostart for delwri
- * buffers as they are queued and no I/O is issued.
- */
-static inline void xfs_bdwrite(void *mp, xfs_buf_t *bp)
-{
- bp->b_strat = xfs_bdstrat_cb;
- bp->b_fspriv3 = mp;
- (void)xfs_buf_iostart(bp, XBF_DELWRI | XBF_ASYNC);
-}
-
#define XFS_bdstrat(bp) xfs_buf_iorequest(bp)
#define xfs_iowait(bp) xfs_buf_iowait(bp)
diff --git a/fs/xfs/linux-2.6/xfs_cred.h b/fs/xfs/linux-2.6/xfs_cred.h
index 652721ce0ea..55bddf3b609 100644
--- a/fs/xfs/linux-2.6/xfs_cred.h
+++ b/fs/xfs/linux-2.6/xfs_cred.h
@@ -23,16 +23,6 @@
/*
* Credentials
*/
-typedef struct cred {
- /* EMPTY */
-} cred_t;
-
-extern struct cred *sys_cred;
-
-/* this is a hack.. (assumes sys_cred is the only cred_t in the system) */
-static inline int capable_cred(cred_t *cr, int cid)
-{
- return (cr == sys_cred) ? 1 : capable(cid);
-}
+typedef const struct cred cred_t;
#endif /* __XFS_CRED_H__ */
diff --git a/fs/xfs/linux-2.6/xfs_export.