Merge branch 'for-linus' of git://linux-nfs.org/~bfields/linux

* 'for-linus' of git://linux-nfs.org/~bfields/linux:
  nfsd: don't allow setting ctime over v4
  Update to NFS/RDMA documentation
  locks: don't call ->copy_lock methods on return of conflicting locks
  lockd: unlock lockd locks held for a certain filesystem
  lockd: unlock lockd locks associated with a given server ip
  leases: remove unneeded variable from fcntl_setlease().
  leases: move lock allocation earlier in generic_setlease()
  leases: when unlocking, skip locking-related steps
  leases: fix a return-value mixup
This commit is contained in:
Linus Torvalds 2008-04-25 11:45:40 -07:00
commit cf2ec150fc
10 changed files with 162 additions and 48 deletions

View file

@ -5,7 +5,7 @@
################################################################################ ################################################################################
Author: NetApp and Open Grid Computing Author: NetApp and Open Grid Computing
Date: February 25, 2008 Date: April 15, 2008
Table of Contents Table of Contents
~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~
@ -197,12 +197,16 @@ NFS/RDMA Setup
- On the server system, configure the /etc/exports file and - On the server system, configure the /etc/exports file and
start the NFS/RDMA server. start the NFS/RDMA server.
Exports entries with the following format have been tested: Exports entries with the following formats have been tested:
/vol0 10.97.103.47(rw,async) 192.168.0.47(rw,async,insecure,no_root_squash) /vol0 192.168.0.47(fsid=0,rw,async,insecure,no_root_squash)
/vol0 192.168.0.0/255.255.255.0(fsid=0,rw,async,insecure,no_root_squash)
Here the first IP address is the client's Ethernet address and the second The IP address(es) is(are) the client's IPoIB address for an InfiniBand HCA or the
IP address is the clients IPoIB address. cleint's iWARP address(es) for an RNIC.
NOTE: The "insecure" option must be used because the NFS/RDMA client does not
use a reserved port.
Each time a machine boots: Each time a machine boots:

View file

@ -632,7 +632,7 @@ nlmsvc_update_deferred_block(struct nlm_block *block, struct file_lock *conf,
block->b_flags |= B_TIMED_OUT; block->b_flags |= B_TIMED_OUT;
if (conf) { if (conf) {
if (block->b_fl) if (block->b_fl)
locks_copy_lock(block->b_fl, conf); __locks_copy_lock(block->b_fl, conf);
} }
} }

View file

@ -18,6 +18,8 @@
#include <linux/lockd/lockd.h> #include <linux/lockd/lockd.h>
#include <linux/lockd/share.h> #include <linux/lockd/share.h>
#include <linux/lockd/sm_inter.h> #include <linux/lockd/sm_inter.h>
#include <linux/module.h>
#include <linux/mount.h>
#define NLMDBG_FACILITY NLMDBG_SVCSUBS #define NLMDBG_FACILITY NLMDBG_SVCSUBS
@ -194,6 +196,12 @@ nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file,
return 0; return 0;
} }
static int
nlmsvc_always_match(void *dummy1, struct nlm_host *dummy2)
{
return 1;
}
/* /*
* Inspect a single file * Inspect a single file
*/ */
@ -230,7 +238,8 @@ nlm_file_inuse(struct nlm_file *file)
* Loop over all files in the file table. * Loop over all files in the file table.
*/ */
static int static int
nlm_traverse_files(struct nlm_host *host, nlm_host_match_fn_t match) nlm_traverse_files(void *data, nlm_host_match_fn_t match,
int (*is_failover_file)(void *data, struct nlm_file *file))
{ {
struct hlist_node *pos, *next; struct hlist_node *pos, *next;
struct nlm_file *file; struct nlm_file *file;
@ -239,12 +248,14 @@ nlm_traverse_files(struct nlm_host *host, nlm_host_match_fn_t match)
mutex_lock(&nlm_file_mutex); mutex_lock(&nlm_file_mutex);
for (i = 0; i < FILE_NRHASH; i++) { for (i = 0; i < FILE_NRHASH; i++) {
hlist_for_each_entry_safe(file, pos, next, &nlm_files[i], f_list) { hlist_for_each_entry_safe(file, pos, next, &nlm_files[i], f_list) {
if (is_failover_file && !is_failover_file(data, file))
continue;
file->f_count++; file->f_count++;
mutex_unlock(&nlm_file_mutex); mutex_unlock(&nlm_file_mutex);
/* Traverse locks, blocks and shares of this file /* Traverse locks, blocks and shares of this file
* and update file->f_locks count */ * and update file->f_locks count */
if (nlm_inspect_file(host, file, match)) if (nlm_inspect_file(data, file, match))
ret = 1; ret = 1;
mutex_lock(&nlm_file_mutex); mutex_lock(&nlm_file_mutex);
@ -303,21 +314,27 @@ nlm_release_file(struct nlm_file *file)
* Used by nlmsvc_invalidate_all * Used by nlmsvc_invalidate_all
*/ */
static int static int
nlmsvc_mark_host(struct nlm_host *host, struct nlm_host *dummy) nlmsvc_mark_host(void *data, struct nlm_host *dummy)
{ {
struct nlm_host *host = data;
host->h_inuse = 1; host->h_inuse = 1;
return 0; return 0;
} }
static int static int
nlmsvc_same_host(struct nlm_host *host, struct nlm_host *other) nlmsvc_same_host(void *data, struct nlm_host *other)
{ {
struct nlm_host *host = data;
return host == other; return host == other;
} }
static int static int
nlmsvc_is_client(struct nlm_host *host, struct nlm_host *dummy) nlmsvc_is_client(void *data, struct nlm_host *dummy)
{ {
struct nlm_host *host = data;
if (host->h_server) { if (host->h_server) {
/* we are destroying locks even though the client /* we are destroying locks even though the client
* hasn't asked us too, so don't unmonitor the * hasn't asked us too, so don't unmonitor the
@ -337,7 +354,7 @@ void
nlmsvc_mark_resources(void) nlmsvc_mark_resources(void)
{ {
dprintk("lockd: nlmsvc_mark_resources\n"); dprintk("lockd: nlmsvc_mark_resources\n");
nlm_traverse_files(NULL, nlmsvc_mark_host); nlm_traverse_files(NULL, nlmsvc_mark_host, NULL);
} }
/* /*
@ -348,7 +365,7 @@ nlmsvc_free_host_resources(struct nlm_host *host)
{ {
dprintk("lockd: nlmsvc_free_host_resources\n"); dprintk("lockd: nlmsvc_free_host_resources\n");
if (nlm_traverse_files(host, nlmsvc_same_host)) { if (nlm_traverse_files(host, nlmsvc_same_host, NULL)) {
printk(KERN_WARNING printk(KERN_WARNING
"lockd: couldn't remove all locks held by %s\n", "lockd: couldn't remove all locks held by %s\n",
host->h_name); host->h_name);
@ -368,5 +385,41 @@ nlmsvc_invalidate_all(void)
* turn, which is about as inefficient as it gets. * turn, which is about as inefficient as it gets.
* Now we just do it once in nlm_traverse_files. * Now we just do it once in nlm_traverse_files.
*/ */
nlm_traverse_files(NULL, nlmsvc_is_client); nlm_traverse_files(NULL, nlmsvc_is_client, NULL);
} }
static int
nlmsvc_match_sb(void *datap, struct nlm_file *file)
{
struct super_block *sb = datap;
return sb == file->f_file->f_path.mnt->mnt_sb;
}
int
nlmsvc_unlock_all_by_sb(struct super_block *sb)
{
int ret;
ret = nlm_traverse_files(sb, nlmsvc_always_match, nlmsvc_match_sb);
return ret ? -EIO : 0;
}
EXPORT_SYMBOL_GPL(nlmsvc_unlock_all_by_sb);
static int
nlmsvc_match_ip(void *datap, struct nlm_host *host)
{
__be32 *server_addr = datap;
return host->h_saddr.sin_addr.s_addr == *server_addr;
}
int
nlmsvc_unlock_all_by_ip(__be32 server_addr)
{
int ret;
ret = nlm_traverse_files(&server_addr, nlmsvc_match_ip, NULL);
return ret ? -EIO : 0;
}
EXPORT_SYMBOL_GPL(nlmsvc_unlock_all_by_ip);

View file

@ -224,7 +224,7 @@ static void locks_copy_private(struct file_lock *new, struct file_lock *fl)
/* /*
* Initialize a new lock from an existing file_lock structure. * Initialize a new lock from an existing file_lock structure.
*/ */
static void __locks_copy_lock(struct file_lock *new, const struct file_lock *fl) void __locks_copy_lock(struct file_lock *new, const struct file_lock *fl)
{ {
new->fl_owner = fl->fl_owner; new->fl_owner = fl->fl_owner;
new->fl_pid = fl->fl_pid; new->fl_pid = fl->fl_pid;
@ -833,7 +833,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
if (!posix_locks_conflict(request, fl)) if (!posix_locks_conflict(request, fl))
continue; continue;
if (conflock) if (conflock)
locks_copy_lock(conflock, fl); __locks_copy_lock(conflock, fl);
error = -EAGAIN; error = -EAGAIN;
if (!(request->fl_flags & FL_SLEEP)) if (!(request->fl_flags & FL_SLEEP))
goto out; goto out;
@ -1367,18 +1367,20 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
lease = *flp; lease = *flp;
error = -EAGAIN; if (arg != F_UNLCK) {
if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) error = -ENOMEM;
goto out; new_fl = locks_alloc_lock();
if ((arg == F_WRLCK) if (new_fl == NULL)
&& ((atomic_read(&dentry->d_count) > 1) goto out;
|| (atomic_read(&inode->i_count) > 1)))
goto out;
error = -ENOMEM; error = -EAGAIN;
new_fl = locks_alloc_lock(); if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0))
if (new_fl == NULL) goto out;
goto out; if ((arg == F_WRLCK)
&& ((atomic_read(&dentry->d_count) > 1)
|| (atomic_read(&inode->i_count) > 1)))
goto out;
}
/* /*
* At this point, we know that if there is an exclusive * At this point, we know that if there is an exclusive
@ -1404,6 +1406,7 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
rdlease_count++; rdlease_count++;
} }
error = -EAGAIN;
if ((arg == F_RDLCK && (wrlease_count > 0)) || if ((arg == F_RDLCK && (wrlease_count > 0)) ||
(arg == F_WRLCK && ((rdlease_count + wrlease_count) > 0))) (arg == F_WRLCK && ((rdlease_count + wrlease_count) > 0)))
goto out; goto out;
@ -1490,8 +1493,7 @@ EXPORT_SYMBOL_GPL(vfs_setlease);
int fcntl_setlease(unsigned int fd, struct file *filp, long arg) int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
{ {
struct file_lock fl, *flp = &fl; struct file_lock fl, *flp = &fl;
struct dentry *dentry = filp->f_path.dentry; struct inode *inode = filp->f_path.dentry->d_inode;
struct inode *inode = dentry->d_inode;
int error; int error;
locks_init_lock(&fl); locks_init_lock(&fl);

View file

@ -2712,9 +2712,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
* Note: locks.c uses the BKL to protect the inode's lock list. * Note: locks.c uses the BKL to protect the inode's lock list.
*/ */
/* XXX?: Just to divert the locks_release_private at the start of
* locks_copy_lock: */
locks_init_lock(&conflock);
err = vfs_lock_file(filp, cmd, &file_lock, &conflock); err = vfs_lock_file(filp, cmd, &file_lock, &conflock);
switch (-err) { switch (-err) {
case 0: /* success! */ case 0: /* success! */

View file

@ -376,20 +376,6 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *ia
goto xdr_error; goto xdr_error;
} }
} }
if (bmval[1] & FATTR4_WORD1_TIME_METADATA) {
/* We require the high 32 bits of 'seconds' to be 0, and we ignore
all 32 bits of 'nseconds'. */
READ_BUF(12);
len += 12;
READ32(dummy32);
if (dummy32)
return nfserr_inval;
READ32(iattr->ia_ctime.tv_sec);
READ32(iattr->ia_ctime.tv_nsec);
if (iattr->ia_ctime.tv_nsec >= (u32)1000000000)
return nfserr_inval;
iattr->ia_valid |= ATTR_CTIME;
}
if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) { if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) {
READ_BUF(4); READ_BUF(4);
len += 4; len += 4;

View file

@ -22,6 +22,7 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/inet.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/ctype.h> #include <linux/ctype.h>
@ -35,6 +36,7 @@
#include <linux/nfsd/cache.h> #include <linux/nfsd/cache.h>
#include <linux/nfsd/xdr.h> #include <linux/nfsd/xdr.h>
#include <linux/nfsd/syscall.h> #include <linux/nfsd/syscall.h>
#include <linux/lockd/lockd.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <net/ipv6.h> #include <net/ipv6.h>
@ -53,6 +55,8 @@ enum {
NFSD_Getfs, NFSD_Getfs,
NFSD_List, NFSD_List,
NFSD_Fh, NFSD_Fh,
NFSD_FO_UnlockIP,
NFSD_FO_UnlockFS,
NFSD_Threads, NFSD_Threads,
NFSD_Pool_Threads, NFSD_Pool_Threads,
NFSD_Versions, NFSD_Versions,
@ -89,6 +93,9 @@ static ssize_t write_leasetime(struct file *file, char *buf, size_t size);
static ssize_t write_recoverydir(struct file *file, char *buf, size_t size); static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
#endif #endif
static ssize_t failover_unlock_ip(struct file *file, char *buf, size_t size);
static ssize_t failover_unlock_fs(struct file *file, char *buf, size_t size);
static ssize_t (*write_op[])(struct file *, char *, size_t) = { static ssize_t (*write_op[])(struct file *, char *, size_t) = {
[NFSD_Svc] = write_svc, [NFSD_Svc] = write_svc,
[NFSD_Add] = write_add, [NFSD_Add] = write_add,
@ -98,6 +105,8 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = {
[NFSD_Getfd] = write_getfd, [NFSD_Getfd] = write_getfd,
[NFSD_Getfs] = write_getfs, [NFSD_Getfs] = write_getfs,
[NFSD_Fh] = write_filehandle, [NFSD_Fh] = write_filehandle,
[NFSD_FO_UnlockIP] = failover_unlock_ip,
[NFSD_FO_UnlockFS] = failover_unlock_fs,
[NFSD_Threads] = write_threads, [NFSD_Threads] = write_threads,
[NFSD_Pool_Threads] = write_pool_threads, [NFSD_Pool_Threads] = write_pool_threads,
[NFSD_Versions] = write_versions, [NFSD_Versions] = write_versions,
@ -298,6 +307,58 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size)
return err; return err;
} }
static ssize_t failover_unlock_ip(struct file *file, char *buf, size_t size)
{
__be32 server_ip;
char *fo_path, c;
int b1, b2, b3, b4;
/* sanity check */
if (size == 0)
return -EINVAL;
if (buf[size-1] != '\n')
return -EINVAL;
fo_path = buf;
if (qword_get(&buf, fo_path, size) < 0)
return -EINVAL;
/* get ipv4 address */
if (sscanf(fo_path, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4)
return -EINVAL;
server_ip = htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
return nlmsvc_unlock_all_by_ip(server_ip);
}
static ssize_t failover_unlock_fs(struct file *file, char *buf, size_t size)
{
struct nameidata nd;
char *fo_path;
int error;
/* sanity check */
if (size == 0)
return -EINVAL;
if (buf[size-1] != '\n')
return -EINVAL;
fo_path = buf;
if (qword_get(&buf, fo_path, size) < 0)
return -EINVAL;
error = path_lookup(fo_path, 0, &nd);
if (error)
return error;
error = nlmsvc_unlock_all_by_sb(nd.path.mnt->mnt_sb);
path_put(&nd.path);
return error;
}
static ssize_t write_filehandle(struct file *file, char *buf, size_t size) static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
{ {
/* request is: /* request is:
@ -700,6 +761,10 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
[NFSD_Getfd] = {".getfd", &transaction_ops, S_IWUSR|S_IRUSR}, [NFSD_Getfd] = {".getfd", &transaction_ops, S_IWUSR|S_IRUSR},
[NFSD_Getfs] = {".getfs", &transaction_ops, S_IWUSR|S_IRUSR}, [NFSD_Getfs] = {".getfs", &transaction_ops, S_IWUSR|S_IRUSR},
[NFSD_List] = {"exports", &exports_operations, S_IRUGO}, [NFSD_List] = {"exports", &exports_operations, S_IRUGO},
[NFSD_FO_UnlockIP] = {"unlock_ip",
&transaction_ops, S_IWUSR|S_IRUSR},
[NFSD_FO_UnlockFS] = {"unlock_filesystem",
&transaction_ops, S_IWUSR|S_IRUSR},
[NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR}, [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR},
[NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR}, [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR},
[NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR}, [NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR},

View file

@ -973,6 +973,7 @@ extern int do_sync_mapping_range(struct address_space *mapping, loff_t offset,
/* fs/locks.c */ /* fs/locks.c */
extern void locks_init_lock(struct file_lock *); extern void locks_init_lock(struct file_lock *);
extern void locks_copy_lock(struct file_lock *, struct file_lock *); extern void locks_copy_lock(struct file_lock *, struct file_lock *);
extern void __locks_copy_lock(struct file_lock *, const struct file_lock *);
extern void locks_remove_posix(struct file *, fl_owner_t); extern void locks_remove_posix(struct file *, fl_owner_t);
extern void locks_remove_flock(struct file *); extern void locks_remove_flock(struct file *);
extern void posix_test_lock(struct file *, struct file_lock *); extern void posix_test_lock(struct file *, struct file_lock *);

View file

@ -194,7 +194,7 @@ void nsm_release(struct nsm_handle *);
* This is used in garbage collection and resource reclaim * This is used in garbage collection and resource reclaim
* A return value != 0 means destroy the lock/block/share * A return value != 0 means destroy the lock/block/share
*/ */
typedef int (*nlm_host_match_fn_t)(struct nlm_host *cur, struct nlm_host *ref); typedef int (*nlm_host_match_fn_t)(void *cur, struct nlm_host *ref);
/* /*
* Server-side lock handling * Server-side lock handling
@ -220,6 +220,12 @@ void nlmsvc_mark_resources(void);
void nlmsvc_free_host_resources(struct nlm_host *); void nlmsvc_free_host_resources(struct nlm_host *);
void nlmsvc_invalidate_all(void); void nlmsvc_invalidate_all(void);
/*
* Cluster failover support
*/
int nlmsvc_unlock_all_by_sb(struct super_block *sb);
int nlmsvc_unlock_all_by_ip(__be32 server_addr);
static inline struct inode *nlmsvc_file_inode(struct nlm_file *file) static inline struct inode *nlmsvc_file_inode(struct nlm_file *file)
{ {
return file->f_file->f_path.dentry->d_inode; return file->f_file->f_path.dentry->d_inode;

View file

@ -329,7 +329,7 @@ extern struct timeval nfssvc_boot;
(FATTR4_WORD0_SIZE | FATTR4_WORD0_ACL ) (FATTR4_WORD0_SIZE | FATTR4_WORD0_ACL )
#define NFSD_WRITEABLE_ATTRS_WORD1 \ #define NFSD_WRITEABLE_ATTRS_WORD1 \
(FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \ (FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \
| FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_METADATA | FATTR4_WORD1_TIME_MODIFY_SET) | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET)
#endif /* CONFIG_NFSD_V4 */ #endif /* CONFIG_NFSD_V4 */