Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
3f1990d3
Commit
3f1990d3
authored
Feb 07, 2004
by
Trond Myklebust
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
NFSv4: Add support for POSIX file locking.
parent
1f37cd43
Changes
10
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
878 additions
and
40 deletions
+878
-40
fs/nfs/file.c
fs/nfs/file.c
+9
-14
fs/nfs/nfs3proc.c
fs/nfs/nfs3proc.c
+8
-0
fs/nfs/nfs4proc.c
fs/nfs/nfs4proc.c
+273
-17
fs/nfs/nfs4state.c
fs/nfs/nfs4state.c
+172
-2
fs/nfs/nfs4xdr.c
fs/nfs/nfs4xdr.c
+306
-3
fs/nfs/proc.c
fs/nfs/proc.c
+8
-0
include/linux/nfs4.h
include/linux/nfs4.h
+3
-0
include/linux/nfs_fs.h
include/linux/nfs_fs.h
+36
-1
include/linux/nfs_page.h
include/linux/nfs_page.h
+1
-0
include/linux/nfs_xdr.h
include/linux/nfs_xdr.h
+62
-3
No files found.
fs/nfs/file.c
View file @
3f1990d3
...
@@ -26,7 +26,6 @@
...
@@ -26,7 +26,6 @@
#include <linux/mm.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/pagemap.h>
#include <linux/pagemap.h>
#include <linux/lockd/bind.h>
#include <linux/smp_lock.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <asm/uaccess.h>
...
@@ -278,22 +277,18 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
...
@@ -278,22 +277,18 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
if
(
!
inode
)
if
(
!
inode
)
return
-
EINVAL
;
return
-
EINVAL
;
/* This will be in a forthcoming patch. */
if
(
NFS_PROTO
(
inode
)
->
version
==
4
)
{
printk
(
KERN_INFO
"NFS: file locking over NFSv4 is not yet supported
\n
"
);
return
-
EIO
;
}
/* No mandatory locks over NFS */
/* No mandatory locks over NFS */
if
((
inode
->
i_mode
&
(
S_ISGID
|
S_IXGRP
))
==
S_ISGID
)
if
((
inode
->
i_mode
&
(
S_ISGID
|
S_IXGRP
))
==
S_ISGID
)
return
-
ENOLCK
;
return
-
ENOLCK
;
if
(
NFS_PROTO
(
inode
)
->
version
!=
4
)
{
/* Fake OK code if mounted without NLM support */
/* Fake OK code if mounted without NLM support */
if
(
NFS_SERVER
(
inode
)
->
flags
&
NFS_MOUNT_NONLM
)
{
if
(
NFS_SERVER
(
inode
)
->
flags
&
NFS_MOUNT_NONLM
)
{
if
(
IS_GETLK
(
cmd
))
if
(
IS_GETLK
(
cmd
))
status
=
LOCK_USE_CLNT
;
status
=
LOCK_USE_CLNT
;
goto
out_ok
;
goto
out_ok
;
}
}
}
/*
/*
* No BSD flocks over NFS allowed.
* No BSD flocks over NFS allowed.
...
@@ -302,7 +297,7 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
...
@@ -302,7 +297,7 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
* Not sure whether that would be unique, though, or whether
* Not sure whether that would be unique, though, or whether
* that would break in other places.
* that would break in other places.
*/
*/
if
(
!
fl
->
fl_owner
||
(
fl
->
fl_flags
&
FL_POSIX
)
!=
FL_POSIX
)
if
(
!
fl
->
fl_owner
||
!
(
fl
->
fl_flags
&
FL_POSIX
)
)
return
-
ENOLCK
;
return
-
ENOLCK
;
/*
/*
...
@@ -322,7 +317,7 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
...
@@ -322,7 +317,7 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
return
status
;
return
status
;
lock_kernel
();
lock_kernel
();
status
=
nlmclnt_proc
(
inode
,
cmd
,
fl
);
status
=
NFS_PROTO
(
inode
)
->
lock
(
filp
,
cmd
,
fl
);
unlock_kernel
();
unlock_kernel
();
if
(
status
<
0
)
if
(
status
<
0
)
return
status
;
return
status
;
...
...
fs/nfs/nfs3proc.c
View file @
3f1990d3
...
@@ -15,6 +15,7 @@
...
@@ -15,6 +15,7 @@
#include <linux/nfs3.h>
#include <linux/nfs3.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_page.h>
#include <linux/nfs_page.h>
#include <linux/lockd/bind.h>
#include <linux/smp_lock.h>
#include <linux/smp_lock.h>
#define NFSDBG_FACILITY NFSDBG_PROC
#define NFSDBG_FACILITY NFSDBG_PROC
...
@@ -896,6 +897,12 @@ nfs3_request_compatible(struct nfs_page *req, struct file *filp, struct page *pa
...
@@ -896,6 +897,12 @@ nfs3_request_compatible(struct nfs_page *req, struct file *filp, struct page *pa
return
1
;
return
1
;
}
}
static
int
nfs3_proc_lock
(
struct
file
*
filp
,
int
cmd
,
struct
file_lock
*
fl
)
{
return
nlmclnt_proc
(
filp
->
f_dentry
->
d_inode
,
cmd
,
fl
);
}
struct
nfs_rpc_ops
nfs_v3_clientops
=
{
struct
nfs_rpc_ops
nfs_v3_clientops
=
{
.
version
=
3
,
/* protocol version */
.
version
=
3
,
/* protocol version */
.
dentry_ops
=
&
nfs_dentry_operations
,
.
dentry_ops
=
&
nfs_dentry_operations
,
...
@@ -931,4 +938,5 @@ struct nfs_rpc_ops nfs_v3_clientops = {
...
@@ -931,4 +938,5 @@ struct nfs_rpc_ops nfs_v3_clientops = {
.
file_release
=
nfs_release
,
.
file_release
=
nfs_release
,
.
request_init
=
nfs3_request_init
,
.
request_init
=
nfs3_request_init
,
.
request_compatible
=
nfs3_request_compatible
,
.
request_compatible
=
nfs3_request_compatible
,
.
lock
=
nfs3_proc_lock
,
};
};
fs/nfs/nfs4proc.c
View file @
3f1990d3
...
@@ -598,9 +598,7 @@ nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *satt
...
@@ -598,9 +598,7 @@ nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *satt
.
fh
=
&
o_res
.
fh
,
.
fh
=
&
o_res
.
fh
,
.
seqid
=
sp
->
so_seqid
,
.
seqid
=
sp
->
so_seqid
,
};
};
struct
nfs_open_confirmres
oc_res
=
{
struct
nfs_open_confirmres
oc_res
;
.
status
=
0
,
};
struct
rpc_message
msg
=
{
struct
rpc_message
msg
=
{
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_OPEN_CONFIRM
],
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_OPEN_CONFIRM
],
.
rpc_argp
=
&
oc_arg
,
.
rpc_argp
=
&
oc_arg
,
...
@@ -692,7 +690,7 @@ nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr,
...
@@ -692,7 +690,7 @@ nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr,
fattr
->
valid
=
0
;
fattr
->
valid
=
0
;
if
(
state
)
if
(
state
)
memcpy
(
&
arg
.
stateid
,
&
state
->
stateid
,
sizeof
(
arg
.
stateid
)
);
nfs4_copy_stateid
(
&
arg
.
stateid
,
state
,
0
);
else
else
memcpy
(
&
arg
.
stateid
,
&
zero_stateid
,
sizeof
(
arg
.
stateid
));
memcpy
(
&
arg
.
stateid
,
&
zero_stateid
,
sizeof
(
arg
.
stateid
));
...
@@ -724,9 +722,7 @@ nfs4_do_close(struct inode *inode, struct nfs4_state *state)
...
@@ -724,9 +722,7 @@ nfs4_do_close(struct inode *inode, struct nfs4_state *state)
struct
nfs_closeargs
arg
=
{
struct
nfs_closeargs
arg
=
{
.
fh
=
NFS_FH
(
inode
),
.
fh
=
NFS_FH
(
inode
),
};
};
struct
nfs_closeres
res
=
{
struct
nfs_closeres
res
;
.
status
=
0
,
};
struct
rpc_message
msg
=
{
struct
rpc_message
msg
=
{
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_CLOSE
],
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_CLOSE
],
.
rpc_argp
=
&
arg
,
.
rpc_argp
=
&
arg
,
...
@@ -758,9 +754,7 @@ nfs4_do_downgrade(struct inode *inode, struct nfs4_state *state, mode_t mode)
...
@@ -758,9 +754,7 @@ nfs4_do_downgrade(struct inode *inode, struct nfs4_state *state, mode_t mode)
.
seqid
=
sp
->
so_seqid
,
.
seqid
=
sp
->
so_seqid
,
.
share_access
=
mode
,
.
share_access
=
mode
,
};
};
struct
nfs_closeres
res
=
{
struct
nfs_closeres
res
;
.
status
=
0
,
};
struct
rpc_message
msg
=
{
struct
rpc_message
msg
=
{
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_OPEN_DOWNGRADE
],
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_OPEN_DOWNGRADE
],
.
rpc_argp
=
&
arg
,
.
rpc_argp
=
&
arg
,
...
@@ -1085,7 +1079,7 @@ nfs4_proc_read(struct nfs_read_data *rdata, struct file *filp)
...
@@ -1085,7 +1079,7 @@ nfs4_proc_read(struct nfs_read_data *rdata, struct file *filp)
if
(
filp
)
{
if
(
filp
)
{
struct
nfs4_state
*
state
;
struct
nfs4_state
*
state
;
state
=
(
struct
nfs4_state
*
)
filp
->
private_data
;
state
=
(
struct
nfs4_state
*
)
filp
->
private_data
;
memcpy
(
&
rdata
->
args
.
stateid
,
&
state
->
stateid
,
sizeof
(
rdata
->
args
.
stateid
)
);
nfs4_copy_stateid
(
&
rdata
->
args
.
stateid
,
state
,
rdata
->
lockowner
);
msg
.
rpc_cred
=
state
->
owner
->
so_cred
;
msg
.
rpc_cred
=
state
->
owner
->
so_cred
;
}
else
{
}
else
{
memcpy
(
&
rdata
->
args
.
stateid
,
&
zero_stateid
,
sizeof
(
rdata
->
args
.
stateid
));
memcpy
(
&
rdata
->
args
.
stateid
,
&
zero_stateid
,
sizeof
(
rdata
->
args
.
stateid
));
...
@@ -1127,7 +1121,7 @@ nfs4_proc_write(struct nfs_write_data *wdata, struct file *filp)
...
@@ -1127,7 +1121,7 @@ nfs4_proc_write(struct nfs_write_data *wdata, struct file *filp)
if
(
filp
)
{
if
(
filp
)
{
struct
nfs4_state
*
state
;
struct
nfs4_state
*
state
;
state
=
(
struct
nfs4_state
*
)
filp
->
private_data
;
state
=
(
struct
nfs4_state
*
)
filp
->
private_data
;
memcpy
(
&
wdata
->
args
.
stateid
,
&
state
->
stateid
,
sizeof
(
wdata
->
args
.
stateid
)
);
nfs4_copy_stateid
(
&
wdata
->
args
.
stateid
,
state
,
wdata
->
lockowner
);
msg
.
rpc_cred
=
state
->
owner
->
so_cred
;
msg
.
rpc_cred
=
state
->
owner
->
so_cred
;
}
else
{
}
else
{
memcpy
(
&
wdata
->
args
.
stateid
,
&
zero_stateid
,
sizeof
(
wdata
->
args
.
stateid
));
memcpy
(
&
wdata
->
args
.
stateid
,
&
zero_stateid
,
sizeof
(
wdata
->
args
.
stateid
));
...
@@ -1163,7 +1157,7 @@ nfs4_proc_commit(struct nfs_write_data *cdata, struct file *filp)
...
@@ -1163,7 +1157,7 @@ nfs4_proc_commit(struct nfs_write_data *cdata, struct file *filp)
if
(
filp
)
{
if
(
filp
)
{
struct
nfs4_state
*
state
;
struct
nfs4_state
*
state
;
state
=
(
struct
nfs4_state
*
)
filp
->
private_data
;
state
=
(
struct
nfs4_state
*
)
filp
->
private_data
;
memcpy
(
&
cdata
->
args
.
stateid
,
&
state
->
stateid
,
sizeof
(
cdata
->
args
.
stateid
)
);
nfs4_copy_stateid
(
&
cdata
->
args
.
stateid
,
state
,
cdata
->
lockowner
);
msg
.
rpc_cred
=
state
->
owner
->
so_cred
;
msg
.
rpc_cred
=
state
->
owner
->
so_cred
;
}
else
{
}
else
{
memcpy
(
&
cdata
->
args
.
stateid
,
&
zero_stateid
,
sizeof
(
cdata
->
args
.
stateid
));
memcpy
(
&
cdata
->
args
.
stateid
,
&
zero_stateid
,
sizeof
(
cdata
->
args
.
stateid
));
...
@@ -1513,7 +1507,7 @@ nfs4_restart_read(struct rpc_task *task)
...
@@ -1513,7 +1507,7 @@ nfs4_restart_read(struct rpc_task *task)
rpc_restart_call
(
task
);
rpc_restart_call
(
task
);
req
=
nfs_list_entry
(
data
->
pages
.
next
);
req
=
nfs_list_entry
(
data
->
pages
.
next
);
if
(
req
->
wb_state
)
if
(
req
->
wb_state
)
memcpy
(
&
data
->
args
.
stateid
,
&
req
->
wb_state
->
stateid
,
sizeof
(
data
->
args
.
stateid
)
);
nfs4_copy_stateid
(
&
data
->
args
.
stateid
,
req
->
wb_state
,
req
->
wb_lockowner
);
else
else
memcpy
(
&
data
->
args
.
stateid
,
&
zero_stateid
,
sizeof
(
data
->
args
.
stateid
));
memcpy
(
&
data
->
args
.
stateid
,
&
zero_stateid
,
sizeof
(
data
->
args
.
stateid
));
}
}
...
@@ -1564,8 +1558,9 @@ nfs4_proc_read_setup(struct nfs_read_data *data, unsigned int count)
...
@@ -1564,8 +1558,9 @@ nfs4_proc_read_setup(struct nfs_read_data *data, unsigned int count)
data
->
res
.
eof
=
0
;
data
->
res
.
eof
=
0
;
data
->
timestamp
=
jiffies
;
data
->
timestamp
=
jiffies
;
data
->
lockowner
=
req
->
wb_lockowner
;
if
(
req
->
wb_state
)
if
(
req
->
wb_state
)
memcpy
(
&
data
->
args
.
stateid
,
&
req
->
wb_state
->
stateid
,
sizeof
(
data
->
args
.
stateid
)
);
nfs4_copy_stateid
(
&
data
->
args
.
stateid
,
req
->
wb_state
,
req
->
wb_lockowner
);
else
else
memcpy
(
&
data
->
args
.
stateid
,
&
zero_stateid
,
sizeof
(
data
->
args
.
stateid
));
memcpy
(
&
data
->
args
.
stateid
,
&
zero_stateid
,
sizeof
(
data
->
args
.
stateid
));
...
@@ -1605,7 +1600,7 @@ nfs4_restart_write(struct rpc_task *task)
...
@@ -1605,7 +1600,7 @@ nfs4_restart_write(struct rpc_task *task)
rpc_restart_call
(
task
);
rpc_restart_call
(
task
);
req
=
nfs_list_entry
(
data
->
pages
.
next
);
req
=
nfs_list_entry
(
data
->
pages
.
next
);
if
(
req
->
wb_state
)
if
(
req
->
wb_state
)
memcpy
(
&
data
->
args
.
stateid
,
&
req
->
wb_state
->
stateid
,
sizeof
(
data
->
args
.
stateid
)
);
nfs4_copy_stateid
(
&
data
->
args
.
stateid
,
req
->
wb_state
,
req
->
wb_lockowner
);
else
else
memcpy
(
&
data
->
args
.
stateid
,
&
zero_stateid
,
sizeof
(
data
->
args
.
stateid
));
memcpy
(
&
data
->
args
.
stateid
,
&
zero_stateid
,
sizeof
(
data
->
args
.
stateid
));
}
}
...
@@ -1661,8 +1656,9 @@ nfs4_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how)
...
@@ -1661,8 +1656,9 @@ nfs4_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how)
data
->
res
.
verf
=
&
data
->
verf
;
data
->
res
.
verf
=
&
data
->
verf
;
data
->
timestamp
=
jiffies
;
data
->
timestamp
=
jiffies
;
data
->
lockowner
=
req
->
wb_lockowner
;
if
(
req
->
wb_state
)
if
(
req
->
wb_state
)
memcpy
(
&
data
->
args
.
stateid
,
&
req
->
wb_state
->
stateid
,
sizeof
(
data
->
args
.
stateid
)
);
nfs4_copy_stateid
(
&
data
->
args
.
stateid
,
req
->
wb_state
,
req
->
wb_lockowner
);
else
else
memcpy
(
&
data
->
args
.
stateid
,
&
zero_stateid
,
sizeof
(
data
->
args
.
stateid
));
memcpy
(
&
data
->
args
.
stateid
,
&
zero_stateid
,
sizeof
(
data
->
args
.
stateid
));
...
@@ -1846,6 +1842,7 @@ nfs4_request_init(struct nfs_page *req, struct file *filp)
...
@@ -1846,6 +1842,7 @@ nfs4_request_init(struct nfs_page *req, struct file *filp)
state
=
(
struct
nfs4_state
*
)
filp
->
private_data
;
state
=
(
struct
nfs4_state
*
)
filp
->
private_data
;
req
->
wb_state
=
state
;
req
->
wb_state
=
state
;
req
->
wb_cred
=
get_rpccred
(
state
->
owner
->
so_cred
);
req
->
wb_cred
=
get_rpccred
(
state
->
owner
->
so_cred
);
req
->
wb_lockowner
=
current
->
files
;
}
}
static
int
static
int
...
@@ -1975,6 +1972,8 @@ nfs4_request_compatible(struct nfs_page *req, struct file *filp, struct page *pa
...
@@ -1975,6 +1972,8 @@ nfs4_request_compatible(struct nfs_page *req, struct file *filp, struct page *pa
state
=
(
struct
nfs4_state
*
)
filp
->
private_data
;
state
=
(
struct
nfs4_state
*
)
filp
->
private_data
;
if
(
req
->
wb_state
!=
state
)
if
(
req
->
wb_state
!=
state
)
return
0
;
return
0
;
if
(
req
->
wb_lockowner
!=
current
->
files
)
return
0
;
cred
=
state
->
owner
->
so_cred
;
cred
=
state
->
owner
->
so_cred
;
if
(
req
->
wb_cred
!=
cred
)
if
(
req
->
wb_cred
!=
cred
)
return
0
;
return
0
;
...
@@ -2032,6 +2031,262 @@ nfs4_proc_setclientid_confirm(struct nfs4_client *clp)
...
@@ -2032,6 +2031,262 @@ nfs4_proc_setclientid_confirm(struct nfs4_client *clp)
return
status
;
return
status
;
}
}
#define NFS4_LOCK_MINTIMEOUT (1 * HZ)
#define NFS4_LOCK_MAXTIMEOUT (30 * HZ)
/*
* sleep, with exponential backoff, and retry the LOCK operation.
*/
static
unsigned
long
nfs4_set_lock_task_retry
(
unsigned
long
timeout
)
{
current
->
state
=
TASK_INTERRUPTIBLE
;
schedule_timeout
(
timeout
);
timeout
<<=
1
;
if
(
timeout
>
NFS4_LOCK_MAXTIMEOUT
)
return
NFS4_LOCK_MAXTIMEOUT
;
return
timeout
;
}
static
inline
int
nfs4_lck_type
(
int
cmd
,
struct
file_lock
*
request
)
{
/* set lock type */
switch
(
request
->
fl_type
)
{
case
F_RDLCK
:
return
IS_SETLKW
(
cmd
)
?
NFS4_READW_LT
:
NFS4_READ_LT
;
case
F_WRLCK
:
return
IS_SETLKW
(
cmd
)
?
NFS4_WRITEW_LT
:
NFS4_WRITE_LT
;
case
F_UNLCK
:
return
NFS4_WRITE_LT
;
}
BUG
();
}
static
inline
uint64_t
nfs4_lck_length
(
struct
file_lock
*
request
)
{
if
(
request
->
fl_end
==
OFFSET_MAX
)
return
~
(
uint64_t
)
0
;
return
request
->
fl_end
-
request
->
fl_start
+
1
;
}
int
nfs4_proc_getlk
(
struct
nfs4_state
*
state
,
int
cmd
,
struct
file_lock
*
request
)
{
struct
inode
*
inode
=
state
->
inode
;
struct
nfs_server
*
server
=
NFS_SERVER
(
inode
);
struct
nfs4_client
*
clp
=
server
->
nfs4_state
;
struct
nfs_lockargs
arg
=
{
.
fh
=
NFS_FH
(
inode
),
.
type
=
nfs4_lck_type
(
cmd
,
request
),
.
offset
=
request
->
fl_start
,
.
length
=
nfs4_lck_length
(
request
),
};
struct
nfs_lockres
res
=
{
.
server
=
server
,
};
struct
rpc_message
msg
=
{
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_LOCKT
],
.
rpc_argp
=
&
arg
,
.
rpc_resp
=
&
res
,
.
rpc_cred
=
state
->
owner
->
so_cred
,
};
struct
nfs_lowner
nlo
;
struct
nfs4_lock_state
*
lsp
;
int
status
;
nlo
.
clientid
=
clp
->
cl_clientid
;
down
(
&
state
->
lock_sema
);
lsp
=
nfs4_find_lock_state
(
state
,
request
->
fl_owner
);
if
(
lsp
)
nlo
.
id
=
lsp
->
ls_id
;
else
{
spin_lock
(
&
clp
->
cl_lock
);
nlo
.
id
=
nfs4_alloc_lockowner_id
(
clp
);
spin_unlock
(
&
clp
->
cl_lock
);
}
arg
.
u
.
lockt
=
&
nlo
;
status
=
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
if
(
!
status
)
{
request
->
fl_type
=
F_UNLCK
;
}
else
if
(
status
==
-
NFS4ERR_DENIED
)
{
int64_t
len
,
start
,
end
;
start
=
res
.
u
.
denied
.
offset
;
len
=
res
.
u
.
denied
.
length
;
end
=
start
+
len
-
1
;
if
(
end
<
0
||
len
==
0
)
request
->
fl_end
=
OFFSET_MAX
;
else
request
->
fl_end
=
(
loff_t
)
end
;
request
->
fl_start
=
(
loff_t
)
start
;
request
->
fl_type
=
F_WRLCK
;
if
(
res
.
u
.
denied
.
type
&
1
)
request
->
fl_type
=
F_RDLCK
;
request
->
fl_pid
=
0
;
status
=
0
;
}
if
(
lsp
)
nfs4_put_lock_state
(
lsp
);
up
(
&
state
->
lock_sema
);
return
status
;
}
int
nfs4_proc_unlck
(
struct
nfs4_state
*
state
,
int
cmd
,
struct
file_lock
*
request
)
{
struct
inode
*
inode
=
state
->
inode
;
struct
nfs_server
*
server
=
NFS_SERVER
(
inode
);
struct
nfs_lockargs
arg
=
{
.
fh
=
NFS_FH
(
inode
),
.
type
=
nfs4_lck_type
(
cmd
,
request
),
.
offset
=
request
->
fl_start
,
.
length
=
nfs4_lck_length
(
request
),
};
struct
nfs_lockres
res
=
{
.
server
=
server
,
};
struct
rpc_message
msg
=
{
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_LOCKU
],
.
rpc_argp
=
&
arg
,
.
rpc_resp
=
&
res
,
.
rpc_cred
=
state
->
owner
->
so_cred
,
};
struct
nfs4_lock_state
*
lsp
;
struct
nfs_locku_opargs
luargs
;
int
status
=
0
;
down
(
&
state
->
lock_sema
);
lsp
=
nfs4_find_lock_state
(
state
,
request
->
fl_owner
);
if
(
!
lsp
)
goto
out
;
luargs
.
seqid
=
lsp
->
ls_seqid
;
memcpy
(
&
luargs
.
stateid
,
&
lsp
->
ls_stateid
,
sizeof
(
luargs
.
stateid
));
arg
.
u
.
locku
=
&
luargs
;
status
=
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
nfs4_increment_lock_seqid
(
status
,
lsp
);
if
(
status
==
0
)
{
memcpy
(
&
lsp
->
ls_stateid
,
&
res
.
u
.
stateid
,
sizeof
(
lsp
->
ls_stateid
));
nfs4_notify_unlck
(
inode
,
request
,
lsp
);
}
nfs4_put_lock_state
(
lsp
);
out:
up
(
&
state
->
lock_sema
);
return
status
;
}
static
int
nfs4_proc_setlk
(
struct
nfs4_state
*
state
,
int
cmd
,
struct
file_lock
*
request
)
{
struct
inode
*
inode
=
state
->
inode
;
struct
nfs_server
*
server
=
NFS_SERVER
(
inode
);
struct
nfs4_lock_state
*
lsp
;
struct
nfs_lockargs
arg
=
{
.
fh
=
NFS_FH
(
inode
),
.
type
=
nfs4_lck_type
(
cmd
,
request
),
.
offset
=
request
->
fl_start
,
.
length
=
nfs4_lck_length
(
request
),
};
struct
nfs_lockres
res
=
{
.
server
=
server
,
};
struct
rpc_message
msg
=
{
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_LOCK
],
.
rpc_argp
=
&
arg
,
.
rpc_resp
=
&
res
,
.
rpc_cred
=
state
->
owner
->
so_cred
,
};
struct
nfs_lock_opargs
largs
=
{
.
new_lock_owner
=
0
,
};
int
status
;
down
(
&
state
->
lock_sema
);
lsp
=
nfs4_find_lock_state
(
state
,
request
->
fl_owner
);
if
(
lsp
==
NULL
)
{
struct
nfs4_state_owner
*
owner
=
state
->
owner
;
struct
nfs_open_to_lock
otl
=
{
.
lock_owner
.
clientid
=
server
->
nfs4_state
->
cl_clientid
,
};
status
=
-
ENOMEM
;
lsp
=
nfs4_alloc_lock_state
(
state
,
request
->
fl_owner
);
if
(
!
lsp
)
goto
out
;
otl
.
lock_seqid
=
lsp
->
ls_seqid
;
otl
.
lock_owner
.
id
=
lsp
->
ls_id
;
memcpy
(
&
otl
.
open_stateid
,
&
state
->
stateid
,
sizeof
(
otl
.
open_stateid
));
largs
.
u
.
open_lock
=
&
otl
;
largs
.
new_lock_owner
=
1
;
arg
.
u
.
lock
=
&
largs
;
down
(
&
owner
->
so_sema
);
otl
.
open_seqid
=
owner
->
so_seqid
;
status
=
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
/* increment open_owner seqid on success, and
* seqid mutating errors */
nfs4_increment_seqid
(
status
,
owner
);
up
(
&
owner
->
so_sema
);
}
else
{
struct
nfs_exist_lock
el
=
{
.
seqid
=
lsp
->
ls_seqid
,
};
memcpy
(
&
el
.
stateid
,
&
lsp
->
ls_stateid
,
sizeof
(
el
.
stateid
));
largs
.
u
.
exist_lock
=
&
el
;
largs
.
new_lock_owner
=
0
;
arg
.
u
.
lock
=
&
largs
;
status
=
rpc_call_sync
(
server
->
client
,
&
msg
,
0
);
}
/* increment seqid on success, and * seqid mutating errors*/
nfs4_increment_lock_seqid
(
status
,
lsp
);
/* save the returned stateid. */
if
(
status
==
0
)
{
memcpy
(
&
lsp
->
ls_stateid
,
&
res
.
u
.
stateid
,
sizeof
(
nfs4_stateid
));
nfs4_notify_setlk
(
inode
,
request
,
lsp
);
}
else
if
(
status
==
-
NFS4ERR_DENIED
)
status
=
-
EAGAIN
;
nfs4_put_lock_state
(
lsp
);
out:
up
(
&
state
->
lock_sema
);
return
status
;
}
static
int
nfs4_proc_lock
(
struct
file
*
filp
,
int
cmd
,
struct
file_lock
*
request
)
{
struct
nfs4_state
*
state
;
unsigned
long
timeout
=
NFS4_LOCK_MINTIMEOUT
;
int
status
;
/* verify open state */
state
=
(
struct
nfs4_state
*
)
filp
->
private_data
;
BUG_ON
(
!
state
);
if
(
request
->
fl_start
<
0
||
request
->
fl_end
<
0
)
return
-
EINVAL
;
if
(
IS_GETLK
(
cmd
))
return
nfs4_proc_getlk
(
state
,
F_GETLK
,
request
);
if
(
!
(
IS_SETLK
(
cmd
)
||
IS_SETLKW
(
cmd
)))
return
-
EINVAL
;
if
(
request
->
fl_type
==
F_UNLCK
)
return
nfs4_proc_unlck
(
state
,
cmd
,
request
);
do
{
status
=
nfs4_proc_setlk
(
state
,
cmd
,
request
);
if
((
status
!=
-
EAGAIN
)
||
IS_SETLK
(
cmd
))
break
;
timeout
=
nfs4_set_lock_task_retry
(
timeout
);
status
=
-
ERESTARTSYS
;
if
(
signalled
())
break
;
}
while
(
status
<
0
);
return
status
;
}
struct
nfs_rpc_ops
nfs_v4_clientops
=
{
struct
nfs_rpc_ops
nfs_v4_clientops
=
{
.
version
=
4
,
/* protocol version */
.
version
=
4
,
/* protocol version */
.
dentry_ops
=
&
nfs4_dentry_operations
,
.
dentry_ops
=
&
nfs4_dentry_operations
,
...
@@ -2067,6 +2322,7 @@ struct nfs_rpc_ops nfs_v4_clientops = {
...
@@ -2067,6 +2322,7 @@ struct nfs_rpc_ops nfs_v4_clientops = {
.
file_release
=
nfs4_proc_file_release
,
.
file_release
=
nfs4_proc_file_release
,
.
request_init
=
nfs4_request_init
,
.
request_init
=
nfs4_request_init
,
.
request_compatible
=
nfs4_request_compatible
,
.
request_compatible
=
nfs4_request_compatible
,
.
lock
=
nfs4_proc_lock
,
};
};
/*
/*
...
...
fs/nfs/nfs4state.c
View file @
3f1990d3
...
@@ -43,6 +43,7 @@
...
@@ -43,6 +43,7 @@
#include <linux/nfs_fs.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_idmap.h>
#include <linux/nfs_idmap.h>
#include <linux/workqueue.h>
#include <linux/workqueue.h>
#include <linux/bitops.h>
#define OPENOWNER_POOL_SIZE 8
#define OPENOWNER_POOL_SIZE 8
...
@@ -168,7 +169,7 @@ nfs4_put_client(struct nfs4_client *clp)
...
@@ -168,7 +169,7 @@ nfs4_put_client(struct nfs4_client *clp)
nfs4_free_client
(
clp
);
nfs4_free_client
(
clp
);
}
}
static
inline
u32
u32
nfs4_alloc_lockowner_id
(
struct
nfs4_client
*
clp
)
nfs4_alloc_lockowner_id
(
struct
nfs4_client
*
clp
)
{
{
return
clp
->
cl_lockowner_id
++
;
return
clp
->
cl_lockowner_id
++
;
...
@@ -304,8 +305,12 @@ nfs4_alloc_open_state(void)
...
@@ -304,8 +305,12 @@ nfs4_alloc_open_state(void)
state
->
state
=
0
;
state
->
state
=
0
;
state
->
nreaders
=
0
;
state
->
nreaders
=
0
;
state
->
nwriters
=
0
;
state
->
nwriters
=
0
;
state
->
flags
=
0
;
memset
(
state
->
stateid
.
data
,
0
,
sizeof
(
state
->
stateid
.
data
));
memset
(
state
->
stateid
.
data
,
0
,
sizeof
(
state
->
stateid
.
data
));
atomic_set
(
&
state
->
count
,
1
);
atomic_set
(
&
state
->
count
,
1
);
INIT_LIST_HEAD
(
&
state
->
lock_states
);
init_MUTEX
(
&
state
->
lock_sema
);
rwlock_init
(
&
state
->
state_lock
);
return
state
;
return
state
;
}
}
...
@@ -478,6 +483,171 @@ nfs4_close_state(struct nfs4_state *state, mode_t mode)
...
@@ -478,6 +483,171 @@ nfs4_close_state(struct nfs4_state *state, mode_t mode)
nfs4_put_open_state
(
state
);
nfs4_put_open_state
(
state
);
}
}
/*
* Search the state->lock_states for an existing lock_owner
* that is compatible with current->files
*/
static
struct
nfs4_lock_state
*
__nfs4_find_lock_state
(
struct
nfs4_state
*
state
,
fl_owner_t
fl_owner
)
{
struct
nfs4_lock_state
*
pos
;
list_for_each_entry
(
pos
,
&
state
->
lock_states
,
ls_locks
)
{
if
(
pos
->
ls_owner
!=
fl_owner
)
continue
;
atomic_inc
(
&
pos
->
ls_count
);
return
pos
;
}
return
NULL
;
}
struct
nfs4_lock_state
*
nfs4_find_lock_state
(
struct
nfs4_state
*
state
,
fl_owner_t
fl_owner
)
{
struct
nfs4_lock_state
*
lsp
;
read_lock
(
&
state
->
state_lock
);
lsp
=
__nfs4_find_lock_state
(
state
,
fl_owner
);
read_unlock
(
&
state
->
state_lock
);
return
lsp
;
}
/*
* Return a compatible lock_state. If no initialized lock_state structure
* exists, return an uninitialized one.
*
* The caller must be holding state->lock_sema
*/
struct
nfs4_lock_state
*
nfs4_alloc_lock_state
(
struct
nfs4_state
*
state
,
fl_owner_t
fl_owner
)
{
struct
nfs4_lock_state
*
lsp
;
struct
nfs4_client
*
clp
=
state
->
owner
->
so_client
;
lsp
=
kmalloc
(
sizeof
(
*
lsp
),
GFP_KERNEL
);
if
(
lsp
==
NULL
)
return
NULL
;
lsp
->
ls_seqid
=
0
;
/* arbitrary */
lsp
->
ls_id
=
-
1
;
memset
(
lsp
->
ls_stateid
.
data
,
0
,
sizeof
(
lsp
->
ls_stateid
.
data
));
atomic_set
(
&
lsp
->
ls_count
,
1
);
lsp
->
ls_owner
=
fl_owner
;
lsp
->
ls_parent
=
state
;
INIT_LIST_HEAD
(
&
lsp
->
ls_locks
);
spin_lock
(
&
clp
->
cl_lock
);
lsp
->
ls_id
=
nfs4_alloc_lockowner_id
(
clp
);
spin_unlock
(
&
clp
->
cl_lock
);
return
lsp
;
}
/*
* Byte-range lock aware utility to initialize the stateid of read/write
* requests.
*/
void
nfs4_copy_stateid
(
nfs4_stateid
*
dst
,
struct
nfs4_state
*
state
,
fl_owner_t
fl_owner
)
{
if
(
test_bit
(
LK_STATE_IN_USE
,
&
state
->
flags
))
{
struct
nfs4_lock_state
*
lsp
;
lsp
=
nfs4_find_lock_state
(
state
,
fl_owner
);
if
(
lsp
)
{
memcpy
(
dst
,
&
lsp
->
ls_stateid
,
sizeof
(
*
dst
));
nfs4_put_lock_state
(
lsp
);
return
;
}
}
memcpy
(
dst
,
&
state
->
stateid
,
sizeof
(
*
dst
));
}
/*
* Called with state->lock_sema held.
*/
void
nfs4_increment_lock_seqid
(
int
status
,
struct
nfs4_lock_state
*
lsp
)
{
if
(
status
==
NFS_OK
||
seqid_mutating_err
(
-
status
))
lsp
->
ls_seqid
++
;
}
/*
* Check to see if the request lock (type FL_UNLK) effects the fl lock.
*
* fl and request must have the same posix owner
*
* return:
* 0 -> fl not effected by request
* 1 -> fl consumed by request
*/
static
int
nfs4_check_unlock
(
struct
file_lock
*
fl
,
struct
file_lock
*
request
)
{
if
(
fl
->
fl_start
>=
request
->
fl_start
&&
fl
->
fl_end
<=
request
->
fl_end
)
return
1
;
return
0
;
}
/*
* Post an initialized lock_state on the state->lock_states list.
*/
void
nfs4_notify_setlk
(
struct
inode
*
inode
,
struct
file_lock
*
request
,
struct
nfs4_lock_state
*
lsp
)
{
struct
nfs4_state
*
state
=
lsp
->
ls_parent
;
if
(
!
list_empty
(
&
lsp
->
ls_locks
))
return
;
write_lock
(
&
state
->
state_lock
);
list_add
(
&
lsp
->
ls_locks
,
&
state
->
lock_states
);
set_bit
(
LK_STATE_IN_USE
,
&
state
->
flags
);
write_unlock
(
&
state
->
state_lock
);
}
/*
* to decide to 'reap' lock state:
* 1) search i_flock for file_locks with fl.lock_state = to ls.
* 2) determine if unlock will consume found lock.
* if so, reap
*
* else, don't reap.
*
*/
void
nfs4_notify_unlck
(
struct
inode
*
inode
,
struct
file_lock
*
request
,
struct
nfs4_lock_state
*
lsp
)
{
struct
nfs4_state
*
state
=
lsp
->
ls_parent
;
struct
file_lock
*
fl
;
for
(
fl
=
inode
->
i_flock
;
fl
!=
NULL
;
fl
=
fl
->
fl_next
)
{
if
(
!
(
fl
->
fl_flags
&
FL_POSIX
))
continue
;
if
(
fl
->
fl_owner
!=
lsp
->
ls_owner
)
continue
;
/* Exit if we find at least one lock which is not consumed */
if
(
nfs4_check_unlock
(
fl
,
request
)
==
0
)
return
;
}
write_lock
(
&
state
->
state_lock
);
list_del_init
(
&
lsp
->
ls_locks
);
if
(
list_empty
(
&
state
->
lock_states
))
clear_bit
(
LK_STATE_IN_USE
,
&
state
->
flags
);
write_unlock
(
&
state
->
state_lock
);
}
/*
* Release reference to lock_state, and free it if we see that
* it is no longer in use
*/
void
nfs4_put_lock_state
(
struct
nfs4_lock_state
*
lsp
)
{
if
(
!
atomic_dec_and_test
(
&
lsp
->
ls_count
))
return
;
if
(
!
list_empty
(
&
lsp
->
ls_locks
))
return
;
kfree
(
lsp
);
}
/*
/*
* Called with sp->so_sema held.
* Called with sp->so_sema held.
*
*
...
...
fs/nfs/nfs4xdr.c
View file @
3f1990d3
...
@@ -66,6 +66,10 @@ static int nfs_stat_to_errno(int);
...
@@ -66,6 +66,10 @@ static int nfs_stat_to_errno(int);
#define NFS4_MAXTAGLEN 0
#define NFS4_MAXTAGLEN 0
#endif
#endif
/* lock,open owner id:
* we currently use size 1 (u32) out of (NFS4_OPAQUE_LIMIT >> 2)
*/
#define owner_id_maxsz 1 + 1
#define compound_encode_hdr_maxsz 3 + (NFS4_MAXTAGLEN >> 2)
#define compound_encode_hdr_maxsz 3 + (NFS4_MAXTAGLEN >> 2)
#define compound_decode_hdr_maxsz 2 + (NFS4_MAXTAGLEN >> 2)
#define compound_decode_hdr_maxsz 2 + (NFS4_MAXTAGLEN >> 2)
#define op_encode_hdr_maxsz 1
#define op_encode_hdr_maxsz 1
...
@@ -222,6 +226,36 @@ static int nfs_stat_to_errno(int);
...
@@ -222,6 +226,36 @@ static int nfs_stat_to_errno(int);
decode_setclientid_confirm_maxsz + \
decode_setclientid_confirm_maxsz + \
decode_putrootfh_maxsz + \
decode_putrootfh_maxsz + \
decode_fsinfo_maxsz
decode_fsinfo_maxsz
#define NFS4_enc_lock_sz compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
encode_getattr_maxsz + \
op_encode_hdr_maxsz + \
1 + 1 + 2 + 2 + \
1 + 4 + 1 + 2 + \
owner_id_maxsz
#define NFS4_dec_lock_sz compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
decode_getattr_maxsz + \
op_decode_hdr_maxsz + \
2 + 2 + 1 + 2 + \
owner_id_maxsz
#define NFS4_enc_lockt_sz compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
encode_getattr_maxsz + \
op_encode_hdr_maxsz + \
1 + 2 + 2 + 2 + \
owner_id_maxsz
#define NFS4_dec_lockt_sz NFS4_dec_lock_sz
#define NFS4_enc_locku_sz compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
encode_getattr_maxsz + \
op_encode_hdr_maxsz + \
1 + 1 + 4 + 2 + 2
#define NFS4_dec_locku_sz compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
decode_getattr_maxsz + \
op_decode_hdr_maxsz + 4
static
struct
{
static
struct
{
...
@@ -596,6 +630,80 @@ encode_link(struct xdr_stream *xdr, struct nfs4_link *link)
...
@@ -596,6 +630,80 @@ encode_link(struct xdr_stream *xdr, struct nfs4_link *link)
return
0
;
return
0
;
}
}
/*
* 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
,
struct
nfs_lockargs
*
arg
)
{
uint32_t
*
p
;
struct
nfs_lock_opargs
*
opargs
=
arg
->
u
.
lock
;
RESERVE_SPACE
(
32
);
WRITE32
(
OP_LOCK
);
WRITE32
(
arg
->
type
);
WRITE32
(
opargs
->
reclaim
);
WRITE64
(
arg
->
offset
);
WRITE64
(
arg
->
length
);
WRITE32
(
opargs
->
new_lock_owner
);
if
(
opargs
->
new_lock_owner
){
struct
nfs_open_to_lock
*
ol
=
opargs
->
u
.
open_lock
;
RESERVE_SPACE
(
40
);
WRITE32
(
ol
->
open_seqid
);
WRITEMEM
(
&
ol
->
open_stateid
,
sizeof
(
ol
->
open_stateid
));
WRITE32
(
ol
->
lock_seqid
);
WRITE64
(
ol
->
lock_owner
.
clientid
);
WRITE32
(
4
);
WRITE32
(
ol
->
lock_owner
.
id
);
}
else
{
struct
nfs_exist_lock
*
el
=
opargs
->
u
.
exist_lock
;
RESERVE_SPACE
(
20
);
WRITEMEM
(
&
el
->
stateid
,
sizeof
(
el
->
stateid
));
WRITE32
(
el
->
seqid
);
}
return
0
;
}
static
int
encode_lockt
(
struct
xdr_stream
*
xdr
,
struct
nfs_lockargs
*
arg
)
{
uint32_t
*
p
;
struct
nfs_lowner
*
opargs
=
arg
->
u
.
lockt
;
RESERVE_SPACE
(
40
);
WRITE32
(
OP_LOCKT
);
WRITE32
(
arg
->
type
);
WRITE64
(
arg
->
offset
);
WRITE64
(
arg
->
length
);
WRITE64
(
opargs
->
clientid
);
WRITE32
(
4
);
WRITE32
(
opargs
->
id
);
return
0
;
}
static
int
encode_locku
(
struct
xdr_stream
*
xdr
,
struct
nfs_lockargs
*
arg
)
{
uint32_t
*
p
;
struct
nfs_locku_opargs
*
opargs
=
arg
->
u
.
locku
;
RESERVE_SPACE
(
44
);
WRITE32
(
OP_LOCKU
);
WRITE32
(
arg
->
type
);
WRITE32
(
opargs
->
seqid
);
WRITEMEM
(
&
opargs
->
stateid
,
sizeof
(
opargs
->
stateid
));
WRITE64
(
arg
->
offset
);
WRITE64
(
arg
->
length
);
return
0
;
}
static
int
static
int
encode_lookup
(
struct
xdr_stream
*
xdr
,
struct
nfs4_lookup
*
lookup
)
encode_lookup
(
struct
xdr_stream
*
xdr
,
struct
nfs4_lookup
*
lookup
)
{
{
...
@@ -1175,6 +1283,72 @@ nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, uint32_t *p, struct nfs_closea
...
@@ -1175,6 +1283,72 @@ nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, uint32_t *p, struct nfs_closea
return
status
;
return
status
;
}
}
/*
* Encode a LOCK request
*/
static
int
nfs4_xdr_enc_lock
(
struct
rpc_rqst
*
req
,
uint32_t
*
p
,
struct
nfs_lockargs
*
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_lock
(
&
xdr
,
args
);
out:
return
status
;
}
/*
* Encode a LOCKT request
*/
static
int
nfs4_xdr_enc_lockt
(
struct
rpc_rqst
*
req
,
uint32_t
*
p
,
struct
nfs_lockargs
*
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_lockt
(
&
xdr
,
args
);
out:
return
status
;
}
/*
* Encode a LOCKU request
*/
static
int
nfs4_xdr_enc_locku
(
struct
rpc_rqst
*
req
,
uint32_t
*
p
,
struct
nfs_lockargs
*
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_locku
(
&
xdr
,
args
);
out:
return
status
;
}
/*
/*
* Encode a READ request
* Encode a READ request
*/
*/
...
@@ -1997,6 +2171,66 @@ decode_link(struct xdr_stream *xdr, struct nfs4_link *link)
...
@@ -1997,6 +2171,66 @@ decode_link(struct xdr_stream *xdr, struct nfs4_link *link)
return
decode_change_info
(
xdr
,
link
->
ln_cinfo
);
return
decode_change_info
(
xdr
,
link
->
ln_cinfo
);
}
}
/*
* We create the owner, so we know a proper owner.id length is 4.
*/
static
int
decode_lock_denied
(
struct
xdr_stream
*
xdr
,
struct
nfs_lock_denied
*
denied
)
{
uint32_t
*
p
;
uint32_t
namelen
;
READ_BUF
(
32
);
READ64
(
denied
->
offset
);
READ64
(
denied
->
length
);
READ32
(
denied
->
type
);
READ64
(
denied
->
owner
.
clientid
);
READ32
(
namelen
);
READ_BUF
(
namelen
);
if
(
namelen
==
4
)
READ32
(
denied
->
owner
.
id
);
return
-
NFS4ERR_DENIED
;
}
static
int
decode_lock
(
struct
xdr_stream
*
xdr
,
struct
nfs_lockres
*
res
)
{
uint32_t
*
p
;
int
status
;
status
=
decode_op_hdr
(
xdr
,
OP_LOCK
);
if
(
status
==
0
)
{
READ_BUF
(
sizeof
(
nfs4_stateid
));
COPYMEM
(
&
res
->
u
.
stateid
,
sizeof
(
res
->
u
.
stateid
));
}
else
if
(
status
==
-
NFS4ERR_DENIED
)
return
decode_lock_denied
(
xdr
,
&
res
->
u
.
denied
);
return
status
;
}
static
int
decode_lockt
(
struct
xdr_stream
*
xdr
,
struct
nfs_lockres
*
res
)
{
int
status
;
status
=
decode_op_hdr
(
xdr
,
OP_LOCKT
);
if
(
status
==
-
NFS4ERR_DENIED
)
return
decode_lock_denied
(
xdr
,
&
res
->
u
.
denied
);
return
status
;
}
static
int
decode_locku
(
struct
xdr_stream
*
xdr
,
struct
nfs_lockres
*
res
)
{
uint32_t
*
p
;
int
status
;
status
=
decode_op_hdr
(
xdr
,
OP_LOCKU
);
if
(
status
==
0
)
{
READ_BUF
(
sizeof
(
nfs4_stateid
));
COPYMEM
(
&
res
->
u
.
stateid
,
sizeof
(
res
->
u
.
stateid
));
}
return
status
;
}
static
int
static
int
decode_lookup
(
struct
xdr_stream
*
xdr
)
decode_lookup
(
struct
xdr_stream
*
xdr
)
{
{
...
@@ -2037,10 +2271,11 @@ static int
...
@@ -2037,10 +2271,11 @@ static int
decode_open_confirm
(
struct
xdr_stream
*
xdr
,
struct
nfs_open_confirmres
*
res
)
decode_open_confirm
(
struct
xdr_stream
*
xdr
,
struct
nfs_open_confirmres
*
res
)
{
{
uint32_t
*
p
;
uint32_t
*
p
;
int
status
;
res
->
status
=
decode_op_hdr
(
xdr
,
OP_OPEN_CONFIRM
);
status
=
decode_op_hdr
(
xdr
,
OP_OPEN_CONFIRM
);
if
(
res
->
status
)
if
(
status
)
return
res
->
status
;
return
status
;
READ_BUF
(
sizeof
(
res
->
stateid
.
data
));
READ_BUF
(
sizeof
(
res
->
stateid
.
data
));
COPYMEM
(
res
->
stateid
.
data
,
sizeof
(
res
->
stateid
.
data
));
COPYMEM
(
res
->
stateid
.
data
,
sizeof
(
res
->
stateid
.
data
));
return
0
;
return
0
;
...
@@ -2619,6 +2854,71 @@ nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_setattrres
...
@@ -2619,6 +2854,71 @@ nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_setattrres
return
status
;
return
status
;
}
}
/*
* Decode LOCK response
*/
static
int
nfs4_xdr_dec_lock
(
struct
rpc_rqst
*
rqstp
,
uint32_t
*
p
,
struct
nfs_lockres
*
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_lock
(
&
xdr
,
res
);
out:
return
status
;
}
/*
* Decode LOCKT response
*/
static
int
nfs4_xdr_dec_lockt
(
struct
rpc_rqst
*
rqstp
,
uint32_t
*
p
,
struct
nfs_lockres
*
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_lockt
(
&
xdr
,
res
);
out:
return
status
;
}
/*
* Decode LOCKU response
*/
static
int
nfs4_xdr_dec_locku
(
struct
rpc_rqst
*
rqstp
,
uint32_t
*
p
,
struct
nfs_lockres
*
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_locku
(
&
xdr
,
res
);
out:
return
status
;
}
/*
/*
* Decode Read response
* Decode Read response
...
@@ -2915,6 +3215,9 @@ struct rpc_procinfo nfs4_procedures[] = {
...
@@ -2915,6 +3215,9 @@ struct rpc_procinfo nfs4_procedures[] = {
PROC
(
RENEW
,
enc_renew
,
dec_renew
),
PROC
(
RENEW
,
enc_renew
,
dec_renew
),
PROC
(
SETCLIENTID
,
enc_setclientid
,
dec_setclientid
),
PROC
(
SETCLIENTID
,
enc_setclientid
,
dec_setclientid
),
PROC
(
SETCLIENTID_CONFIRM
,
enc_setclientid_confirm
,
dec_setclientid_confirm
),
PROC
(
SETCLIENTID_CONFIRM
,
enc_setclientid_confirm
,
dec_setclientid_confirm
),
PROC
(
LOCK
,
enc_lock
,
dec_lock
),
PROC
(
LOCKT
,
enc_lockt
,
dec_lockt
),
PROC
(
LOCKU
,
enc_locku
,
dec_locku
),
};
};
struct
rpc_version
nfs_version4
=
{
struct
rpc_version
nfs_version4
=
{
...
...
fs/nfs/proc.c
View file @
3f1990d3
...
@@ -42,6 +42,7 @@
...
@@ -42,6 +42,7 @@
#include <linux/nfs2.h>
#include <linux/nfs2.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_page.h>
#include <linux/nfs_page.h>
#include <linux/lockd/bind.h>
#include <linux/smp_lock.h>
#include <linux/smp_lock.h>
#define NFSDBG_FACILITY NFSDBG_PROC
#define NFSDBG_FACILITY NFSDBG_PROC
...
@@ -653,6 +654,12 @@ nfs_request_compatible(struct nfs_page *req, struct file *filp, struct page *pag
...
@@ -653,6 +654,12 @@ nfs_request_compatible(struct nfs_page *req, struct file *filp, struct page *pag
return
1
;
return
1
;
}
}
static
int
nfs_proc_lock
(
struct
file
*
filp
,
int
cmd
,
struct
file_lock
*
fl
)
{
return
nlmclnt_proc
(
filp
->
f_dentry
->
d_inode
,
cmd
,
fl
);
}
struct
nfs_rpc_ops
nfs_v2_clientops
=
{
struct
nfs_rpc_ops
nfs_v2_clientops
=
{
.
version
=
2
,
/* protocol version */
.
version
=
2
,
/* protocol version */
...
@@ -689,4 +696,5 @@ struct nfs_rpc_ops nfs_v2_clientops = {
...
@@ -689,4 +696,5 @@ struct nfs_rpc_ops nfs_v2_clientops = {
.
file_release
=
nfs_release
,
.
file_release
=
nfs_release
,
.
request_init
=
nfs_request_init
,
.
request_init
=
nfs_request_init
,
.
request_compatible
=
nfs_request_compatible
,
.
request_compatible
=
nfs_request_compatible
,
.
lock
=
nfs_proc_lock
,
};
};
include/linux/nfs4.h
View file @
3f1990d3
...
@@ -297,6 +297,9 @@ enum {
...
@@ -297,6 +297,9 @@ enum {
NFSPROC4_CLNT_RENEW
,
NFSPROC4_CLNT_RENEW
,
NFSPROC4_CLNT_SETCLIENTID
,
NFSPROC4_CLNT_SETCLIENTID
,
NFSPROC4_CLNT_SETCLIENTID_CONFIRM
,
NFSPROC4_CLNT_SETCLIENTID_CONFIRM
,
NFSPROC4_CLNT_LOCK
,
NFSPROC4_CLNT_LOCKT
,
NFSPROC4_CLNT_LOCKU
,
};
};
#endif
#endif
...
...
include/linux/nfs_fs.h
View file @
3f1990d3
...
@@ -542,19 +542,43 @@ struct nfs4_state_owner {
...
@@ -542,19 +542,43 @@ struct nfs4_state_owner {
/*
/*
* struct nfs4_state maintains the client-side state for a given
* struct nfs4_state maintains the client-side state for a given
* (state_owner,inode) tuple.
* (state_owner,inode) tuple
(OPEN) or state_owner (LOCK)
.
*
*
* OPEN:
* In order to know when to OPEN_DOWNGRADE or CLOSE the state on the server,
* In order to know when to OPEN_DOWNGRADE or CLOSE the state on the server,
* we need to know how many files are open for reading or writing on a
* we need to know how many files are open for reading or writing on a
* given inode. This information too is stored here.
* given inode. This information too is stored here.
*
* LOCK: one nfs4_state (LOCK) to hold the lock stateid nfs4_state(OPEN)
*/
*/
struct
nfs4_lock_state
{
struct
list_head
ls_locks
;
/* Other lock stateids */
fl_owner_t
ls_owner
;
/* POSIX lock owner */
struct
nfs4_state
*
ls_parent
;
/* Parent nfs4_state */
u32
ls_seqid
;
u32
ls_id
;
nfs4_stateid
ls_stateid
;
atomic_t
ls_count
;
};
/* bits for nfs4_state->flags */
enum
{
LK_STATE_IN_USE
,
};
struct
nfs4_state
{
struct
nfs4_state
{
struct
list_head
open_states
;
/* List of states for the same state_owner */
struct
list_head
open_states
;
/* List of states for the same state_owner */
struct
list_head
inode_states
;
/* List of states for the same inode */
struct
list_head
inode_states
;
/* List of states for the same inode */
struct
list_head
lock_states
;
/* List of subservient lock stateids */
struct
nfs4_state_owner
*
owner
;
/* Pointer to the open owner */
struct
nfs4_state_owner
*
owner
;
/* Pointer to the open owner */
struct
inode
*
inode
;
/* Pointer to the inode */
struct
inode
*
inode
;
/* Pointer to the inode */
unsigned
long
flags
;
/* Do we hold any locks? */
struct
semaphore
lock_sema
;
/* Serializes file locking operations */
rwlock_t
state_lock
;
/* Protects the lock_states list */
nfs4_stateid
stateid
;
nfs4_stateid
stateid
;
unsigned
int
nreaders
;
unsigned
int
nreaders
;
...
@@ -589,6 +613,8 @@ extern void init_nfsv4_state(struct nfs_server *);
...
@@ -589,6 +613,8 @@ extern void init_nfsv4_state(struct nfs_server *);
extern
void
destroy_nfsv4_state
(
struct
nfs_server
*
);
extern
void
destroy_nfsv4_state
(
struct
nfs_server
*
);
extern
struct
nfs4_client
*
nfs4_get_client
(
struct
in_addr
*
);
extern
struct
nfs4_client
*
nfs4_get_client
(
struct
in_addr
*
);
extern
void
nfs4_put_client
(
struct
nfs4_client
*
clp
);
extern
void
nfs4_put_client
(
struct
nfs4_client
*
clp
);
extern
u32
nfs4_alloc_lockowner_id
(
struct
nfs4_client
*
);
extern
struct
nfs4_state_owner
*
nfs4_get_state_owner
(
struct
nfs_server
*
,
struct
rpc_cred
*
);
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
void
nfs4_put_state_owner
(
struct
nfs4_state_owner
*
);
extern
struct
nfs4_state
*
nfs4_get_open_state
(
struct
inode
*
,
struct
nfs4_state_owner
*
);
extern
struct
nfs4_state
*
nfs4_get_open_state
(
struct
inode
*
,
struct
nfs4_state_owner
*
);
...
@@ -598,6 +624,15 @@ extern struct nfs4_state *nfs4_find_state(struct inode *, struct rpc_cred *, mod
...
@@ -598,6 +624,15 @@ extern struct nfs4_state *nfs4_find_state(struct inode *, struct rpc_cred *, mod
extern
void
nfs4_increment_seqid
(
int
status
,
struct
nfs4_state_owner
*
sp
);
extern
void
nfs4_increment_seqid
(
int
status
,
struct
nfs4_state_owner
*
sp
);
extern
int
nfs4_handle_error
(
struct
nfs_server
*
,
int
);
extern
int
nfs4_handle_error
(
struct
nfs_server
*
,
int
);
extern
void
nfs4_schedule_state_recovery
(
struct
nfs4_client
*
);
extern
void
nfs4_schedule_state_recovery
(
struct
nfs4_client
*
);
extern
struct
nfs4_lock_state
*
nfs4_find_lock_state
(
struct
nfs4_state
*
state
,
fl_owner_t
);
extern
struct
nfs4_lock_state
*
nfs4_alloc_lock_state
(
struct
nfs4_state
*
state
,
fl_owner_t
);
extern
void
nfs4_put_lock_state
(
struct
nfs4_lock_state
*
state
);
extern
void
nfs4_increment_lock_seqid
(
int
status
,
struct
nfs4_lock_state
*
ls
);
extern
void
nfs4_notify_setlk
(
struct
inode
*
,
struct
file_lock
*
,
struct
nfs4_lock_state
*
);
extern
void
nfs4_notify_unlck
(
struct
inode
*
,
struct
file_lock
*
,
struct
nfs4_lock_state
*
);
extern
void
nfs4_copy_stateid
(
nfs4_stateid
*
,
struct
nfs4_state
*
,
fl_owner_t
);
struct
nfs4_mount_data
;
struct
nfs4_mount_data
;
#else
#else
...
...
include/linux/nfs_page.h
View file @
3f1990d3
...
@@ -26,6 +26,7 @@ struct nfs_page {
...
@@ -26,6 +26,7 @@ struct nfs_page {
struct
list_head
wb_list
,
/* Defines state of page: */
struct
list_head
wb_list
,
/* Defines state of page: */
*
wb_list_head
;
/* read/write/commit */
*
wb_list_head
;
/* read/write/commit */
struct
file
*
wb_file
;
struct
file
*
wb_file
;
fl_owner_t
wb_lockowner
;
struct
inode
*
wb_inode
;
struct
inode
*
wb_inode
;
struct
rpc_cred
*
wb_cred
;
struct
rpc_cred
*
wb_cred
;
struct
nfs4_state
*
wb_state
;
struct
nfs4_state
*
wb_state
;
...
...
include/linux/nfs_xdr.h
View file @
3f1990d3
...
@@ -109,7 +109,6 @@ struct nfs_openargs {
...
@@ -109,7 +109,6 @@ struct nfs_openargs {
};
};
struct
nfs_openres
{
struct
nfs_openres
{
__u32
status
;
nfs4_stateid
stateid
;
nfs4_stateid
stateid
;
struct
nfs_fh
fh
;
struct
nfs_fh
fh
;
struct
nfs4_change_info
*
cinfo
;
struct
nfs4_change_info
*
cinfo
;
...
@@ -129,7 +128,6 @@ struct nfs_open_confirmargs {
...
@@ -129,7 +128,6 @@ struct nfs_open_confirmargs {
};
};
struct
nfs_open_confirmres
{
struct
nfs_open_confirmres
{
__u32
status
;
nfs4_stateid
stateid
;
nfs4_stateid
stateid
;
};
};
...
@@ -157,10 +155,68 @@ struct nfs_closeargs {
...
@@ -157,10 +155,68 @@ struct nfs_closeargs {
};
};
struct
nfs_closeres
{
struct
nfs_closeres
{
__u32
status
;
nfs4_stateid
stateid
;
nfs4_stateid
stateid
;
};
};
/*
* * Arguments to the lock,lockt, and locku call.
* */
struct
nfs_lowner
{
__u64
clientid
;
u32
id
;
};
struct
nfs_open_to_lock
{
__u32
open_seqid
;
nfs4_stateid
open_stateid
;
__u32
lock_seqid
;
struct
nfs_lowner
lock_owner
;
};
struct
nfs_exist_lock
{
nfs4_stateid
stateid
;
__u32
seqid
;
};
struct
nfs_lock_opargs
{
__u32
reclaim
;
__u32
new_lock_owner
;
union
{
struct
nfs_open_to_lock
*
open_lock
;
struct
nfs_exist_lock
*
exist_lock
;
}
u
;
};
struct
nfs_locku_opargs
{
__u32
seqid
;
nfs4_stateid
stateid
;
};
struct
nfs_lockargs
{
struct
nfs_fh
*
fh
;
__u32
type
;
__u64
offset
;
__u64
length
;
union
{
struct
nfs_lock_opargs
*
lock
;
/* LOCK */
struct
nfs_lowner
*
lockt
;
/* LOCKT */
struct
nfs_locku_opargs
*
locku
;
/* LOCKU */
}
u
;
};
struct
nfs_lock_denied
{
__u64
offset
;
__u64
length
;
__u32
type
;
struct
nfs_lowner
owner
;
};
struct
nfs_lockres
{
union
{
nfs4_stateid
stateid
;
/* LOCK success, LOCKU */
struct
nfs_lock_denied
denied
;
/* LOCK failed, LOCKT success */
}
u
;
struct
nfs_server
*
server
;
};
/*
/*
* Arguments to the read call.
* Arguments to the read call.
...
@@ -605,6 +661,7 @@ struct nfs_read_data {
...
@@ -605,6 +661,7 @@ struct nfs_read_data {
struct
rpc_task
task
;
struct
rpc_task
task
;
struct
inode
*
inode
;
struct
inode
*
inode
;
struct
rpc_cred
*
cred
;
struct
rpc_cred
*
cred
;
fl_owner_t
lockowner
;
struct
nfs_fattr
fattr
;
/* fattr storage */
struct
nfs_fattr
fattr
;
/* fattr storage */
struct
list_head
pages
;
/* Coalesced read requests */
struct
list_head
pages
;
/* Coalesced read requests */
struct
page
*
pagevec
[
NFS_READ_MAXIOV
];
struct
page
*
pagevec
[
NFS_READ_MAXIOV
];
...
@@ -620,6 +677,7 @@ struct nfs_write_data {
...
@@ -620,6 +677,7 @@ struct nfs_write_data {
struct
rpc_task
task
;
struct
rpc_task
task
;
struct
inode
*
inode
;
struct
inode
*
inode
;
struct
rpc_cred
*
cred
;
struct
rpc_cred
*
cred
;
fl_owner_t
lockowner
;
struct
nfs_fattr
fattr
;
struct
nfs_fattr
fattr
;
struct
nfs_writeverf
verf
;
struct
nfs_writeverf
verf
;
struct
list_head
pages
;
/* Coalesced requests we wish to flush */
struct
list_head
pages
;
/* Coalesced requests we wish to flush */
...
@@ -686,6 +744,7 @@ struct nfs_rpc_ops {
...
@@ -686,6 +744,7 @@ struct nfs_rpc_ops {
int
(
*
file_release
)
(
struct
inode
*
,
struct
file
*
);
int
(
*
file_release
)
(
struct
inode
*
,
struct
file
*
);
void
(
*
request_init
)(
struct
nfs_page
*
,
struct
file
*
);
void
(
*
request_init
)(
struct
nfs_page
*
,
struct
file
*
);
int
(
*
request_compatible
)(
struct
nfs_page
*
,
struct
file
*
,
struct
page
*
);
int
(
*
request_compatible
)(
struct
nfs_page
*
,
struct
file
*
,
struct
page
*
);
int
(
*
lock
)(
struct
file
*
,
int
,
struct
file_lock
*
);
};
};
/*
/*
...
...
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