Commit 8244559f authored by Neil Brown's avatar Neil Brown Committed by Linus Torvalds

[PATCH] PATCH 2/16: NFSD: BKL Removal: Lock export table

Change export table lock to (SMP safe) rwsemaphore

As a first step to removing the BKL from nfsd, this patch
changes the lock used for the export table to be a rwsem semaphore.
Previously it had the same functionality but depended on the BKL
for correctness.

As there is no "down_write_interruptible" this patch removes the
posibility of interrupting the write_lock request, but this should
never be needed anyway.
parent dd63f4c1
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/in.h> #include <linux/in.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/rwsem.h>
#include <linux/sunrpc/svc.h> #include <linux/sunrpc/svc.h>
#include <linux/nfsd/nfsd.h> #include <linux/nfsd/nfsd.h>
...@@ -60,10 +61,6 @@ struct svc_clnthash { ...@@ -60,10 +61,6 @@ struct svc_clnthash {
static struct svc_clnthash * clnt_hash[CLIENT_HASHMAX]; static struct svc_clnthash * clnt_hash[CLIENT_HASHMAX];
static svc_client * clients; static svc_client * clients;
static int hash_lock;
static int want_lock;
static int hash_count;
static DECLARE_WAIT_QUEUE_HEAD( hash_wait );
/* /*
* Find the client's export entry matching xdev/xino. * Find the client's export entry matching xdev/xino.
...@@ -162,6 +159,39 @@ static void exp_change_parents(svc_client *clp, svc_export *old, svc_export *new ...@@ -162,6 +159,39 @@ static void exp_change_parents(svc_client *clp, svc_export *old, svc_export *new
} }
} }
/*
* Hashtable locking. Write locks are placed only by user processes
* wanting to modify export information.
* Write locking only done in this file. Read locking
* needed externally.
*/
static DECLARE_RWSEM(hash_sem);
void
exp_readlock(void)
{
down_read(&hash_sem);
}
static inline void
exp_writelock(void)
{
down_write(&hash_sem);
}
void
exp_readunlock(void)
{
up_read(&hash_sem);
}
static inline void
exp_writeunlock(void)
{
up_write(&hash_sem);
}
/* /*
* Export a file system. * Export a file system.
*/ */
...@@ -189,11 +219,9 @@ exp_export(struct nfsctl_export *nxp) ...@@ -189,11 +219,9 @@ exp_export(struct nfsctl_export *nxp)
ino = nxp->ex_ino; ino = nxp->ex_ino;
/* Try to lock the export table for update */ /* Try to lock the export table for update */
if ((err = exp_writelock()) < 0) exp_writelock();
goto out;
/* Look up client info */ /* Look up client info */
err = -EINVAL;
if (!(clp = exp_getclientbyname(nxp->ex_client))) if (!(clp = exp_getclientbyname(nxp->ex_client)))
goto out_unlock; goto out_unlock;
...@@ -278,7 +306,7 @@ exp_export(struct nfsctl_export *nxp) ...@@ -278,7 +306,7 @@ exp_export(struct nfsctl_export *nxp)
/* Unlock hashtable */ /* Unlock hashtable */
out_unlock: out_unlock:
exp_unlock(); exp_writeunlock();
out: out:
return err; return err;
...@@ -345,8 +373,7 @@ exp_unexport(struct nfsctl_export *nxp) ...@@ -345,8 +373,7 @@ exp_unexport(struct nfsctl_export *nxp)
if (!exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX)) if (!exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX))
return -EINVAL; return -EINVAL;
if ((err = exp_writelock()) < 0) exp_writelock();
goto out;
err = -EINVAL; err = -EINVAL;
clp = exp_getclientbyname(nxp->ex_client); clp = exp_getclientbyname(nxp->ex_client);
...@@ -361,8 +388,7 @@ exp_unexport(struct nfsctl_export *nxp) ...@@ -361,8 +388,7 @@ exp_unexport(struct nfsctl_export *nxp)
} }
} }
exp_unlock(); exp_writeunlock();
out:
return err; return err;
} }
...@@ -415,58 +441,6 @@ exp_rootfh(struct svc_client *clp, char *path, struct knfsd_fh *f, int maxsize) ...@@ -415,58 +441,6 @@ exp_rootfh(struct svc_client *clp, char *path, struct knfsd_fh *f, int maxsize)
return err; return err;
} }
/*
* Hashtable locking. Write locks are placed only by user processes
* wanting to modify export information.
*/
void
exp_readlock(void)
{
while (hash_lock || want_lock)
sleep_on(&hash_wait);
hash_count++;
}
int
exp_writelock(void)
{
/* fast track */
if (!hash_count && !hash_lock) {
lock_it:
hash_lock = 1;
return 0;
}
clear_thread_flag(TIF_SIGPENDING);
want_lock++;
while (hash_count || hash_lock) {
interruptible_sleep_on(&hash_wait);
if (signal_pending(current))
break;
}
want_lock--;
/* restore the task's signals */
spin_lock_irq(&current->sigmask_lock);
recalc_sigpending();
spin_unlock_irq(&current->sigmask_lock);
if (!hash_count && !hash_lock)
goto lock_it;
return -EINTR;
}
void
exp_unlock(void)
{
if (!hash_count && !hash_lock)
printk(KERN_WARNING "exp_unlock: not locked!\n");
if (hash_count)
hash_count--;
else
hash_lock = 0;
wake_up(&hash_wait);
}
/* /*
* Find a valid client given an inet address. We always move the most * Find a valid client given an inet address. We always move the most
...@@ -572,7 +546,7 @@ static void *e_next(struct seq_file *m, void *p, loff_t *pos) ...@@ -572,7 +546,7 @@ static void *e_next(struct seq_file *m, void *p, loff_t *pos)
static void e_stop(struct seq_file *m, void *p) static void e_stop(struct seq_file *m, void *p)
{ {
exp_unlock(); exp_readunlock();
} }
struct flags { struct flags {
...@@ -688,8 +662,7 @@ exp_addclient(struct nfsctl_client *ncp) ...@@ -688,8 +662,7 @@ exp_addclient(struct nfsctl_client *ncp)
goto out; goto out;
/* Lock the hashtable */ /* Lock the hashtable */
if ((err = exp_writelock()) < 0) exp_writelock();
goto out;
/* First check if this is a change request for a client. */ /* First check if this is a change request for a client. */
for (clp = clients; clp; clp = clp->cl_next) for (clp = clients; clp; clp = clp->cl_next)
...@@ -754,7 +727,7 @@ exp_addclient(struct nfsctl_client *ncp) ...@@ -754,7 +727,7 @@ exp_addclient(struct nfsctl_client *ncp)
err = 0; err = 0;
out_unlock: out_unlock:
exp_unlock(); exp_writeunlock();
out: out:
return err; return err;
} }
...@@ -773,10 +746,8 @@ exp_delclient(struct nfsctl_client *ncp) ...@@ -773,10 +746,8 @@ exp_delclient(struct nfsctl_client *ncp)
goto out; goto out;
/* Lock the hashtable */ /* Lock the hashtable */
if ((err = exp_writelock()) < 0) exp_writelock();
goto out;
err = -EINVAL;
for (clpp = &clients; (clp = *clpp); clpp = &(clp->cl_next)) for (clpp = &clients; (clp = *clpp); clpp = &(clp->cl_next))
if (!strcmp(ncp->cl_ident, clp->cl_ident)) if (!strcmp(ncp->cl_ident, clp->cl_ident))
break; break;
...@@ -787,7 +758,7 @@ exp_delclient(struct nfsctl_client *ncp) ...@@ -787,7 +758,7 @@ exp_delclient(struct nfsctl_client *ncp)
err = 0; err = 0;
} }
exp_unlock(); exp_writeunlock();
out: out:
return err; return err;
} }
...@@ -893,16 +864,14 @@ nfsd_export_shutdown(void) ...@@ -893,16 +864,14 @@ nfsd_export_shutdown(void)
dprintk("nfsd: shutting down export module.\n"); dprintk("nfsd: shutting down export module.\n");
if (exp_writelock() < 0) { exp_writelock();
printk(KERN_WARNING "Weird: hashtable locked in exp_shutdown");
return;
}
for (i = 0; i < CLIENT_HASHMAX; i++) { for (i = 0; i < CLIENT_HASHMAX; i++) {
while (clnt_hash[i]) while (clnt_hash[i])
exp_freeclient(clnt_hash[i]->h_client); exp_freeclient(clnt_hash[i]->h_client);
} }
clients = NULL; /* we may be restarted before the module unloads */ clients = NULL; /* we may be restarted before the module unloads */
exp_unlock(); exp_writeunlock();
dprintk("nfsd: export shutdown complete.\n"); dprintk("nfsd: export shutdown complete.\n");
} }
...@@ -62,7 +62,7 @@ nlm_fclose(struct file *filp) ...@@ -62,7 +62,7 @@ nlm_fclose(struct file *filp)
struct nlmsvc_binding nfsd_nlm_ops = { struct nlmsvc_binding nfsd_nlm_ops = {
exp_readlock, /* lock export table for reading */ exp_readlock, /* lock export table for reading */
exp_unlock, /* unlock export table */ exp_readunlock, /* unlock export table */
exp_getclient, /* look up NFS client */ exp_getclient, /* look up NFS client */
nlm_fopen, /* open file for locking */ nlm_fopen, /* open file for locking */
nlm_fclose, /* close file */ nlm_fclose, /* close file */
......
...@@ -121,7 +121,7 @@ nfsctl_getfs(struct nfsctl_fsparm *data, struct knfsd_fh *res) ...@@ -121,7 +121,7 @@ nfsctl_getfs(struct nfsctl_fsparm *data, struct knfsd_fh *res)
err = -EPERM; err = -EPERM;
else else
err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen); err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen);
exp_unlock(); exp_readunlock();
return err; return err;
} }
...@@ -144,7 +144,7 @@ nfsctl_getfd(struct nfsctl_fdparm *data, __u8 *res) ...@@ -144,7 +144,7 @@ nfsctl_getfd(struct nfsctl_fdparm *data, __u8 *res)
err = -EPERM; err = -EPERM;
else else
err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE); err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE);
exp_unlock(); exp_readunlock();
if (err == 0) { if (err == 0) {
if (fh.fh_size > NFS_FHSIZE) if (fh.fh_size > NFS_FHSIZE)
......
...@@ -211,7 +211,7 @@ nfsd(struct svc_rqst *rqstp) ...@@ -211,7 +211,7 @@ nfsd(struct svc_rqst *rqstp)
svc_process(serv, rqstp); svc_process(serv, rqstp);
/* Unlock export hash tables */ /* Unlock export hash tables */
exp_unlock(); exp_readunlock();
update_thread_usage(nfsd_busy); update_thread_usage(nfsd_busy);
nfsd_busy--; nfsd_busy--;
} }
......
...@@ -87,8 +87,7 @@ struct svc_export { ...@@ -87,8 +87,7 @@ struct svc_export {
void nfsd_export_init(void); void nfsd_export_init(void);
void nfsd_export_shutdown(void); void nfsd_export_shutdown(void);
void exp_readlock(void); void exp_readlock(void);
int exp_writelock(void); void exp_readunlock(void);
void exp_unlock(void);
struct svc_client * exp_getclient(struct sockaddr_in *sin); struct svc_client * exp_getclient(struct sockaddr_in *sin);
void exp_putclient(struct svc_client *clp); void exp_putclient(struct svc_client *clp);
struct svc_export * exp_get(struct svc_client *clp, kdev_t dev, ino_t ino); struct svc_export * exp_get(struct svc_client *clp, kdev_t dev, ino_t ino);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment