Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
matisse
android_kernel_samsung_matisse
Commits
9092131f
Commit
9092131f
authored
19 years ago
by
Linus Torvalds
Browse files
Options
Download
Plain Diff
Merge
rsync://client.linux-nfs.org/pub/linux/nfs-2.6
parents
f1b04770
eadf4598
Changes
68
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
1014 additions
and
290 deletions
+1014
-290
fs/Kconfig
fs/Kconfig
+35
-0
fs/Makefile
fs/Makefile
+1
-0
fs/lockd/clntlock.c
fs/lockd/clntlock.c
+62
-51
fs/lockd/clntproc.c
fs/lockd/clntproc.c
+32
-8
fs/lockd/host.c
fs/lockd/host.c
+3
-5
fs/lockd/mon.c
fs/lockd/mon.c
+3
-4
fs/locks.c
fs/locks.c
+6
-0
fs/nfs/Makefile
fs/nfs/Makefile
+1
-0
fs/nfs/callback.c
fs/nfs/callback.c
+1
-0
fs/nfs/callback_proc.c
fs/nfs/callback_proc.c
+1
-0
fs/nfs/callback_xdr.c
fs/nfs/callback_xdr.c
+1
-1
fs/nfs/delegation.c
fs/nfs/delegation.c
+1
-0
fs/nfs/dir.c
fs/nfs/dir.c
+130
-30
fs/nfs/direct.c
fs/nfs/direct.c
+1
-1
fs/nfs/file.c
fs/nfs/file.c
+41
-7
fs/nfs/idmap.c
fs/nfs/idmap.c
+1
-0
fs/nfs/inode.c
fs/nfs/inode.c
+255
-172
fs/nfs/mount_clnt.c
fs/nfs/mount_clnt.c
+1
-3
fs/nfs/nfs3acl.c
fs/nfs/nfs3acl.c
+403
-0
fs/nfs/nfs3proc.c
fs/nfs/nfs3proc.c
+35
-8
No files found.
fs/Kconfig
View file @
9092131f
...
...
@@ -1268,6 +1268,7 @@ config NFS_FS
depends on INET
select LOCKD
select SUNRPC
select NFS_ACL_SUPPORT if NFS_V3_ACL
help
If you are connected to some other (usually local) Unix computer
(using SLIP, PLIP, PPP or Ethernet) and want to mount files residing
...
...
@@ -1310,6 +1311,16 @@ config NFS_V3
If unsure, say Y.
config NFS_V3_ACL
bool "Provide client support for the NFSv3 ACL protocol extension"
depends on NFS_V3
help
Implement the NFSv3 ACL protocol extension for manipulating POSIX
Access Control Lists. The server should also be compiled with
the NFSv3 ACL protocol extension; see the CONFIG_NFSD_V3_ACL option.
If unsure, say N.
config NFS_V4
bool "Provide NFSv4 client support (EXPERIMENTAL)"
depends on NFS_FS && EXPERIMENTAL
...
...
@@ -1353,6 +1364,7 @@ config NFSD
select LOCKD
select SUNRPC
select EXPORTFS
select NFS_ACL_SUPPORT if NFSD_V3_ACL || NFSD_V2_ACL
help
If you want your Linux box to act as an NFS *server*, so that other
computers on your local network which support NFS can access certain
...
...
@@ -1376,6 +1388,10 @@ config NFSD
To compile the NFS server support as a module, choose M here: the
module will be called nfsd. If unsure, say N.
config NFSD_V2_ACL
bool
depends on NFSD
config NFSD_V3
bool "Provide NFSv3 server support"
depends on NFSD
...
...
@@ -1383,6 +1399,16 @@ config NFSD_V3
If you would like to include the NFSv3 server as well as the NFSv2
server, say Y here. If unsure, say Y.
config NFSD_V3_ACL
bool "Provide server support for the NFSv3 ACL protocol extension"
depends on NFSD_V3
select NFSD_V2_ACL
help
Implement the NFSv3 ACL protocol extension for manipulating POSIX
Access Control Lists on exported file systems. NFS clients should
be compiled with the NFSv3 ACL protocol extension; see the
CONFIG_NFS_V3_ACL option. If unsure, say N.
config NFSD_V4
bool "Provide NFSv4 server support (EXPERIMENTAL)"
depends on NFSD_V3 && EXPERIMENTAL
...
...
@@ -1427,6 +1453,15 @@ config LOCKD_V4
config EXPORTFS
tristate
config NFS_ACL_SUPPORT
tristate
select FS_POSIX_ACL
config NFS_COMMON
bool
depends on NFSD || NFS_FS
default y
config SUNRPC
tristate
...
...
This diff is collapsed.
Click to expand it.
fs/Makefile
View file @
9092131f
...
...
@@ -31,6 +31,7 @@ obj-$(CONFIG_BINFMT_FLAT) += binfmt_flat.o
obj-$(CONFIG_FS_MBCACHE)
+=
mbcache.o
obj-$(CONFIG_FS_POSIX_ACL)
+=
posix_acl.o xattr_acl.o
obj-$(CONFIG_NFS_COMMON)
+=
nfs_common/
obj-$(CONFIG_QUOTA)
+=
dquot.o
obj-$(CONFIG_QFMT_V1)
+=
quota_v1.o
...
...
This diff is collapsed.
Click to expand it.
fs/lockd/clntlock.c
View file @
9092131f
...
...
@@ -31,7 +31,7 @@ static int reclaimer(void *ptr);
* This is the representation of a blocked client lock.
*/
struct
nlm_wait
{
struct
nlm_wait
*
b_nex
t
;
/* linked list */
struct
list_head
b_lis
t
;
/* linked list */
wait_queue_head_t
b_wait
;
/* where to wait on */
struct
nlm_host
*
b_host
;
struct
file_lock
*
b_lock
;
/* local file lock */
...
...
@@ -39,27 +39,54 @@ struct nlm_wait {
u32
b_status
;
/* grant callback status */
};
static
struct
nlm_wait
*
nlm_blocked
;
static
LIST_HEAD
(
nlm_blocked
)
;
/*
*
Block on a lock
*
Queue up a lock for blocking so that the GRANTED request can see it
*/
int
nlmclnt_block
(
struct
nlm_host
*
host
,
struct
file_lock
*
fl
,
u32
*
statp
)
int
nlmclnt_prepare_block
(
struct
nlm_rqst
*
req
,
struct
nlm_host
*
host
,
struct
file_lock
*
fl
)
{
struct
nlm_wait
*
block
;
BUG_ON
(
req
->
a_block
!=
NULL
);
block
=
kmalloc
(
sizeof
(
*
block
),
GFP_KERNEL
);
if
(
block
==
NULL
)
return
-
ENOMEM
;
block
->
b_host
=
host
;
block
->
b_lock
=
fl
;
init_waitqueue_head
(
&
block
->
b_wait
);
block
->
b_status
=
NLM_LCK_BLOCKED
;
list_add
(
&
block
->
b_list
,
&
nlm_blocked
);
req
->
a_block
=
block
;
return
0
;
}
void
nlmclnt_finish_block
(
struct
nlm_rqst
*
req
)
{
struct
nlm_wait
block
,
**
head
;
int
err
;
u32
pstate
;
struct
nlm_wait
*
block
=
req
->
a_block
;
block
.
b_host
=
host
;
block
.
b_lock
=
fl
;
init_waitqueue_head
(
&
block
.
b_wait
);
block
.
b_status
=
NLM_LCK_BLOCKED
;
block
.
b_next
=
nlm_blocked
;
nlm_blocked
=
&
block
;
if
(
block
==
NULL
)
return
;
req
->
a_block
=
NULL
;
list_del
(
&
block
->
b_list
);
kfree
(
block
);
}
/*
* Block on a lock
*/
long
nlmclnt_block
(
struct
nlm_rqst
*
req
,
long
timeout
)
{
struct
nlm_wait
*
block
=
req
->
a_block
;
long
ret
;
/* Remember pseudo nsm state */
pstate
=
host
->
h_state
;
/* A borken server might ask us to block even if we didn't
* request it. Just say no!
*/
if
(
!
req
->
a_args
.
block
)
return
-
EAGAIN
;
/* Go to sleep waiting for GRANT callback. Some servers seem
* to lose callbacks, however, so we're going to poll from
...
...
@@ -69,28 +96,16 @@ nlmclnt_block(struct nlm_host *host, struct file_lock *fl, u32 *statp)
* a 1 minute timeout would do. See the comment before
* nlmclnt_lock for an explanation.
*/
sleep_on_timeout
(
&
block
.
b_wait
,
30
*
HZ
);
for
(
head
=
&
nlm_blocked
;
*
head
;
head
=
&
(
*
head
)
->
b_next
)
{
if
(
*
head
==
&
block
)
{
*
head
=
block
.
b_next
;
break
;
}
}
ret
=
wait_event_interruptible_timeout
(
block
->
b_wait
,
block
->
b_status
!=
NLM_LCK_BLOCKED
,
timeout
);
if
(
!
signalled
()
)
{
*
stat
p
=
block
.
b_status
;
return
0
;
if
(
block
->
b_status
!=
NLM_LCK_BLOCKED
)
{
req
->
a_res
.
stat
us
=
block
->
b_status
;
block
->
b_status
=
NLM_LCK_BLOCKED
;
}
/* Okay, we were interrupted. Cancel the pending request
* unless the server has rebooted.
*/
if
(
pstate
==
host
->
h_state
&&
(
err
=
nlmclnt_cancel
(
host
,
fl
))
<
0
)
printk
(
KERN_NOTICE
"lockd: CANCEL call failed (errno %d)
\n
"
,
-
err
);
return
-
ERESTARTSYS
;
return
ret
;
}
/*
...
...
@@ -100,27 +115,23 @@ u32
nlmclnt_grant
(
struct
nlm_lock
*
lock
)
{
struct
nlm_wait
*
block
;
u32
res
=
nlm_lck_denied
;
/*
* Look up blocked request based on arguments.
* Warning: must not use cookie to match it!
*/
for
(
block
=
nlm_blocked
;
block
;
block
=
block
->
b_next
)
{
if
(
nlm_compare_locks
(
block
->
b_lock
,
&
lock
->
fl
))
break
;
list_for_each_entry
(
block
,
&
nlm_blocked
,
b_list
)
{
if
(
nlm_compare_locks
(
block
->
b_lock
,
&
lock
->
fl
))
{
/* Alright, we found a lock. Set the return status
* and wake up the caller
*/
block
->
b_status
=
NLM_LCK_GRANTED
;
wake_up
(
&
block
->
b_wait
);
res
=
nlm_granted
;
}
}
/* Ooops, no blocked request found. */
if
(
block
==
NULL
)
return
nlm_lck_denied
;
/* Alright, we found the lock. Set the return status and
* wake up the caller.
*/
block
->
b_status
=
NLM_LCK_GRANTED
;
wake_up
(
&
block
->
b_wait
);
return
nlm_granted
;
return
res
;
}
/*
...
...
@@ -230,7 +241,7 @@ restart:
host
->
h_reclaiming
=
0
;
/* Now, wake up all processes that sleep on a blocked lock */
for
(
block
=
nlm_blocked
;
b
lock
;
block
=
block
->
b_nex
t
)
{
list_for_each_entry
(
block
,
&
nlm_blocked
,
b
_lis
t
)
{
if
(
block
->
b_host
==
host
)
{
block
->
b_status
=
NLM_LCK_DENIED_GRACE_PERIOD
;
wake_up
(
&
block
->
b_wait
);
...
...
This diff is collapsed.
Click to expand it.
fs/lockd/clntproc.c
View file @
9092131f
...
...
@@ -21,6 +21,7 @@
#define NLMDBG_FACILITY NLMDBG_CLIENT
#define NLMCLNT_GRACE_WAIT (5*HZ)
#define NLMCLNT_POLL_TIMEOUT (30*HZ)
static
int
nlmclnt_test
(
struct
nlm_rqst
*
,
struct
file_lock
*
);
static
int
nlmclnt_lock
(
struct
nlm_rqst
*
,
struct
file_lock
*
);
...
...
@@ -553,7 +554,8 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
{
struct
nlm_host
*
host
=
req
->
a_host
;
struct
nlm_res
*
resp
=
&
req
->
a_res
;
int
status
;
long
timeout
;
int
status
;
if
(
!
host
->
h_monitored
&&
nsm_monitor
(
host
)
<
0
)
{
printk
(
KERN_NOTICE
"lockd: failed to monitor %s
\n
"
,
...
...
@@ -562,15 +564,32 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
goto
out
;
}
do
{
if
((
status
=
nlmclnt_call
(
req
,
NLMPROC_LOCK
))
>=
0
)
{
if
(
resp
->
status
!=
NLM_LCK_BLOCKED
)
break
;
status
=
nlmclnt_block
(
host
,
fl
,
&
resp
->
status
);
}
if
(
req
->
a_args
.
block
)
{
status
=
nlmclnt_prepare_block
(
req
,
host
,
fl
);
if
(
status
<
0
)
goto
out
;
}
while
(
resp
->
status
==
NLM_LCK_BLOCKED
&&
req
->
a_args
.
block
);
}
for
(;;)
{
status
=
nlmclnt_call
(
req
,
NLMPROC_LOCK
);
if
(
status
<
0
)
goto
out_unblock
;
if
(
resp
->
status
!=
NLM_LCK_BLOCKED
)
break
;
/* Wait on an NLM blocking lock */
timeout
=
nlmclnt_block
(
req
,
NLMCLNT_POLL_TIMEOUT
);
/* Did a reclaimer thread notify us of a server reboot? */
if
(
resp
->
status
==
NLM_LCK_DENIED_GRACE_PERIOD
)
continue
;
if
(
resp
->
status
!=
NLM_LCK_BLOCKED
)
break
;
if
(
timeout
>=
0
)
continue
;
/* We were interrupted. Send a CANCEL request to the server
* and exit
*/
status
=
(
int
)
timeout
;
goto
out_unblock
;
}
if
(
resp
->
status
==
NLM_LCK_GRANTED
)
{
fl
->
fl_u
.
nfs_fl
.
state
=
host
->
h_state
;
...
...
@@ -579,6 +598,11 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
do_vfs_lock
(
fl
);
}
status
=
nlm_stat_to_errno
(
resp
->
status
);
out_unblock:
nlmclnt_finish_block
(
req
);
/* Cancel the blocked request if it is still pending */
if
(
resp
->
status
==
NLM_LCK_BLOCKED
)
nlmclnt_cancel
(
host
,
fl
);
out:
nlmclnt_release_lockargs
(
req
);
return
status
;
...
...
This diff is collapsed.
Click to expand it.
fs/lockd/host.c
View file @
9092131f
...
...
@@ -189,17 +189,15 @@ nlm_bind_host(struct nlm_host *host)
goto
forgetit
;
xprt_set_timeout
(
&
xprt
->
timeout
,
5
,
nlmsvc_timeout
);
xprt
->
nocong
=
1
;
/* No congestion control for NLM */
xprt
->
resvport
=
1
;
/* NLM requires a reserved port */
/* Existing NLM servers accept AUTH_UNIX only */
clnt
=
rpc_create_client
(
xprt
,
host
->
h_name
,
&
nlm_program
,
host
->
h_version
,
RPC_AUTH_UNIX
);
if
(
IS_ERR
(
clnt
))
{
xprt_destroy
(
xprt
);
if
(
IS_ERR
(
clnt
))
goto
forgetit
;
}
clnt
->
cl_autobind
=
1
;
/* turn on pmap queries */
xprt
->
nocong
=
1
;
/* No congestion control for NLM */
xprt
->
resvport
=
1
;
/* NLM requires a reserved port */
host
->
h_rpcclnt
=
clnt
;
}
...
...
This diff is collapsed.
Click to expand it.
fs/lockd/mon.c
View file @
9092131f
...
...
@@ -115,20 +115,19 @@ nsm_create(void)
xprt
=
xprt_create_proto
(
IPPROTO_UDP
,
&
sin
,
NULL
);
if
(
IS_ERR
(
xprt
))
return
(
struct
rpc_clnt
*
)
xprt
;
xprt
->
resvport
=
1
;
/* NSM requires a reserved port */
clnt
=
rpc_create_client
(
xprt
,
"localhost"
,
&
nsm_program
,
SM_VERSION
,
RPC_AUTH_NULL
);
if
(
IS_ERR
(
clnt
))
goto
out_
destroy
;
goto
out_
err
;
clnt
->
cl_softrtry
=
1
;
clnt
->
cl_chatty
=
1
;
clnt
->
cl_oneshot
=
1
;
xprt
->
resvport
=
1
;
/* NSM requires a reserved port */
return
clnt
;
out_destroy:
xprt_destroy
(
xprt
);
out_err:
return
clnt
;
}
...
...
This diff is collapsed.
Click to expand it.
fs/locks.c
View file @
9092131f
...
...
@@ -1548,6 +1548,8 @@ int fcntl_getlk(struct file *filp, struct flock __user *l)
if
(
filp
->
f_op
&&
filp
->
f_op
->
lock
)
{
error
=
filp
->
f_op
->
lock
(
filp
,
F_GETLK
,
&
file_lock
);
if
(
file_lock
.
fl_ops
&&
file_lock
.
fl_ops
->
fl_release_private
)
file_lock
.
fl_ops
->
fl_release_private
(
&
file_lock
);
if
(
error
<
0
)
goto
out
;
else
...
...
@@ -1690,6 +1692,8 @@ int fcntl_getlk64(struct file *filp, struct flock64 __user *l)
if
(
filp
->
f_op
&&
filp
->
f_op
->
lock
)
{
error
=
filp
->
f_op
->
lock
(
filp
,
F_GETLK
,
&
file_lock
);
if
(
file_lock
.
fl_ops
&&
file_lock
.
fl_ops
->
fl_release_private
)
file_lock
.
fl_ops
->
fl_release_private
(
&
file_lock
);
if
(
error
<
0
)
goto
out
;
else
...
...
@@ -1873,6 +1877,8 @@ void locks_remove_flock(struct file *filp)
.
fl_end
=
OFFSET_MAX
,
};
filp
->
f_op
->
flock
(
filp
,
F_SETLKW
,
&
fl
);
if
(
fl
.
fl_ops
&&
fl
.
fl_ops
->
fl_release_private
)
fl
.
fl_ops
->
fl_release_private
(
&
fl
);
}
lock_kernel
();
...
...
This diff is collapsed.
Click to expand it.
fs/nfs/Makefile
View file @
9092131f
...
...
@@ -8,6 +8,7 @@ nfs-y := dir.o file.o inode.o nfs2xdr.o pagelist.o \
proc.o read.o symlink.o unlink.o write.o
nfs-$(CONFIG_ROOT_NFS)
+=
nfsroot.o mount_clnt.o
nfs-$(CONFIG_NFS_V3)
+=
nfs3proc.o nfs3xdr.o
nfs-$(CONFIG_NFS_V3_ACL)
+=
nfs3acl.o
nfs-$(CONFIG_NFS_V4)
+=
nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o
\
delegation.o idmap.o
\
callback.o callback_xdr.o callback_proc.o
...
...
This diff is collapsed.
Click to expand it.
fs/nfs/callback.c
View file @
9092131f
...
...
@@ -14,6 +14,7 @@
#include <linux/sunrpc/svc.h>
#include <linux/sunrpc/svcsock.h>
#include <linux/nfs_fs.h>
#include "nfs4_fs.h"
#include "callback.h"
#define NFSDBG_FACILITY NFSDBG_CALLBACK
...
...
This diff is collapsed.
Click to expand it.
fs/nfs/callback_proc.c
View file @
9092131f
...
...
@@ -8,6 +8,7 @@
#include <linux/config.h>
#include <linux/nfs4.h>
#include <linux/nfs_fs.h>
#include "nfs4_fs.h"
#include "callback.h"
#include "delegation.h"
...
...
This diff is collapsed.
Click to expand it.
fs/nfs/callback_xdr.c
View file @
9092131f
...
...
@@ -10,6 +10,7 @@
#include <linux/sunrpc/svc.h>
#include <linux/nfs4.h>
#include <linux/nfs_fs.h>
#include "nfs4_fs.h"
#include "callback.h"
#define CB_OP_TAGLEN_MAXSZ (512)
...
...
@@ -410,7 +411,6 @@ static int nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *resp
xdr_init_decode
(
&
xdr_in
,
&
rqstp
->
rq_arg
,
rqstp
->
rq_arg
.
head
[
0
].
iov_base
);
p
=
(
uint32_t
*
)((
char
*
)
rqstp
->
rq_res
.
head
[
0
].
iov_base
+
rqstp
->
rq_res
.
head
[
0
].
iov_len
);
rqstp
->
rq_res
.
head
[
0
].
iov_len
=
PAGE_SIZE
;
xdr_init_encode
(
&
xdr_out
,
&
rqstp
->
rq_res
,
p
);
decode_compound_hdr_arg
(
&
xdr_in
,
&
hdr_arg
);
...
...
This diff is collapsed.
Click to expand it.
fs/nfs/delegation.c
View file @
9092131f
...
...
@@ -16,6 +16,7 @@
#include <linux/nfs_fs.h>
#include <linux/nfs_xdr.h>
#include "nfs4_fs.h"
#include "delegation.h"
static
struct
nfs_delegation
*
nfs_alloc_delegation
(
void
)
...
...
This diff is collapsed.
Click to expand it.
fs/nfs/dir.c
View file @
9092131f
...
...
@@ -32,6 +32,7 @@
#include <linux/smp_lock.h>
#include <linux/namei.h>
#include "nfs4_fs.h"
#include "delegation.h"
#define NFS_PARANOIA 1
...
...
@@ -50,8 +51,10 @@ static int nfs_mknod(struct inode *, struct dentry *, int, dev_t);
static
int
nfs_rename
(
struct
inode
*
,
struct
dentry
*
,
struct
inode
*
,
struct
dentry
*
);
static
int
nfs_fsync_dir
(
struct
file
*
,
struct
dentry
*
,
int
);
static
loff_t
nfs_llseek_dir
(
struct
file
*
,
loff_t
,
int
);
struct
file_operations
nfs_dir_operations
=
{
.
llseek
=
nfs_llseek_dir
,
.
read
=
generic_read_dir
,
.
readdir
=
nfs_readdir
,
.
open
=
nfs_opendir
,
...
...
@@ -74,6 +77,27 @@ struct inode_operations nfs_dir_inode_operations = {
.
setattr
=
nfs_setattr
,
};
#ifdef CONFIG_NFS_V3
struct
inode_operations
nfs3_dir_inode_operations
=
{
.
create
=
nfs_create
,
.
lookup
=
nfs_lookup
,
.
link
=
nfs_link
,
.
unlink
=
nfs_unlink
,
.
symlink
=
nfs_symlink
,
.
mkdir
=
nfs_mkdir
,
.
rmdir
=
nfs_rmdir
,
.
mknod
=
nfs_mknod
,
.
rename
=
nfs_rename
,
.
permission
=
nfs_permission
,
.
getattr
=
nfs_getattr
,
.
setattr
=
nfs_setattr
,
.
listxattr
=
nfs3_listxattr
,
.
getxattr
=
nfs3_getxattr
,
.
setxattr
=
nfs3_setxattr
,
.
removexattr
=
nfs3_removexattr
,
};
#endif
/* CONFIG_NFS_V3 */
#ifdef CONFIG_NFS_V4
static
struct
dentry
*
nfs_atomic_lookup
(
struct
inode
*
,
struct
dentry
*
,
struct
nameidata
*
);
...
...
@@ -90,6 +114,9 @@ struct inode_operations nfs4_dir_inode_operations = {
.
permission
=
nfs_permission
,
.
getattr
=
nfs_getattr
,
.
setattr
=
nfs_setattr
,
.
getxattr
=
nfs4_getxattr
,
.
setxattr
=
nfs4_setxattr
,
.
listxattr
=
nfs4_listxattr
,
};
#endif
/* CONFIG_NFS_V4 */
...
...
@@ -116,7 +143,8 @@ typedef struct {
struct
page
*
page
;
unsigned
long
page_index
;
u32
*
ptr
;
u64
target
;
u64
*
dir_cookie
;
loff_t
current_index
;
struct
nfs_entry
*
entry
;
decode_dirent_t
decode
;
int
plus
;
...
...
@@ -164,12 +192,10 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
NFS_FLAGS
(
inode
)
|=
NFS_INO_INVALID_ATIME
;
/* Ensure consistent page alignment of the data.
* Note: assumes we have exclusive access to this mapping either
* through
t
inode->i_sem or some other mechanism.
* through inode->i_sem or some other mechanism.
*/
if
(
page
->
index
==
0
)
{
invalidate_inode_pages
(
inode
->
i_mapping
);
NFS_I
(
inode
)
->
readdir_timestamp
=
timestamp
;
}
if
(
page
->
index
==
0
)
invalidate_inode_pages2_range
(
inode
->
i_mapping
,
PAGE_CACHE_SIZE
,
-
1
);
unlock_page
(
page
);
return
0
;
error:
...
...
@@ -202,22 +228,22 @@ void dir_page_release(nfs_readdir_descriptor_t *desc)
/*
* Given a pointer to a buffer that has already been filled by a call
* to readdir, find the next entry.
* to readdir, find the next entry
with cookie '*desc->dir_cookie'
.
*
* If the end of the buffer has been reached, return -EAGAIN, if not,
* return the offset within the buffer of the next entry to be
* read.
*/
static
inline
int
find_dirent
(
nfs_readdir_descriptor_t
*
desc
,
struct
page
*
page
)
int
find_dirent
(
nfs_readdir_descriptor_t
*
desc
)
{
struct
nfs_entry
*
entry
=
desc
->
entry
;
int
loop_count
=
0
,
status
;
while
((
status
=
dir_decode
(
desc
))
==
0
)
{
dfprintk
(
VFS
,
"NFS: found cookie %Lu
\n
"
,
(
long
long
)
entry
->
cookie
);
if
(
entry
->
prev_cookie
==
desc
->
target
)
dfprintk
(
VFS
,
"NFS: found cookie %Lu
\n
"
,
(
unsigned
long
long
)
entry
->
cookie
);
if
(
entry
->
prev_cookie
==
*
desc
->
dir_cookie
)
break
;
if
(
loop_count
++
>
200
)
{
loop_count
=
0
;
...
...
@@ -229,8 +255,44 @@ int find_dirent(nfs_readdir_descriptor_t *desc, struct page *page)
}
/*
* Find the given page, and call find_dirent() in order to try to
* return the next entry.
* Given a pointer to a buffer that has already been filled by a call
* to readdir, find the entry at offset 'desc->file->f_pos'.
*
* If the end of the buffer has been reached, return -EAGAIN, if not,
* return the offset within the buffer of the next entry to be
* read.
*/
static
inline
int
find_dirent_index
(
nfs_readdir_descriptor_t
*
desc
)
{
struct
nfs_entry
*
entry
=
desc
->
entry
;
int
loop_count
=
0
,
status
;
for
(;;)
{
status
=
dir_decode
(
desc
);
if
(
status
)
break
;
dfprintk
(
VFS
,
"NFS: found cookie %Lu at index %Ld
\n
"
,
(
unsigned
long
long
)
entry
->
cookie
,
desc
->
current_index
);
if
(
desc
->
file
->
f_pos
==
desc
->
current_index
)
{
*
desc
->
dir_cookie
=
entry
->
cookie
;
break
;
}
desc
->
current_index
++
;
if
(
loop_count
++
>
200
)
{
loop_count
=
0
;
schedule
();
}
}
dfprintk
(
VFS
,
"NFS: find_dirent_index() returns %d
\n
"
,
status
);
return
status
;
}
/*
* Find the given page, and call find_dirent() or find_dirent_index in
* order to try to return the next entry.
*/
static
inline
int
find_dirent_page
(
nfs_readdir_descriptor_t
*
desc
)
...
...
@@ -253,7 +315,10 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc)
/* NOTE: Someone else may have changed the READDIRPLUS flag */
desc
->
page
=
page
;
desc
->
ptr
=
kmap
(
page
);
/* matching kunmap in nfs_do_filldir */
status
=
find_dirent
(
desc
,
page
);
if
(
*
desc
->
dir_cookie
!=
0
)
status
=
find_dirent
(
desc
);
else
status
=
find_dirent_index
(
desc
);
if
(
status
<
0
)
dir_page_release
(
desc
);
out:
...
...
@@ -268,7 +333,8 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc)
* Recurse through the page cache pages, and return a
* filled nfs_entry structure of the next directory entry if possible.
*
* The target for the search is 'desc->target'.
* The target for the search is '*desc->dir_cookie' if non-0,
* 'desc->file->f_pos' otherwise
*/
static
inline
int
readdir_search_pagecache
(
nfs_readdir_descriptor_t
*
desc
)
...
...
@@ -276,7 +342,16 @@ int readdir_search_pagecache(nfs_readdir_descriptor_t *desc)
int
loop_count
=
0
;
int
res
;
dfprintk
(
VFS
,
"NFS: readdir_search_pagecache() searching for cookie %Lu
\n
"
,
(
long
long
)
desc
->
target
);
/* Always search-by-index from the beginning of the cache */
if
(
*
desc
->
dir_cookie
==
0
)
{
dfprintk
(
VFS
,
"NFS: readdir_search_pagecache() searching for offset %Ld
\n
"
,
(
long
long
)
desc
->
file
->
f_pos
);
desc
->
page_index
=
0
;
desc
->
entry
->
cookie
=
desc
->
entry
->
prev_cookie
=
0
;
desc
->
entry
->
eof
=
0
;
desc
->
current_index
=
0
;
}
else
dfprintk
(
VFS
,
"NFS: readdir_search_pagecache() searching for cookie %Lu
\n
"
,
(
unsigned
long
long
)
*
desc
->
dir_cookie
);
for
(;;)
{
res
=
find_dirent_page
(
desc
);
if
(
res
!=
-
EAGAIN
)
...
...
@@ -313,7 +388,7 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
int
loop_count
=
0
,
res
;
dfprintk
(
VFS
,
"NFS: nfs_do_filldir() filling starting @ cookie %Lu
\n
"
,
(
long
long
)
desc
->
target
);
dfprintk
(
VFS
,
"NFS: nfs_do_filldir() filling starting @ cookie %Lu
\n
"
,
(
long
long
)
entry
->
cookie
);
for
(;;)
{
unsigned
d_type
=
DT_UNKNOWN
;
...
...
@@ -333,10 +408,11 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
}
res
=
filldir
(
dirent
,
entry
->
name
,
entry
->
len
,
entry
->
prev_cookie
,
fileid
,
d_type
);
file
->
f_pos
,
fileid
,
d_type
);
if
(
res
<
0
)
break
;
file
->
f_pos
=
desc
->
target
=
entry
->
cookie
;
file
->
f_pos
++
;
*
desc
->
dir_cookie
=
entry
->
cookie
;
if
(
dir_decode
(
desc
)
!=
0
)
{
desc
->
page_index
++
;
break
;
...
...
@@ -349,7 +425,7 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
dir_page_release
(
desc
);
if
(
dentry
!=
NULL
)
dput
(
dentry
);
dfprintk
(
VFS
,
"NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d
\n
"
,
(
long
long
)
desc
->
target
,
res
);
dfprintk
(
VFS
,
"NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d
\n
"
,
(
unsigned
long
long
)
*
desc
->
dir_cookie
,
res
);
return
res
;
}
...
...
@@ -375,14 +451,14 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
struct
page
*
page
=
NULL
;
int
status
;
dfprintk
(
VFS
,
"NFS: uncached_readdir() searching for cookie %Lu
\n
"
,
(
long
long
)
desc
->
target
);
dfprintk
(
VFS
,
"NFS: uncached_readdir() searching for cookie %Lu
\n
"
,
(
unsigned
long
long
)
*
desc
->
dir_cookie
);
page
=
alloc_page
(
GFP_HIGHUSER
);
if
(
!
page
)
{
status
=
-
ENOMEM
;
goto
out
;
}
desc
->
error
=
NFS_PROTO
(
inode
)
->
readdir
(
file
->
f_dentry
,
cred
,
desc
->
target
,
desc
->
error
=
NFS_PROTO
(
inode
)
->
readdir
(
file
->
f_dentry
,
cred
,
*
desc
->
dir_cookie
,
page
,
NFS_SERVER
(
inode
)
->
dtsize
,
desc
->
plus
);
...
...
@@ -391,7 +467,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
desc
->
ptr
=
kmap
(
page
);
/* matching kunmap in nfs_do_filldir */
if
(
desc
->
error
>=
0
)
{
if
((
status
=
dir_decode
(
desc
))
==
0
)
desc
->
entry
->
prev_cookie
=
desc
->
target
;
desc
->
entry
->
prev_cookie
=
*
desc
->
dir_cookie
;
}
else
status
=
-
EIO
;
if
(
status
<
0
)
...
...
@@ -412,8 +488,9 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
goto
out
;
}
/* The file offset position is now represented as a true offset into the
* page cache as is the case in most of the other filesystems.
/* The file offset position represents the dirent entry number. A
last cookie cache takes care of the common case of reading the
whole directory.
*/
static
int
nfs_readdir
(
struct
file
*
filp
,
void
*
dirent
,
filldir_t
filldir
)
{
...
...
@@ -435,15 +512,15 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
}
/*
* filp->f_pos points to the
file offset in the page cache
.
*
but if the cache has meanwhile been zapped, we need to
*
read from the last dirent to revalidate f_pos
*
itself
.
* filp->f_pos points to the
dirent entry number
.
*
*desc->dir_cookie has the cookie for the next entry. We have
*
to either find the entry with the appropriate number or
*
revalidate the cookie
.
*/
memset
(
desc
,
0
,
sizeof
(
*
desc
));
desc
->
file
=
filp
;
desc
->
target
=
filp
->
f_pos
;
desc
->
dir_cookie
=
&
((
struct
nfs_open_context
*
)
filp
->
private_data
)
->
dir_cookie
;
desc
->
decode
=
NFS_PROTO
(
inode
)
->
decode_dirent
;
desc
->
plus
=
NFS_USE_READDIRPLUS
(
inode
);
...
...
@@ -455,9 +532,10 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
while
(
!
desc
->
entry
->
eof
)
{
res
=
readdir_search_pagecache
(
desc
);
if
(
res
==
-
EBADCOOKIE
)
{
/* This means either end of directory */
if
(
desc
->
entry
->
cookie
!=
desc
->
target
)
{
if
(
*
desc
->
dir_cookie
&&
desc
->
entry
->
cookie
!=
*
desc
->
dir_cookie
)
{
/* Or that the server has 'lost' a cookie */
res
=
uncached_readdir
(
desc
,
dirent
,
filldir
);
if
(
res
>=
0
)
...
...
@@ -490,6 +568,28 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
return
0
;
}
loff_t
nfs_llseek_dir
(
struct
file
*
filp
,
loff_t
offset
,
int
origin
)
{
down
(
&
filp
->
f_dentry
->
d_inode
->
i_sem
);
switch
(
origin
)
{
case
1
:
offset
+=
filp
->
f_pos
;
case
0
:
if
(
offset
>=
0
)
break
;
default:
offset
=
-
EINVAL
;
goto
out
;
}
if
(
offset
!=
filp
->
f_pos
)
{
filp
->
f_pos
=
offset
;
((
struct
nfs_open_context
*
)
filp
->
private_data
)
->
dir_cookie
=
0
;
}
out:
up
(
&
filp
->
f_dentry
->
d_inode
->
i_sem
);
return
offset
;
}
/*
* All directory operations under NFS are synchronous, so fsync()
* is a dummy operation.
...
...
This diff is collapsed.
Click to expand it.
fs/nfs/direct.c
View file @
9092131f
...
...
@@ -517,7 +517,7 @@ retry:
result
=
tot_bytes
;
out:
nfs_end_data_update
_defer
(
inode
);
nfs_end_data_update
(
inode
);
nfs_writedata_free
(
wdata
);
return
result
;
...
...
This diff is collapsed.
Click to expand it.
fs/nfs/file.c
View file @
9092131f
...
...
@@ -71,6 +71,18 @@ struct inode_operations nfs_file_inode_operations = {
.
setattr
=
nfs_setattr
,
};
#ifdef CONFIG_NFS_V3
struct
inode_operations
nfs3_file_inode_operations
=
{
.
permission
=
nfs_permission
,
.
getattr
=
nfs_getattr
,
.
setattr
=
nfs_setattr
,
.
listxattr
=
nfs3_listxattr
,
.
getxattr
=
nfs3_getxattr
,
.
setxattr
=
nfs3_setxattr
,
.
removexattr
=
nfs3_removexattr
,
};
#endif
/* CONFIG_NFS_v3 */
/* Hack for future NFS swap support */
#ifndef IS_SWAPFILE
# define IS_SWAPFILE(inode) (0)
...
...
@@ -115,6 +127,21 @@ nfs_file_release(struct inode *inode, struct file *filp)
return
NFS_PROTO
(
inode
)
->
file_release
(
inode
,
filp
);
}
/**
* nfs_revalidate_file - Revalidate the page cache & related metadata
* @inode - pointer to inode struct
* @file - pointer to file
*/
static
int
nfs_revalidate_file
(
struct
inode
*
inode
,
struct
file
*
filp
)
{
int
retval
=
0
;
if
((
NFS_FLAGS
(
inode
)
&
NFS_INO_REVAL_PAGECACHE
)
||
nfs_attribute_timeout
(
inode
))
retval
=
__nfs_revalidate_inode
(
NFS_SERVER
(
inode
),
inode
);
nfs_revalidate_mapping
(
inode
,
filp
->
f_mapping
);
return
0
;
}
/**
* nfs_revalidate_size - Revalidate the file size
* @inode - pointer to inode struct
...
...
@@ -137,7 +164,8 @@ static int nfs_revalidate_file_size(struct inode *inode, struct file *filp)
goto
force_reval
;
if
(
nfsi
->
npages
!=
0
)
return
0
;
return
nfs_revalidate_inode
(
server
,
inode
);
if
(
!
(
NFS_FLAGS
(
inode
)
&
NFS_INO_REVAL_PAGECACHE
)
&&
!
nfs_attribute_timeout
(
inode
))
return
0
;
force_reval:
return
__nfs_revalidate_inode
(
server
,
inode
);
}
...
...
@@ -198,7 +226,7 @@ nfs_file_read(struct kiocb *iocb, char __user * buf, size_t count, loff_t pos)
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
(
unsigned
long
)
count
,
(
unsigned
long
)
pos
);
result
=
nfs_revalidate_
inode
(
NFS_SERVER
(
inode
)
,
i
node
);
result
=
nfs_revalidate_
file
(
inode
,
i
ocb
->
ki_filp
);
if
(
!
result
)
result
=
generic_file_aio_read
(
iocb
,
buf
,
count
,
pos
);
return
result
;
...
...
@@ -216,7 +244,7 @@ nfs_file_sendfile(struct file *filp, loff_t *ppos, size_t count,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
,
(
unsigned
long
)
count
,
(
unsigned
long
long
)
*
ppos
);
res
=
nfs_revalidate_
inode
(
NFS_SERVER
(
inode
)
,
inode
);
res
=
nfs_revalidate_
file
(
inode
,
filp
);
if
(
!
res
)
res
=
generic_file_sendfile
(
filp
,
ppos
,
count
,
actor
,
target
);
return
res
;
...
...
@@ -232,7 +260,7 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
dfprintk
(
VFS
,
"nfs: mmap(%s/%s)
\n
"
,
dentry
->
d_parent
->
d_name
.
name
,
dentry
->
d_name
.
name
);
status
=
nfs_revalidate_
inode
(
NFS_SERVER
(
inode
)
,
inod
e
);
status
=
nfs_revalidate_
file
(
inode
,
fil
e
);
if
(
!
status
)
status
=
generic_file_mmap
(
file
,
vma
);
return
status
;
...
...
@@ -321,9 +349,15 @@ nfs_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t
result
=
-
EBUSY
;
if
(
IS_SWAPFILE
(
inode
))
goto
out_swapfile
;
result
=
nfs_revalidate_inode
(
NFS_SERVER
(
inode
),
inode
);
if
(
result
)
goto
out
;
/*
* O_APPEND implies that we must revalidate the file length.
*/
if
(
iocb
->
ki_filp
->
f_flags
&
O_APPEND
)
{
result
=
nfs_revalidate_file_size
(
inode
,
iocb
->
ki_filp
);
if
(
result
)
goto
out
;
}
nfs_revalidate_mapping
(
inode
,
iocb
->
ki_filp
->
f_mapping
);
result
=
count
;
if
(
!
count
)
...
...
This diff is collapsed.
Click to expand it.
fs/nfs/idmap.c
View file @
9092131f
...
...
@@ -50,6 +50,7 @@
#include <linux/nfs_fs.h>
#include <linux/nfs_idmap.h>
#include "nfs4_fs.h"
#define IDMAP_HASH_SZ 128
...
...
This diff is collapsed.
Click to expand it.
fs/nfs/inode.c
View file @
9092131f
This diff is collapsed.
Click to expand it.
fs/nfs/mount_clnt.c
View file @
9092131f
...
...
@@ -80,9 +80,7 @@ mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version,
clnt
=
rpc_create_client
(
xprt
,
hostname
,
&
mnt_program
,
version
,
RPC_AUTH_UNIX
);
if
(
IS_ERR
(
clnt
))
{
xprt_destroy
(
xprt
);
}
else
{
if
(
!
IS_ERR
(
clnt
))
{
clnt
->
cl_softrtry
=
1
;
clnt
->
cl_chatty
=
1
;
clnt
->
cl_oneshot
=
1
;
...
...
This diff is collapsed.
Click to expand it.
fs/nfs/nfs3acl.c
0 → 100644
View file @
9092131f
#include <linux/fs.h>
#include <linux/nfs.h>
#include <linux/nfs3.h>
#include <linux/nfs_fs.h>
#include <linux/xattr_acl.h>
#include <linux/nfsacl.h>
#define NFSDBG_FACILITY NFSDBG_PROC
ssize_t
nfs3_listxattr
(
struct
dentry
*
dentry
,
char
*
buffer
,
size_t
size
)
{
struct
inode
*
inode
=
dentry
->
d_inode
;
struct
posix_acl
*
acl
;
int
pos
=
0
,
len
=
0
;
# define output(s) do { \
if (pos + sizeof(s) <= size) { \
memcpy(buffer + pos, s, sizeof(s)); \
pos += sizeof(s); \
} \
len += sizeof(s); \
} while(0)
acl
=
nfs3_proc_getacl
(
inode
,
ACL_TYPE_ACCESS
);
if
(
IS_ERR
(
acl
))
return
PTR_ERR
(
acl
);
if
(
acl
)
{
output
(
"system.posix_acl_access"
);
posix_acl_release
(
acl
);
}
if
(
S_ISDIR
(
inode
->
i_mode
))
{
acl
=
nfs3_proc_getacl
(
inode
,
ACL_TYPE_DEFAULT
);
if
(
IS_ERR
(
acl
))
return
PTR_ERR
(
acl
);
if
(
acl
)
{
output
(
"system.posix_acl_default"
);
posix_acl_release
(
acl
);
}
}
# undef output
if
(
!
buffer
||
len
<=
size
)
return
len
;
return
-
ERANGE
;
}
ssize_t
nfs3_getxattr
(
struct
dentry
*
dentry
,
const
char
*
name
,
void
*
buffer
,
size_t
size
)
{
struct
inode
*
inode
=
dentry
->
d_inode
;
struct
posix_acl
*
acl
;
int
type
,
error
=
0
;
if
(
strcmp
(
name
,
XATTR_NAME_ACL_ACCESS
)
==
0
)
type
=
ACL_TYPE_ACCESS
;
else
if
(
strcmp
(
name
,
XATTR_NAME_ACL_DEFAULT
)
==
0
)
type
=
ACL_TYPE_DEFAULT
;
else
return
-
EOPNOTSUPP
;
acl
=
nfs3_proc_getacl
(
inode
,
type
);
if
(
IS_ERR
(
acl
))
return
PTR_ERR
(
acl
);
else
if
(
acl
)
{
if
(
type
==
ACL_TYPE_ACCESS
&&
acl
->
a_count
==
0
)
error
=
-
ENODATA
;
else
error
=
posix_acl_to_xattr
(
acl
,
buffer
,
size
);
posix_acl_release
(
acl
);
}
else
error
=
-
ENODATA
;
return
error
;
}
int
nfs3_setxattr
(
struct
dentry
*
dentry
,
const
char
*
name
,
const
void
*
value
,
size_t
size
,
int
flags
)
{
struct
inode
*
inode
=
dentry
->
d_inode
;
struct
posix_acl
*
acl
;
int
type
,
error
;
if
(
strcmp
(
name
,
XATTR_NAME_ACL_ACCESS
)
==
0
)
type
=
ACL_TYPE_ACCESS
;
else
if
(
strcmp
(
name
,
XATTR_NAME_ACL_DEFAULT
)
==
0
)
type
=
ACL_TYPE_DEFAULT
;
else
return
-
EOPNOTSUPP
;
acl
=
posix_acl_from_xattr
(
value
,
size
);
if
(
IS_ERR
(
acl
))
return
PTR_ERR
(
acl
);
error
=
nfs3_proc_setacl
(
inode
,
type
,
acl
);
posix_acl_release
(
acl
);
return
error
;
}
int
nfs3_removexattr
(
struct
dentry
*
dentry
,
const
char
*
name
)
{
struct
inode
*
inode
=
dentry
->
d_inode
;
int
type
;
if
(
strcmp
(
name
,
XATTR_NAME_ACL_ACCESS
)
==
0
)
type
=
ACL_TYPE_ACCESS
;
else
if
(
strcmp
(
name
,
XATTR_NAME_ACL_DEFAULT
)
==
0
)
type
=
ACL_TYPE_DEFAULT
;
else
return
-
EOPNOTSUPP
;
return
nfs3_proc_setacl
(
inode
,
type
,
NULL
);
}
static
void
__nfs3_forget_cached_acls
(
struct
nfs_inode
*
nfsi
)
{
if
(
!
IS_ERR
(
nfsi
->
acl_access
))
{
posix_acl_release
(
nfsi
->
acl_access
);
nfsi
->
acl_access
=
ERR_PTR
(
-
EAGAIN
);
}
if
(
!
IS_ERR
(
nfsi
->
acl_default
))
{
posix_acl_release
(
nfsi
->
acl_default
);
nfsi
->
acl_default
=
ERR_PTR
(
-
EAGAIN
);
}
}
void
nfs3_forget_cached_acls
(
struct
inode
*
inode
)
{
dprintk
(
"NFS: nfs3_forget_cached_acls(%s/%ld)
\n
"
,
inode
->
i_sb
->
s_id
,
inode
->
i_ino
);
spin_lock
(
&
inode
->
i_lock
);
__nfs3_forget_cached_acls
(
NFS_I
(
inode
));
spin_unlock
(
&
inode
->
i_lock
);
}
static
struct
posix_acl
*
nfs3_get_cached_acl
(
struct
inode
*
inode
,
int
type
)
{
struct
nfs_inode
*
nfsi
=
NFS_I
(
inode
);
struct
posix_acl
*
acl
=
ERR_PTR
(
-
EINVAL
);
spin_lock
(
&
inode
->
i_lock
);
switch
(
type
)
{
case
ACL_TYPE_ACCESS
:
acl
=
nfsi
->
acl_access
;
break
;
case
ACL_TYPE_DEFAULT
:
acl
=
nfsi
->
acl_default
;
break
;
default:
goto
out
;
}
if
(
IS_ERR
(
acl
))
acl
=
ERR_PTR
(
-
EAGAIN
);
else
acl
=
posix_acl_dup
(
acl
);
out:
spin_unlock
(
&
inode
->
i_lock
);
dprintk
(
"NFS: nfs3_get_cached_acl(%s/%ld, %d) = %p
\n
"
,
inode
->
i_sb
->
s_id
,
inode
->
i_ino
,
type
,
acl
);
return
acl
;
}
static
void
nfs3_cache_acls
(
struct
inode
*
inode
,
struct
posix_acl
*
acl
,
struct
posix_acl
*
dfacl
)
{
struct
nfs_inode
*
nfsi
=
NFS_I
(
inode
);
dprintk
(
"nfs3_cache_acls(%s/%ld, %p, %p)
\n
"
,
inode
->
i_sb
->
s_id
,
inode
->
i_ino
,
acl
,
dfacl
);
spin_lock
(
&
inode
->
i_lock
);
__nfs3_forget_cached_acls
(
NFS_I
(
inode
));
nfsi
->
acl_access
=
posix_acl_dup
(
acl
);
nfsi
->
acl_default
=
posix_acl_dup
(
dfacl
);
spin_unlock
(
&
inode
->
i_lock
);
}
struct
posix_acl
*
nfs3_proc_getacl
(
struct
inode
*
inode
,
int
type
)
{
struct
nfs_server
*
server
=
NFS_SERVER
(
inode
);
struct
nfs_fattr
fattr
;
struct
page
*
pages
[
NFSACL_MAXPAGES
]
=
{
};
struct
nfs3_getaclargs
args
=
{
.
fh
=
NFS_FH
(
inode
),
/* The xdr layer may allocate pages here. */
.
pages
=
pages
,
};
struct
nfs3_getaclres
res
=
{
.
fattr
=
&
fattr
,
};
struct
posix_acl
*
acl
;
int
status
,
count
;
if
(
!
nfs_server_capable
(
inode
,
NFS_CAP_ACLS
))
return
ERR_PTR
(
-
EOPNOTSUPP
);
status
=
nfs_revalidate_inode
(
server
,
inode
);
if
(
status
<
0
)
return
ERR_PTR
(
status
);
acl
=
nfs3_get_cached_acl
(
inode
,
type
);
if
(
acl
!=
ERR_PTR
(
-
EAGAIN
))
return
acl
;
acl
=
NULL
;
/*
* Only get the access acl when explicitly requested: We don't
* need it for access decisions, and only some applications use
* it. Applications which request the access acl first are not
* penalized from this optimization.
*/
if
(
type
==
ACL_TYPE_ACCESS
)
args
.
mask
|=
NFS_ACLCNT
|
NFS_ACL
;
if
(
S_ISDIR
(
inode
->
i_mode
))
args
.
mask
|=
NFS_DFACLCNT
|
NFS_DFACL
;
if
(
args
.
mask
==
0
)
return
NULL
;
dprintk
(
"NFS call getacl
\n
"
);
status
=
rpc_call
(
server
->
client_acl
,
ACLPROC3_GETACL
,
&
args
,
&
res
,
0
);
dprintk
(
"NFS reply getacl: %d
\n
"
,
status
);
/* pages may have been allocated at the xdr layer. */
for
(
count
=
0
;
count
<
NFSACL_MAXPAGES
&&
args
.
pages
[
count
];
count
++
)
__free_page
(
args
.
pages
[
count
]);
switch
(
status
)
{
case
0
:
status
=
nfs_refresh_inode
(
inode
,
&
fattr
);
break
;
case
-
EPFNOSUPPORT
:
case
-
EPROTONOSUPPORT
:
dprintk
(
"NFS_V3_ACL extension not supported; disabling
\n
"
);
server
->
caps
&=
~
NFS_CAP_ACLS
;
case
-
ENOTSUPP
:
status
=
-
EOPNOTSUPP
;
default:
goto
getout
;
}
if
((
args
.
mask
&
res
.
mask
)
!=
args
.
mask
)
{
status
=
-
EIO
;
goto
getout
;
}
if
(
res
.
acl_access
!=
NULL
)
{
if
(
posix_acl_equiv_mode
(
res
.
acl_access
,
NULL
)
==
0
)
{
posix_acl_release
(
res
.
acl_access
);
res
.
acl_access
=
NULL
;
}
}
nfs3_cache_acls
(
inode
,
res
.
acl_access
,
res
.
acl_default
);
switch
(
type
)
{
case
ACL_TYPE_ACCESS
:
acl
=
res
.
acl_access
;
res
.
acl_access
=
NULL
;
break
;
case
ACL_TYPE_DEFAULT
:
acl
=
res
.
acl_default
;
res
.
acl_default
=
NULL
;
}
getout:
posix_acl_release
(
res
.
acl_access
);
posix_acl_release
(
res
.
acl_default
);
if
(
status
!=
0
)
{
posix_acl_release
(
acl
);
acl
=
ERR_PTR
(
status
);
}
return
acl
;
}
static
int
nfs3_proc_setacls
(
struct
inode
*
inode
,
struct
posix_acl
*
acl
,
struct
posix_acl
*
dfacl
)
{
struct
nfs_server
*
server
=
NFS_SERVER
(
inode
);
struct
nfs_fattr
fattr
;
struct
page
*
pages
[
NFSACL_MAXPAGES
]
=
{
};
struct
nfs3_setaclargs
args
=
{
.
inode
=
inode
,
.
mask
=
NFS_ACL
,
.
acl_access
=
acl
,
.
pages
=
pages
,
};
int
status
,
count
;
status
=
-
EOPNOTSUPP
;
if
(
!
nfs_server_capable
(
inode
,
NFS_CAP_ACLS
))
goto
out
;
/* We are doing this here, because XDR marshalling can only
return -ENOMEM. */
status
=
-
ENOSPC
;
if
(
acl
!=
NULL
&&
acl
->
a_count
>
NFS_ACL_MAX_ENTRIES
)
goto
out
;
if
(
dfacl
!=
NULL
&&
dfacl
->
a_count
>
NFS_ACL_MAX_ENTRIES
)
goto
out
;
if
(
S_ISDIR
(
inode
->
i_mode
))
{
args
.
mask
|=
NFS_DFACL
;
args
.
acl_default
=
dfacl
;
}
dprintk
(
"NFS call setacl
\n
"
);
nfs_begin_data_update
(
inode
);
status
=
rpc_call
(
server
->
client_acl
,
ACLPROC3_SETACL
,
&
args
,
&
fattr
,
0
);
NFS_FLAGS
(
inode
)
|=
NFS_INO_INVALID_ACCESS
;
nfs_end_data_update
(
inode
);
dprintk
(
"NFS reply setacl: %d
\n
"
,
status
);
/* pages may have been allocated at the xdr layer. */
for
(
count
=
0
;
count
<
NFSACL_MAXPAGES
&&
args
.
pages
[
count
];
count
++
)
__free_page
(
args
.
pages
[
count
]);
switch
(
status
)
{
case
0
:
status
=
nfs_refresh_inode
(
inode
,
&
fattr
);
break
;
case
-
EPFNOSUPPORT
:
case
-
EPROTONOSUPPORT
:
dprintk
(
"NFS_V3_ACL SETACL RPC not supported"
"(will not retry)
\n
"
);
server
->
caps
&=
~
NFS_CAP_ACLS
;
case
-
ENOTSUPP
:
status
=
-
EOPNOTSUPP
;
}
out:
return
status
;
}
int
nfs3_proc_setacl
(
struct
inode
*
inode
,
int
type
,
struct
posix_acl
*
acl
)
{
struct
posix_acl
*
alloc
=
NULL
,
*
dfacl
=
NULL
;
int
status
;
if
(
S_ISDIR
(
inode
->
i_mode
))
{
switch
(
type
)
{
case
ACL_TYPE_ACCESS
:
alloc
=
dfacl
=
nfs3_proc_getacl
(
inode
,
ACL_TYPE_DEFAULT
);
if
(
IS_ERR
(
alloc
))
goto
fail
;
break
;
case
ACL_TYPE_DEFAULT
:
dfacl
=
acl
;
alloc
=
acl
=
nfs3_proc_getacl
(
inode
,
ACL_TYPE_ACCESS
);
if
(
IS_ERR
(
alloc
))
goto
fail
;
break
;
default:
return
-
EINVAL
;
}
}
else
if
(
type
!=
ACL_TYPE_ACCESS
)
return
-
EINVAL
;
if
(
acl
==
NULL
)
{
alloc
=
acl
=
posix_acl_from_mode
(
inode
->
i_mode
,
GFP_KERNEL
);
if
(
IS_ERR
(
alloc
))
goto
fail
;
}
status
=
nfs3_proc_setacls
(
inode
,
acl
,
dfacl
);
posix_acl_release
(
alloc
);
return
status
;
fail:
return
PTR_ERR
(
alloc
);
}
int
nfs3_proc_set_default_acl
(
struct
inode
*
dir
,
struct
inode
*
inode
,
mode_t
mode
)
{
struct
posix_acl
*
dfacl
,
*
acl
;
int
error
=
0
;
dfacl
=
nfs3_proc_getacl
(
dir
,
ACL_TYPE_DEFAULT
);
if
(
IS_ERR
(
dfacl
))
{
error
=
PTR_ERR
(
dfacl
);
return
(
error
==
-
EOPNOTSUPP
)
?
0
:
error
;
}
if
(
!
dfacl
)
return
0
;
acl
=
posix_acl_clone
(
dfacl
,
GFP_KERNEL
);
error
=
-
ENOMEM
;
if
(
!
acl
)
goto
out_release_dfacl
;
error
=
posix_acl_create_masq
(
acl
,
&
mode
);
if
(
error
<
0
)
goto
out_release_acl
;
error
=
nfs3_proc_setacls
(
inode
,
acl
,
S_ISDIR
(
inode
->
i_mode
)
?
dfacl
:
NULL
);
out_release_acl:
posix_acl_release
(
acl
);
out_release_dfacl:
posix_acl_release
(
dfacl
);
return
error
;
}
This diff is collapsed.
Click to expand it.
fs/nfs/nfs3proc.c
View file @
9092131f
...
...
@@ -17,6 +17,7 @@
#include <linux/nfs_page.h>
#include <linux/lockd/bind.h>
#include <linux/smp_lock.h>
#include <linux/nfs_mount.h>
#define NFSDBG_FACILITY NFSDBG_PROC
...
...
@@ -45,7 +46,7 @@ static inline int
nfs3_rpc_call_wrapper
(
struct
rpc_clnt
*
clnt
,
u32
proc
,
void
*
argp
,
void
*
resp
,
int
flags
)
{
struct
rpc_message
msg
=
{
.
rpc_proc
=
&
nfs3_procedures
[
proc
],
.
rpc_proc
=
&
clnt
->
cl_procinfo
[
proc
],
.
rpc_argp
=
argp
,
.
rpc_resp
=
resp
,
};
...
...
@@ -313,7 +314,8 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
.
fh
=
&
fhandle
,
.
fattr
=
&
fattr
};
int
status
;
mode_t
mode
=
sattr
->
ia_mode
;
int
status
;
dprintk
(
"NFS call create %s
\n
"
,
dentry
->
d_name
.
name
);
arg
.
createmode
=
NFS3_CREATE_UNCHECKED
;
...
...
@@ -323,6 +325,8 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
arg
.
verifier
[
1
]
=
current
->
pid
;
}
sattr
->
ia_mode
&=
~
current
->
fs
->
umask
;
again:
dir_attr
.
valid
=
0
;
fattr
.
valid
=
0
;
...
...
@@ -369,6 +373,9 @@ again:
nfs_refresh_inode
(
dentry
->
d_inode
,
&
fattr
);
dprintk
(
"NFS reply setattr (post-create): %d
\n
"
,
status
);
}
if
(
status
!=
0
)
goto
out
;
status
=
nfs3_proc_set_default_acl
(
dir
,
dentry
->
d_inode
,
mode
);
out:
dprintk
(
"NFS reply create: %d
\n
"
,
status
);
return
status
;
...
...
@@ -538,15 +545,24 @@ nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
.
fh
=
&
fhandle
,
.
fattr
=
&
fattr
};
int
status
;
int
mode
=
sattr
->
ia_mode
;
int
status
;
dprintk
(
"NFS call mkdir %s
\n
"
,
dentry
->
d_name
.
name
);
dir_attr
.
valid
=
0
;
fattr
.
valid
=
0
;
sattr
->
ia_mode
&=
~
current
->
fs
->
umask
;
status
=
rpc_call
(
NFS_CLIENT
(
dir
),
NFS3PROC_MKDIR
,
&
arg
,
&
res
,
0
);
nfs_refresh_inode
(
dir
,
&
dir_attr
);
if
(
status
==
0
)
status
=
nfs_instantiate
(
dentry
,
&
fhandle
,
&
fattr
);
if
(
status
!=
0
)
goto
out
;
status
=
nfs_instantiate
(
dentry
,
&
fhandle
,
&
fattr
);
if
(
status
!=
0
)
goto
out
;
status
=
nfs3_proc_set_default_acl
(
dir
,
dentry
->
d_inode
,
mode
);
out:
dprintk
(
"NFS reply mkdir: %d
\n
"
,
status
);
return
status
;
}
...
...
@@ -641,6 +657,7 @@ nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
.
fh
=
&
fh
,
.
fattr
=
&
fattr
};
mode_t
mode
=
sattr
->
ia_mode
;
int
status
;
switch
(
sattr
->
ia_mode
&
S_IFMT
)
{
...
...
@@ -653,12 +670,20 @@ nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
dprintk
(
"NFS call mknod %s %u:%u
\n
"
,
dentry
->
d_name
.
name
,
MAJOR
(
rdev
),
MINOR
(
rdev
));
sattr
->
ia_mode
&=
~
current
->
fs
->
umask
;
dir_attr
.
valid
=
0
;
fattr
.
valid
=
0
;
status
=
rpc_call
(
NFS_CLIENT
(
dir
),
NFS3PROC_MKNOD
,
&
arg
,
&
res
,
0
);
nfs_refresh_inode
(
dir
,
&
dir_attr
);
if
(
status
==
0
)
status
=
nfs_instantiate
(
dentry
,
&
fh
,
&
fattr
);
if
(
status
!=
0
)
goto
out
;
status
=
nfs_instantiate
(
dentry
,
&
fh
,
&
fattr
);
if
(
status
!=
0
)
goto
out
;
status
=
nfs3_proc_set_default_acl
(
dir
,
dentry
->
d_inode
,
mode
);
out:
dprintk
(
"NFS reply mknod: %d
\n
"
,
status
);
return
status
;
}
...
...
@@ -825,7 +850,8 @@ nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
struct
nfs_rpc_ops
nfs_v3_clientops
=
{
.
version
=
3
,
/* protocol version */
.
dentry_ops
=
&
nfs_dentry_operations
,
.
dir_inode_ops
=
&
nfs_dir_inode_operations
,
.
dir_inode_ops
=
&
nfs3_dir_inode_operations
,
.
file_inode_ops
=
&
nfs3_file_inode_operations
,
.
getroot
=
nfs3_proc_get_root
,
.
getattr
=
nfs3_proc_getattr
,
.
setattr
=
nfs3_proc_setattr
,
...
...
@@ -856,4 +882,5 @@ struct nfs_rpc_ops nfs_v3_clientops = {
.
file_open
=
nfs_open
,
.
file_release
=
nfs_release
,
.
lock
=
nfs3_proc_lock
,
.
clear_acl_cache
=
nfs3_forget_cached_acls
,
};
This diff is collapsed.
Click to expand it.
Prev
1
2
3
4
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment