Commit 38d7463e authored by James Simmons's avatar James Simmons

Merge bk://linus.bkbits.net/linux-2.5

into maxwell.earthlink.net:/usr/src/linus-2.5
parents bca102e6 c39f7320
...@@ -56,11 +56,8 @@ ...@@ -56,11 +56,8 @@
#include <linux/blk.h> #include <linux/blk.h>
#define DEBUG 0 #define DEBUG 0
#if DEBUG #define dprintk(x...) ((void)(DEBUG && printk(x)))
# define dprintk(x...) printk(x)
#else
# define dprintk(x...) do { } while(0)
#endif
#ifndef MODULE #ifndef MODULE
static void autostart_arrays (void); static void autostart_arrays (void);
...@@ -604,18 +601,6 @@ static void export_array(mddev_t *mddev) ...@@ -604,18 +601,6 @@ static void export_array(mddev_t *mddev)
mddev->raid_disks = 0; mddev->raid_disks = 0;
} }
static void free_mddev(mddev_t *mddev)
{
if (!mddev) {
MD_BUG();
return;
}
export_array(mddev);
md_size[mdidx(mddev)] = 0;
set_capacity(disks[mdidx(mddev)], 0);
}
#undef BAD_CSUM #undef BAD_CSUM
#undef BAD_MAGIC #undef BAD_MAGIC
#undef OUT_OF_MEM #undef OUT_OF_MEM
...@@ -1533,7 +1518,6 @@ static int do_md_stop(mddev_t * mddev, int ro) ...@@ -1533,7 +1518,6 @@ static int do_md_stop(mddev_t * mddev, int ro)
{ {
int err = 0; int err = 0;
kdev_t dev = mddev_to_kdev(mddev); kdev_t dev = mddev_to_kdev(mddev);
struct gendisk *disk;
if (atomic_read(&mddev->active)>1) { if (atomic_read(&mddev->active)>1) {
printk(STILL_IN_USE, mdidx(mddev)); printk(STILL_IN_USE, mdidx(mddev));
...@@ -1582,6 +1566,16 @@ static int do_md_stop(mddev_t * mddev, int ro) ...@@ -1582,6 +1566,16 @@ static int do_md_stop(mddev_t * mddev, int ro)
if (ro) if (ro)
set_device_ro(dev, 1); set_device_ro(dev, 1);
} }
/*
* Free resources if final stop
*/
if (!ro) {
struct gendisk *disk;
printk(KERN_INFO "md: md%d stopped.\n", mdidx(mddev));
export_array(mddev);
md_size[mdidx(mddev)] = 0;
disk = disks[mdidx(mddev)]; disk = disks[mdidx(mddev)];
disks[mdidx(mddev)] = NULL; disks[mdidx(mddev)] = NULL;
...@@ -1591,12 +1585,6 @@ static int do_md_stop(mddev_t * mddev, int ro) ...@@ -1591,12 +1585,6 @@ static int do_md_stop(mddev_t * mddev, int ro)
kfree(disk); kfree(disk);
} }
/*
* Free resources if final stop
*/
if (!ro) {
printk(KERN_INFO "md: md%d stopped.\n", mdidx(mddev));
free_mddev(mddev);
} else } else
printk(KERN_INFO "md: md%d switched to read-only mode.\n", mdidx(mddev)); printk(KERN_INFO "md: md%d switched to read-only mode.\n", mdidx(mddev));
err = 0; err = 0;
...@@ -2593,7 +2581,7 @@ static void md_recover_arrays(void) ...@@ -2593,7 +2581,7 @@ static void md_recover_arrays(void)
void md_error(mddev_t *mddev, mdk_rdev_t *rdev) void md_error(mddev_t *mddev, mdk_rdev_t *rdev)
{ {
dprintk("md_error dev:(%d:%d), rdev:(%d:%d), (caller: %p,%p,%p,%p).\n", dprintk("md_error dev:(%d:%d), rdev:(%d:%d), (caller: %p,%p,%p,%p).\n",
MD_MAJOR,mdidx(mddev),MAJOR(bdev->bd_dev),MINOR(bdev->bd_dev), MD_MAJOR,mdidx(mddev),MAJOR(rdev->bdev->bd_dev),MINOR(rdev->bdev->bd_dev),
__builtin_return_address(0),__builtin_return_address(1), __builtin_return_address(0),__builtin_return_address(1),
__builtin_return_address(2),__builtin_return_address(3)); __builtin_return_address(2),__builtin_return_address(3));
...@@ -3149,11 +3137,11 @@ request_queue_t * md_queue_proc(kdev_t dev) ...@@ -3149,11 +3137,11 @@ request_queue_t * md_queue_proc(kdev_t dev)
{ {
mddev_t *mddev = mddev_find(minor(dev)); mddev_t *mddev = mddev_find(minor(dev));
request_queue_t *q = BLK_DEFAULT_QUEUE(MAJOR_NR); request_queue_t *q = BLK_DEFAULT_QUEUE(MAJOR_NR);
if (!mddev || atomic_read(&mddev->active)<2) if (mddev) {
BUG();
if (mddev->pers) if (mddev->pers)
q = &mddev->queue; q = &mddev->queue;
mddev_put(mddev); /* the caller must hold a reference... */ mddev_put(mddev);
}
return q; return q;
} }
......
...@@ -37,20 +37,6 @@ ...@@ -37,20 +37,6 @@
#define NR_RESERVED_BUFS 32 #define NR_RESERVED_BUFS 32
/*
* The following can be used to debug the driver
*/
#define MULTIPATH_DEBUG 0
#if MULTIPATH_DEBUG
#define PRINTK(x...) printk(x)
#define inline
#define __inline__
#else
#define PRINTK(x...) do { } while (0)
#endif
static mdk_personality_t multipath_personality; static mdk_personality_t multipath_personality;
static spinlock_t retry_list_lock = SPIN_LOCK_UNLOCKED; static spinlock_t retry_list_lock = SPIN_LOCK_UNLOCKED;
struct multipath_bh *multipath_retry_list = NULL, **multipath_retry_tail; struct multipath_bh *multipath_retry_list = NULL, **multipath_retry_tail;
......
...@@ -49,12 +49,10 @@ ...@@ -49,12 +49,10 @@
# define CHECK_DEVLOCK() # define CHECK_DEVLOCK()
#endif #endif
#define PRINTK(x...) ((void)(RAID5_DEBUG && printk(x)))
#if RAID5_DEBUG #if RAID5_DEBUG
#define PRINTK(x...) printk(x)
#define inline #define inline
#define __inline__ #define __inline__
#else
#define PRINTK(x...) do { } while (0)
#endif #endif
static void print_raid5_conf (raid5_conf_t *conf); static void print_raid5_conf (raid5_conf_t *conf);
...@@ -933,13 +931,16 @@ static void handle_stripe(struct stripe_head *sh) ...@@ -933,13 +931,16 @@ static void handle_stripe(struct stripe_head *sh)
test_bit(R5_UPTODATE, &dev->flags)) test_bit(R5_UPTODATE, &dev->flags))
|| (failed == 1 && failed_num == sh->pd_idx)) || (failed == 1 && failed_num == sh->pd_idx))
) { ) {
/* any written block on an uptodate or failed drive can be returned */ /* any written block on an uptodate or failed drive can be returned.
* Note that if we 'wrote' to a failed drive, it will be UPTODATE, but
* never LOCKED, so we don't need to test 'failed' directly.
*/
for (i=disks; i--; ) for (i=disks; i--; )
if (sh->dev[i].written) { if (sh->dev[i].written) {
dev = &sh->dev[i]; dev = &sh->dev[i];
if (!test_bit(R5_Insync, &sh->dev[sh->pd_idx].flags) && if (!test_bit(R5_LOCKED, &dev->flags) &&
(!test_bit(R5_LOCKED, &dev->flags) && test_bit(R5_UPTODATE, &dev->flags)) ) { test_bit(R5_UPTODATE, &dev->flags) ) {
/* maybe we can return some write requests */ /* We can return any write requests */
struct bio *wbi, *wbi2; struct bio *wbi, *wbi2;
PRINTK("Return write for disc %d\n", i); PRINTK("Return write for disc %d\n", i);
wbi = dev->written; wbi = dev->written;
...@@ -1164,7 +1165,7 @@ static void handle_stripe(struct stripe_head *sh) ...@@ -1164,7 +1165,7 @@ static void handle_stripe(struct stripe_head *sh)
md_sync_acct(rdev, STRIPE_SECTORS); md_sync_acct(rdev, STRIPE_SECTORS);
bi->bi_bdev = rdev->bdev; bi->bi_bdev = rdev->bdev;
PRINTK("for %ld schedule op %d on disc %d\n", sh->sector, bi->bi_rw, i); PRINTK("for %ld schedule op %ld on disc %d\n", sh->sector, bi->bi_rw, i);
atomic_inc(&sh->count); atomic_inc(&sh->count);
bi->bi_sector = sh->sector; bi->bi_sector = sh->sector;
bi->bi_flags = 0; bi->bi_flags = 0;
...@@ -1175,7 +1176,7 @@ static void handle_stripe(struct stripe_head *sh) ...@@ -1175,7 +1176,7 @@ static void handle_stripe(struct stripe_head *sh)
bi->bi_next = NULL; bi->bi_next = NULL;
generic_make_request(bi); generic_make_request(bi);
} else { } else {
PRINTK("skip op %d on disc %d for sector %ld\n", bi->bi_rw, i, sh->sector); PRINTK("skip op %ld on disc %d for sector %ld\n", bi->bi_rw, i, sh->sector);
clear_bit(R5_LOCKED, &dev->flags); clear_bit(R5_LOCKED, &dev->flags);
set_bit(STRIPE_HANDLE, &sh->state); set_bit(STRIPE_HANDLE, &sh->state);
} }
...@@ -1242,8 +1243,8 @@ static int make_request (request_queue_t *q, struct bio * bi) ...@@ -1242,8 +1243,8 @@ static int make_request (request_queue_t *q, struct bio * bi)
new_sector = raid5_compute_sector(logical_sector, new_sector = raid5_compute_sector(logical_sector,
raid_disks, data_disks, &dd_idx, &pd_idx, conf); raid_disks, data_disks, &dd_idx, &pd_idx, conf);
PRINTK("raid5: make_request, sector %ul logical %ul\n", PRINTK("raid5: make_request, sector %Lu logical %Lu\n",
new_sector, logical_sector); (unsigned long long)new_sector, (unsigned long long)logical_sector);
sh = get_active_stripe(conf, new_sector, pd_idx, (bi->bi_rw&RWA_MASK)); sh = get_active_stripe(conf, new_sector, pd_idx, (bi->bi_rw&RWA_MASK));
if (sh) { if (sh) {
......
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
#define NLM_HOST_MAX 64 #define NLM_HOST_MAX 64
#define NLM_HOST_NRHASH 32 #define NLM_HOST_NRHASH 32
#define NLM_ADDRHASH(addr) (ntohl(addr) & (NLM_HOST_NRHASH-1)) #define NLM_ADDRHASH(addr) (ntohl(addr) & (NLM_HOST_NRHASH-1))
#define NLM_PTRHASH(ptr) ((((u32)(unsigned long) ptr) / 32) & (NLM_HOST_NRHASH-1))
#define NLM_HOST_REBIND (60 * HZ) #define NLM_HOST_REBIND (60 * HZ)
#define NLM_HOST_EXPIRE ((nrhosts > NLM_HOST_MAX)? 300 * HZ : 120 * HZ) #define NLM_HOST_EXPIRE ((nrhosts > NLM_HOST_MAX)? 300 * HZ : 120 * HZ)
#define NLM_HOST_COLLECT ((nrhosts > NLM_HOST_MAX)? 120 * HZ : 60 * HZ) #define NLM_HOST_COLLECT ((nrhosts > NLM_HOST_MAX)? 120 * HZ : 60 * HZ)
...@@ -42,7 +41,7 @@ static void nlm_gc_hosts(void); ...@@ -42,7 +41,7 @@ static void nlm_gc_hosts(void);
struct nlm_host * struct nlm_host *
nlmclnt_lookup_host(struct sockaddr_in *sin, int proto, int version) nlmclnt_lookup_host(struct sockaddr_in *sin, int proto, int version)
{ {
return nlm_lookup_host(NULL, sin, proto, version); return nlm_lookup_host(0, sin, proto, version);
} }
/* /*
...@@ -51,44 +50,24 @@ nlmclnt_lookup_host(struct sockaddr_in *sin, int proto, int version) ...@@ -51,44 +50,24 @@ nlmclnt_lookup_host(struct sockaddr_in *sin, int proto, int version)
struct nlm_host * struct nlm_host *
nlmsvc_lookup_host(struct svc_rqst *rqstp) nlmsvc_lookup_host(struct svc_rqst *rqstp)
{ {
return nlm_lookup_host(rqstp->rq_client, &rqstp->rq_addr, return nlm_lookup_host(1, &rqstp->rq_addr,
rqstp->rq_prot, rqstp->rq_vers); rqstp->rq_prot, rqstp->rq_vers);
} }
/*
* Match the given host against client/address
*/
static inline int
nlm_match_host(struct nlm_host *host, struct svc_client *clnt,
struct sockaddr_in *sin)
{
if (clnt)
return host->h_exportent == clnt;
return nlm_cmp_addr(&host->h_addr, sin);
}
/* /*
* Common host lookup routine for server & client * Common host lookup routine for server & client
*/ */
struct nlm_host * struct nlm_host *
nlm_lookup_host(struct svc_client *clnt, struct sockaddr_in *sin, nlm_lookup_host(int server, struct sockaddr_in *sin,
int proto, int version) int proto, int version)
{ {
struct nlm_host *host, **hp; struct nlm_host *host, **hp;
u32 addr; u32 addr;
int hash; int hash;
if (!clnt && !sin) {
printk(KERN_NOTICE "lockd: no clnt or addr in lookup_host!\n");
return NULL;
}
dprintk("lockd: nlm_lookup_host(%08x, p=%d, v=%d)\n", dprintk("lockd: nlm_lookup_host(%08x, p=%d, v=%d)\n",
(unsigned)(sin? ntohl(sin->sin_addr.s_addr) : 0), proto, version); (unsigned)(sin? ntohl(sin->sin_addr.s_addr) : 0), proto, version);
if (clnt)
hash = NLM_PTRHASH(clnt);
else
hash = NLM_ADDRHASH(sin->sin_addr.s_addr); hash = NLM_ADDRHASH(sin->sin_addr.s_addr);
/* Lock hash table */ /* Lock hash table */
...@@ -98,12 +77,14 @@ nlm_lookup_host(struct svc_client *clnt, struct sockaddr_in *sin, ...@@ -98,12 +77,14 @@ nlm_lookup_host(struct svc_client *clnt, struct sockaddr_in *sin,
nlm_gc_hosts(); nlm_gc_hosts();
for (hp = &nlm_hosts[hash]; (host = *hp); hp = &host->h_next) { for (hp = &nlm_hosts[hash]; (host = *hp); hp = &host->h_next) {
if (proto && host->h_proto != proto) if (host->h_proto != proto)
continue; continue;
if (version && host->h_version != version) if (host->h_version != version)
continue;
if (host->h_server != server)
continue; continue;
if (nlm_match_host(host, clnt, sin)) { if (nlm_cmp_addr(&host->h_addr, sin)) {
if (hp != nlm_hosts + hash) { if (hp != nlm_hosts + hash) {
*hp = host->h_next; *hp = host->h_next;
host->h_next = nlm_hosts[hash]; host->h_next = nlm_hosts[hash];
...@@ -115,10 +96,6 @@ nlm_lookup_host(struct svc_client *clnt, struct sockaddr_in *sin, ...@@ -115,10 +96,6 @@ nlm_lookup_host(struct svc_client *clnt, struct sockaddr_in *sin,
} }
} }
/* special hack for nlmsvc_invalidate_client */
if (sin == NULL)
goto nohost;
/* Ooops, no host found, create it */ /* Ooops, no host found, create it */
dprintk("lockd: creating host entry\n"); dprintk("lockd: creating host entry\n");
...@@ -146,8 +123,7 @@ nlm_lookup_host(struct svc_client *clnt, struct sockaddr_in *sin, ...@@ -146,8 +123,7 @@ nlm_lookup_host(struct svc_client *clnt, struct sockaddr_in *sin,
init_waitqueue_head(&host->h_gracewait); init_waitqueue_head(&host->h_gracewait);
host->h_state = 0; /* pseudo NSM state */ host->h_state = 0; /* pseudo NSM state */
host->h_nsmstate = 0; /* real NSM state */ host->h_nsmstate = 0; /* real NSM state */
host->h_exportent = clnt; host->h_server = server;
host->h_next = nlm_hosts[hash]; host->h_next = nlm_hosts[hash];
nlm_hosts[hash] = host; nlm_hosts[hash] = host;
...@@ -159,6 +135,30 @@ nlm_lookup_host(struct svc_client *clnt, struct sockaddr_in *sin, ...@@ -159,6 +135,30 @@ nlm_lookup_host(struct svc_client *clnt, struct sockaddr_in *sin,
return host; return host;
} }
struct nlm_host *
nlm_find_client(void)
{
/* find a nlm_host for a client for which h_killed == 0.
* and return it
*/
int hash;
down(&nlm_host_sema);
for (hash = 0 ; hash < NLM_HOST_NRHASH; hash++) {
struct nlm_host *host, **hp;
for (hp = &nlm_hosts[hash]; (host = *hp) ; hp = &host->h_next) {
if (host->h_server &&
host->h_killed == 0) {
nlm_get_host(host);
up(&nlm_host_sema);
return host;
}
}
}
up(&nlm_host_sema);
return NULL;
}
/* /*
* Create the NLM RPC client for an NLM peer * Create the NLM RPC client for an NLM peer
*/ */
......
...@@ -32,7 +32,6 @@ EXPORT_SYMBOL(lockd_down); ...@@ -32,7 +32,6 @@ EXPORT_SYMBOL(lockd_down);
EXPORT_SYMBOL(nlmclnt_proc); EXPORT_SYMBOL(nlmclnt_proc);
/* NFS server entry points/hooks */ /* NFS server entry points/hooks */
EXPORT_SYMBOL(nlmsvc_invalidate_client);
EXPORT_SYMBOL(nlmsvc_ops); EXPORT_SYMBOL(nlmsvc_ops);
#endif /* CONFIG_MODULES */ #endif /* CONFIG_MODULES */
...@@ -42,6 +42,7 @@ nsm_mon_unmon(struct nlm_host *host, u32 proc, struct nsm_res *res) ...@@ -42,6 +42,7 @@ nsm_mon_unmon(struct nlm_host *host, u32 proc, struct nsm_res *res)
goto out; goto out;
args.addr = host->h_addr.sin_addr.s_addr; args.addr = host->h_addr.sin_addr.s_addr;
args.proto= (host->h_proto<<1) | host->h_server;
args.prog = NLM_PROGRAM; args.prog = NLM_PROGRAM;
args.vers = host->h_version; args.vers = host->h_version;
args.proc = NLMPROC_NSM_NOTIFY; args.proc = NLMPROC_NSM_NOTIFY;
...@@ -167,8 +168,8 @@ xdr_encode_mon(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp) ...@@ -167,8 +168,8 @@ xdr_encode_mon(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp)
/* This is the private part. Needed only for SM_MON call */ /* This is the private part. Needed only for SM_MON call */
if (rqstp->rq_task->tk_msg.rpc_proc == SM_MON) { if (rqstp->rq_task->tk_msg.rpc_proc == SM_MON) {
*p++ = argp->addr; *p++ = argp->addr;
*p++ = 0; *p++ = argp->vers;
*p++ = 0; *p++ = argp->proto;
*p++ = 0; *p++ = 0;
} }
...@@ -206,61 +207,60 @@ xdr_decode_stat(struct rpc_rqst *rqstp, u32 *p, struct nsm_res *resp) ...@@ -206,61 +207,60 @@ xdr_decode_stat(struct rpc_rqst *rqstp, u32 *p, struct nsm_res *resp)
static struct rpc_procinfo nsm_procedures[] = { static struct rpc_procinfo nsm_procedures[] = {
{ {
p_procname: "sm_null", .p_procname = "sm_null",
p_encode: (kxdrproc_t) xdr_error, .p_encode = (kxdrproc_t) xdr_error,
p_decode: (kxdrproc_t) xdr_error, .p_decode = (kxdrproc_t) xdr_error,
}, },
{ {
p_procname: "sm_stat", .p_procname = "sm_stat",
p_encode: (kxdrproc_t) xdr_error, .p_encode = (kxdrproc_t) xdr_error,
p_decode: (kxdrproc_t) xdr_error, .p_decode = (kxdrproc_t) xdr_error,
}, },
{ {
p_procname: "sm_mon", .p_procname = "sm_mon",
p_encode: (kxdrproc_t) xdr_encode_mon, .p_encode = (kxdrproc_t) xdr_encode_mon,
p_decode: (kxdrproc_t) xdr_decode_stat_res, .p_decode = (kxdrproc_t) xdr_decode_stat_res,
p_bufsiz: MAX(SM_mon_sz, SM_monres_sz) << 2, .p_bufsiz = MAX(SM_mon_sz, SM_monres_sz) << 2,
}, },
{ {
p_procname: "sm_unmon", .p_procname = "sm_unmon",
p_encode: (kxdrproc_t) xdr_encode_mon, .p_encode = (kxdrproc_t) xdr_encode_mon,
p_decode: (kxdrproc_t) xdr_decode_stat, .p_decode = (kxdrproc_t) xdr_decode_stat,
p_bufsiz: MAX(SM_mon_id_sz, SM_unmonres_sz) << 2, .p_bufsiz = MAX(SM_mon_id_sz, SM_unmonres_sz) << 2,
}, },
{ {
p_procname: "sm_unmon_all", .p_procname = "sm_unmon_all",
p_encode: (kxdrproc_t) xdr_error, .p_encode = (kxdrproc_t) xdr_error,
p_decode: (kxdrproc_t) xdr_error, .p_decode = (kxdrproc_t) xdr_error,
}, },
{ {
p_procname: "sm_simu_crash", .p_procname = "sm_simu_crash",
p_encode: (kxdrproc_t) xdr_error, .p_encode = (kxdrproc_t) xdr_error,
p_decode: (kxdrproc_t) xdr_error, 0, 0 .p_decode = (kxdrproc_t) xdr_error,
}, },
{ {
p_procname: "sm_notify", .p_procname = "sm_notify",
p_encode: (kxdrproc_t) xdr_error, .p_encode = (kxdrproc_t) xdr_error,
p_decode: (kxdrproc_t) xdr_error, .p_decode = (kxdrproc_t) xdr_error,
}, },
}; };
static struct rpc_version nsm_version1 = { static struct rpc_version nsm_version1 = {
number: 1, .number = 1,
nrprocs: sizeof(nsm_procedures)/sizeof(nsm_procedures[0]), .nrprocs = sizeof(nsm_procedures)/sizeof(nsm_procedures[0]),
procs: nsm_procedures .procs = nsm_procedures
}; };
static struct rpc_version * nsm_version[] = { static struct rpc_version * nsm_version[] = {
NULL, [1] = &nsm_version1,
&nsm_version1,
}; };
static struct rpc_stat nsm_stats; static struct rpc_stat nsm_stats;
struct rpc_program nsm_program = { struct rpc_program nsm_program = {
name: "statd", .name = "statd",
number: SM_PROGRAM, .number = SM_PROGRAM,
nrvers: sizeof(nsm_version)/sizeof(nsm_version[0]), .nrvers = sizeof(nsm_version)/sizeof(nsm_version[0]),
version: nsm_version, .version = nsm_version,
stats: &nsm_stats .stats = &nsm_stats
}; };
...@@ -130,7 +130,7 @@ lockd(struct svc_rqst *rqstp) ...@@ -130,7 +130,7 @@ lockd(struct svc_rqst *rqstp)
flush_signals(current); flush_signals(current);
spin_unlock_irq(&current->sigmask_lock); spin_unlock_irq(&current->sigmask_lock);
if (nlmsvc_ops) { if (nlmsvc_ops) {
nlmsvc_ops->detach(); nlmsvc_invalidate_all();
grace_period_expire = set_grace_period(); grace_period_expire = set_grace_period();
} }
} }
...@@ -163,22 +163,8 @@ lockd(struct svc_rqst *rqstp) ...@@ -163,22 +163,8 @@ lockd(struct svc_rqst *rqstp)
dprintk("lockd: request from %08x\n", dprintk("lockd: request from %08x\n",
(unsigned)ntohl(rqstp->rq_addr.sin_addr.s_addr)); (unsigned)ntohl(rqstp->rq_addr.sin_addr.s_addr));
/*
* Look up the NFS client handle. The handle is needed for
* all but the GRANTED callback RPCs.
*/
rqstp->rq_client = NULL;
if (nlmsvc_ops) {
nlmsvc_ops->exp_readlock();
rqstp->rq_client =
nlmsvc_ops->exp_getclient(&rqstp->rq_addr);
}
svc_process(serv, rqstp); svc_process(serv, rqstp);
/* Unlock export hash tables */
if (nlmsvc_ops)
nlmsvc_ops->exp_unlock();
} }
/* /*
...@@ -187,7 +173,7 @@ lockd(struct svc_rqst *rqstp) ...@@ -187,7 +173,7 @@ lockd(struct svc_rqst *rqstp)
*/ */
if (!nlmsvc_pid || current->pid == nlmsvc_pid) { if (!nlmsvc_pid || current->pid == nlmsvc_pid) {
if (nlmsvc_ops) if (nlmsvc_ops)
nlmsvc_ops->detach(); nlmsvc_invalidate_all();
nlm_shutdown_hosts(); nlm_shutdown_hosts();
nlmsvc_pid = 0; nlmsvc_pid = 0;
} else } else
...@@ -369,29 +355,27 @@ __setup("lockd.tcpport=", tcpport_set); ...@@ -369,29 +355,27 @@ __setup("lockd.tcpport=", tcpport_set);
* Define NLM program and procedures * Define NLM program and procedures
*/ */
static struct svc_version nlmsvc_version1 = { static struct svc_version nlmsvc_version1 = {
vs_vers: 1, .vs_vers = 1,
vs_nproc: 17, .vs_nproc = 17,
vs_proc: nlmsvc_procedures, .vs_proc = nlmsvc_procedures,
}; };
static struct svc_version nlmsvc_version3 = { static struct svc_version nlmsvc_version3 = {
vs_vers: 3, .vs_vers = 3,
vs_nproc: 24, .vs_nproc = 24,
vs_proc: nlmsvc_procedures, .vs_proc = nlmsvc_procedures,
}; };
#ifdef CONFIG_LOCKD_V4 #ifdef CONFIG_LOCKD_V4
static struct svc_version nlmsvc_version4 = { static struct svc_version nlmsvc_version4 = {
vs_vers: 4, .vs_vers = 4,
vs_nproc: 24, .vs_nproc = 24,
vs_proc: nlmsvc_procedures4, .vs_proc = nlmsvc_procedures4,
}; };
#endif #endif
static struct svc_version * nlmsvc_version[] = { static struct svc_version * nlmsvc_version[] = {
NULL, [1] = &nlmsvc_version1,
&nlmsvc_version1, [3] = &nlmsvc_version3,
NULL,
&nlmsvc_version3,
#ifdef CONFIG_LOCKD_V4 #ifdef CONFIG_LOCKD_V4
&nlmsvc_version4, [4] = &nlmsvc_version4,
#endif #endif
}; };
...@@ -399,11 +383,11 @@ static struct svc_stat nlmsvc_stats; ...@@ -399,11 +383,11 @@ static struct svc_stat nlmsvc_stats;
#define NLM_NRVERS (sizeof(nlmsvc_version)/sizeof(nlmsvc_version[0])) #define NLM_NRVERS (sizeof(nlmsvc_version)/sizeof(nlmsvc_version[0]))
struct svc_program nlmsvc_program = { struct svc_program nlmsvc_program = {
pg_prog: NLM_PROGRAM, /* program number */ .pg_prog = NLM_PROGRAM, /* program number */
pg_lovers: 1, // version .pg_lovers = 1, /* version */
pg_hivers: NLM_NRVERS-1, // range .pg_hivers = NLM_NRVERS-1, /* range */
pg_nvers: NLM_NRVERS, /* number of entries in nlmsvc_version */ .pg_nvers = NLM_NRVERS, /* number of entries in nlmsvc_version */
pg_vers: nlmsvc_version, /* version table */ .pg_vers = nlmsvc_version, /* version table */
pg_name: "lockd", /* service name */ .pg_name = "lockd", /* service name */
pg_stats: &nlmsvc_stats, /* stats table */ .pg_stats = &nlmsvc_stats, /* stats table */
}; };
...@@ -40,15 +40,6 @@ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, ...@@ -40,15 +40,6 @@ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
if (!nlmsvc_ops) if (!nlmsvc_ops)
return nlm_lck_denied_nolocks; return nlm_lck_denied_nolocks;
/* Obtain handle for client host */
if (rqstp->rq_client == NULL) {
printk(KERN_NOTICE
"lockd: unauthenticated request from (%08x:%d)\n",
ntohl(rqstp->rq_addr.sin_addr.s_addr),
ntohs(rqstp->rq_addr.sin_port));
return nlm_lck_denied_nolocks;
}
/* Obtain host handle */ /* Obtain host handle */
if (!(host = nlmsvc_lookup_host(rqstp)) if (!(host = nlmsvc_lookup_host(rqstp))
|| (argp->monitor && !host->h_monitored && nsm_monitor(host) < 0)) || (argp->monitor && !host->h_monitored && nsm_monitor(host) < 0))
...@@ -420,8 +411,9 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, ...@@ -420,8 +411,9 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
void *resp) void *resp)
{ {
struct sockaddr_in saddr = rqstp->rq_addr; struct sockaddr_in saddr = rqstp->rq_addr;
int vers = rqstp->rq_vers; int vers = argp->vers;
int prot = rqstp->rq_prot; int prot = argp->proto >> 1;
struct nlm_host *host; struct nlm_host *host;
dprintk("lockd: SM_NOTIFY called\n"); dprintk("lockd: SM_NOTIFY called\n");
...@@ -438,24 +430,20 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, ...@@ -438,24 +430,20 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
* reclaim all locks we hold on this server. * reclaim all locks we hold on this server.
*/ */
saddr.sin_addr.s_addr = argp->addr; saddr.sin_addr.s_addr = argp->addr;
if ((argp->proto & 1)==0) {
if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) { if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) {
nlmclnt_recovery(host, argp->state); nlmclnt_recovery(host, argp->state);
nlm_release_host(host); nlm_release_host(host);
} }
} else {
/* If we run on an NFS server, delete all locks held by the client */ /* If we run on an NFS server, delete all locks held by the client */
if (nlmsvc_ops != NULL) {
struct svc_client *clnt; if ((host = nlm_lookup_host(1, &saddr, prot, vers)) != NULL) {
saddr.sin_addr.s_addr = argp->addr;
nlmsvc_ops->exp_readlock();
if ((clnt = nlmsvc_ops->exp_getclient(&saddr)) != NULL
&& (host = nlm_lookup_host(clnt, &saddr, 0, 0)) != NULL) {
nlmsvc_free_host_resources(host); nlmsvc_free_host_resources(host);
}
nlm_release_host(host); nlm_release_host(host);
nlmsvc_ops->exp_unlock();
} }
}
return rpc_success; return rpc_success;
} }
...@@ -527,15 +515,13 @@ nlm4svc_callback_exit(struct rpc_task *task) ...@@ -527,15 +515,13 @@ nlm4svc_callback_exit(struct rpc_task *task)
struct nlm_void { int dummy; }; struct nlm_void { int dummy; };
#define PROC(name, xargt, xrest, argt, rest, respsize) \ #define PROC(name, xargt, xrest, argt, rest, respsize) \
{ (svc_procfunc) nlm4svc_proc_##name, \ { .pc_func = (svc_procfunc) nlm4svc_proc_##name, \
(kxdrproc_t) nlm4svc_decode_##xargt, \ .pc_decode = (kxdrproc_t) nlm4svc_decode_##xargt, \
(kxdrproc_t) nlm4svc_encode_##xrest, \ .pc_encode = (kxdrproc_t) nlm4svc_encode_##xrest, \
NULL, \ .pc_release = NULL, \
sizeof(struct nlm_##argt), \ .pc_argsize = sizeof(struct nlm_##argt), \
sizeof(struct nlm_##rest), \ .pc_ressize = sizeof(struct nlm_##rest), \
0, \ .pc_xdrressize = respsize, \
0, \
respsize, \
} }
#define Ck (1+8) /* cookie */ #define Ck (1+8) /* cookie */
#define No (1+1024/4) /* netobj */ #define No (1+1024/4) /* netobj */
......
...@@ -69,15 +69,6 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, ...@@ -69,15 +69,6 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
if (!nlmsvc_ops) if (!nlmsvc_ops)
return nlm_lck_denied_nolocks; return nlm_lck_denied_nolocks;
/* Obtain handle for client host */
if (rqstp->rq_client == NULL) {
printk(KERN_NOTICE
"lockd: unauthenticated request from (%08x:%d)\n",
ntohl(rqstp->rq_addr.sin_addr.s_addr),
ntohs(rqstp->rq_addr.sin_port));
return nlm_lck_denied_nolocks;
}
/* Obtain host handle */ /* Obtain host handle */
if (!(host = nlmsvc_lookup_host(rqstp)) if (!(host = nlmsvc_lookup_host(rqstp))
|| (argp->monitor && !host->h_monitored && nsm_monitor(host) < 0)) || (argp->monitor && !host->h_monitored && nsm_monitor(host) < 0))
...@@ -448,8 +439,8 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, ...@@ -448,8 +439,8 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
void *resp) void *resp)
{ {
struct sockaddr_in saddr = rqstp->rq_addr; struct sockaddr_in saddr = rqstp->rq_addr;
int vers = rqstp->rq_vers; int vers = argp->vers;
int prot = rqstp->rq_prot; int prot = argp->proto >> 1;
struct nlm_host *host; struct nlm_host *host;
dprintk("lockd: SM_NOTIFY called\n"); dprintk("lockd: SM_NOTIFY called\n");
...@@ -466,22 +457,17 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, ...@@ -466,22 +457,17 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
* reclaim all locks we hold on this server. * reclaim all locks we hold on this server.
*/ */
saddr.sin_addr.s_addr = argp->addr; saddr.sin_addr.s_addr = argp->addr;
if ((argp->proto & 1)==0) {
if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) { if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) {
nlmclnt_recovery(host, argp->state); nlmclnt_recovery(host, argp->state);
nlm_release_host(host); nlm_release_host(host);
} }
} else {
/* If we run on an NFS server, delete all locks held by the client */ /* If we run on an NFS server, delete all locks held by the client */
if (nlmsvc_ops != NULL) { if ((host = nlm_lookup_host(1, &saddr, prot, vers)) != NULL) {
struct svc_client *clnt;
saddr.sin_addr.s_addr = argp->addr;
nlmsvc_ops->exp_readlock();
if ((clnt = nlmsvc_ops->exp_getclient(&saddr)) != NULL
&& (host = nlm_lookup_host(clnt, &saddr, 0, 0)) != NULL) {
nlmsvc_free_host_resources(host); nlmsvc_free_host_resources(host);
}
nlm_release_host(host); nlm_release_host(host);
nlmsvc_ops->exp_unlock(); }
} }
return rpc_success; return rpc_success;
...@@ -555,15 +541,13 @@ nlmsvc_callback_exit(struct rpc_task *task) ...@@ -555,15 +541,13 @@ nlmsvc_callback_exit(struct rpc_task *task)
struct nlm_void { int dummy; }; struct nlm_void { int dummy; };
#define PROC(name, xargt, xrest, argt, rest, respsize) \ #define PROC(name, xargt, xrest, argt, rest, respsize) \
{ (svc_procfunc) nlmsvc_proc_##name, \ { .pc_func = (svc_procfunc) nlmsvc_proc_##name, \
(kxdrproc_t) nlmsvc_decode_##xargt, \ .pc_decode = (kxdrproc_t) nlmsvc_decode_##xargt, \
(kxdrproc_t) nlmsvc_encode_##xrest, \ .pc_encode = (kxdrproc_t) nlmsvc_encode_##xrest, \
NULL, \ .pc_release = NULL, \
sizeof(struct nlm_##argt), \ .pc_argsize = sizeof(struct nlm_##argt), \
sizeof(struct nlm_##rest), \ .pc_ressize = sizeof(struct nlm_##rest), \
0, \ .pc_xdrressize = respsize, \
0, \
respsize, \
} }
#define Ck (1+8) /* cookie */ #define Ck (1+8) /* cookie */
......
...@@ -294,15 +294,13 @@ nlmsvc_free_host_resources(struct nlm_host *host) ...@@ -294,15 +294,13 @@ nlmsvc_free_host_resources(struct nlm_host *host)
} }
/* /*
* Delete a client when the nfsd entry is removed. * delete all hosts structs for clients
*/ */
void void
nlmsvc_invalidate_client(struct svc_client *clnt) nlmsvc_invalidate_all(void)
{ {
struct nlm_host *host; struct nlm_host *host;
while ((host = nlm_find_client()) != NULL) {
if ((host = nlm_lookup_host(clnt, NULL, 0, 0)) != NULL) {
dprintk("lockd: invalidating client for %s\n", host->h_name);
nlmsvc_free_host_resources(host); nlmsvc_free_host_resources(host);
host->h_expires = 0; host->h_expires = 0;
host->h_killed = 1; host->h_killed = 1;
......
...@@ -369,6 +369,8 @@ nlmsvc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp) ...@@ -369,6 +369,8 @@ nlmsvc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp)
argp->state = ntohl(*p++); argp->state = ntohl(*p++);
/* Preserve the address in network byte order */ /* Preserve the address in network byte order */
argp->addr = *p++; argp->addr = *p++;
argp->vers = *p++;
argp->proto = *p++;
return xdr_argsize_check(rqstp, p); return xdr_argsize_check(rqstp, p);
} }
...@@ -602,15 +604,15 @@ static struct rpc_procinfo nlm_procedures[] = { ...@@ -602,15 +604,15 @@ static struct rpc_procinfo nlm_procedures[] = {
}; };
static struct rpc_version nlm_version1 = { static struct rpc_version nlm_version1 = {
number: 1, .number = 1,
nrprocs: 16, .nrprocs = 16,
procs: nlm_procedures, .procs = nlm_procedures,
}; };
static struct rpc_version nlm_version3 = { static struct rpc_version nlm_version3 = {
number: 3, .number = 3,
nrprocs: 24, .nrprocs = 24,
procs: nlm_procedures, .procs = nlm_procedures,
}; };
#ifdef CONFIG_LOCKD_V4 #ifdef CONFIG_LOCKD_V4
...@@ -618,23 +620,21 @@ extern struct rpc_version nlm_version4; ...@@ -618,23 +620,21 @@ extern struct rpc_version nlm_version4;
#endif #endif
static struct rpc_version * nlm_versions[] = { static struct rpc_version * nlm_versions[] = {
NULL, [1] = &nlm_version1,
&nlm_version1, [3] = &nlm_version3,
NULL,
&nlm_version3,
#ifdef CONFIG_LOCKD_V4 #ifdef CONFIG_LOCKD_V4
&nlm_version4, [4] = &nlm_version4,
#endif #endif
}; };
static struct rpc_stat nlm_stats; static struct rpc_stat nlm_stats;
struct rpc_program nlm_program = { struct rpc_program nlm_program = {
name: "lockd", .name = "lockd",
number: NLM_PROGRAM, .number = NLM_PROGRAM,
nrvers: sizeof(nlm_versions) / sizeof(nlm_versions[0]), .nrvers = sizeof(nlm_versions) / sizeof(nlm_versions[0]),
version: nlm_versions, .version = nlm_versions,
stats: &nlm_stats, .stats = &nlm_stats,
}; };
#ifdef LOCKD_DEBUG #ifdef LOCKD_DEBUG
......
...@@ -608,7 +608,7 @@ static struct rpc_procinfo nlm4_procedures[] = { ...@@ -608,7 +608,7 @@ static struct rpc_procinfo nlm4_procedures[] = {
}; };
struct rpc_version nlm_version4 = { struct rpc_version nlm_version4 = {
number: 4, .number = 4,
nrprocs: 24, .nrprocs = 24,
procs: nlm4_procedures, .procs = nlm4_procedures,
}; };
...@@ -35,10 +35,6 @@ ...@@ -35,10 +35,6 @@
typedef struct svc_client svc_client; typedef struct svc_client svc_client;
typedef struct svc_export svc_export; typedef struct svc_export svc_export;
static svc_export * exp_parent(svc_client *clp, struct super_block *sb,
struct dentry *dentry);
static svc_export * exp_child(svc_client *clp, struct super_block *sb,
struct dentry *dentry);
static void exp_unexport_all(svc_client *clp); static void exp_unexport_all(svc_client *clp);
static void exp_do_unexport(svc_export *unexp); static void exp_do_unexport(svc_export *unexp);
static svc_client * exp_getclientbyname(char *name); static svc_client * exp_getclientbyname(char *name);
...@@ -51,9 +47,25 @@ static int exp_verify_string(char *cp, int max); ...@@ -51,9 +47,25 @@ static int exp_verify_string(char *cp, int max);
#define CLIENT_HASHMASK (CLIENT_HASHMAX - 1) #define CLIENT_HASHMASK (CLIENT_HASHMAX - 1)
#define CLIENT_HASH(a) \ #define CLIENT_HASH(a) \
((((a)>>24) ^ ((a)>>16) ^ ((a)>>8) ^(a)) & CLIENT_HASHMASK) ((((a)>>24) ^ ((a)>>16) ^ ((a)>>8) ^(a)) & CLIENT_HASHMASK)
/* XXX: is this adequate for 32bit kdev_t ? */
#define EXPORT_HASH(dev) (MINOR(dev) & (NFSCLNT_EXPMAX - 1)) #define EXPKEY_HASHBITS 8
#define EXPORT_FSID_HASH(fsid) ((fsid) & (NFSCLNT_EXPMAX - 1)) #define EXPKEY_HASHMAX (1 << EXPKEY_HASHBITS)
#define EXPKEY_HASHMASK (EXPKEY_HASHMAX -1)
static struct list_head expkey_table[EXPKEY_HASHMAX];
static inline int expkey_hash(struct svc_client *clp, int type, u32 *fsidv)
{
int hash = type;
char * cp = (char*)fsidv;
int len = (type==0)?8:4;
while (len--)
hash += *cp++;
cp = (char*)&clp;
len = sizeof(clp);
while (len--)
hash += *cp++;
return hash & EXPKEY_HASHMASK;
}
struct svc_clnthash { struct svc_clnthash {
struct svc_clnthash * h_next; struct svc_clnthash * h_next;
...@@ -63,123 +75,131 @@ struct svc_clnthash { ...@@ -63,123 +75,131 @@ 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;
/* hash table of exports indexed by dentry+client */
#define EXPORT_HASHBITS 8
#define EXPORT_HASHMAX (1<< EXPORT_HASHBITS)
#define EXPORT_HASHMASK (EXPORT_HASHMAX -1)
struct list_head export_table[EXPORT_HASHMAX];
static int export_hash(svc_client *clp, struct dentry *dentry)
{
void *k[2];
unsigned char *cp;
int rv, i;
k[0] = clp;
k[1] = dentry;
cp = (char*)k;
rv = 0;
for (i=0; i<sizeof(k); i++)
rv ^= cp[i];
return rv & EXPORT_HASHMASK;
}
struct svc_expkey *
exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv)
{
struct list_head *head;
struct svc_expkey *ek;
if (!clp)
return NULL;
head = &expkey_table[expkey_hash(clp, fsid_type, fsidv)];
list_for_each_entry(ek, head, ek_hash)
if (ek->ek_fsidtype == fsid_type &&
fsidv[0] == ek->ek_fsid[0] &&
(fsid_type == 1 || fsidv[1] == ek->ek_fsid[1]) &&
clp == ek->ek_client)
return ek;
return NULL;
}
/* /*
* Find the client's export entry matching xdev/xino. * Find the client's export entry matching xdev/xino.
*/ */
svc_export * static inline struct svc_expkey *
exp_get(svc_client *clp, dev_t dev, ino_t ino) exp_get_key(svc_client *clp, dev_t dev, ino_t ino)
{ {
struct list_head *head, *p; u32 fsidv[2];
if (!clp) mk_fsid_v0(fsidv, dev, ino);
return NULL; return exp_find_key(clp, 0, fsidv);
}
head = &clp->cl_export[EXPORT_HASH(dev)]; static inline svc_export *
list_for_each(p, head) { exp_get(svc_client *clp, dev_t dev, ino_t ino)
svc_export *exp = list_entry(p, svc_export, ex_hash); {
if (exp->ex_ino == ino && exp->ex_dev == dev) struct svc_expkey *ek;
return exp;
} ek = exp_get_key(clp, dev, ino);
if (ek)
return ek->ek_export;
else
return NULL; return NULL;
} }
/* /*
* Find the client's export entry matching fsid * Find the client's export entry matching fsid
*/ */
svc_export * static inline struct svc_expkey *
exp_get_fsid(svc_client *clp, int fsid) exp_get_fsid_key(svc_client *clp, int fsid)
{ {
struct list_head *head, *p; u32 fsidv[2];
mk_fsid_v1(fsidv, fsid);
if (!clp) return exp_find_key(clp, 1, fsidv);
return NULL; }
head = &clp->cl_expfsid[EXPORT_FSID_HASH(fsid)]; static inline svc_export *
list_for_each(p, head) { exp_get_fsid(svc_client *clp, int fsid)
svc_export *exp = list_entry(p, svc_export, ex_fsid_hash); {
if (exp->ex_fsid == fsid) struct svc_expkey *ek;
return exp;
} ek = exp_get_fsid_key(clp, fsid);
if (ek)
return ek->ek_export;
else
return NULL; return NULL;
} }
svc_export * svc_export *
exp_get_by_name(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry) exp_get_by_name(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry)
{ {
struct list_head *head, *p; svc_export *exp;
int hash = EXPORT_HASH(mnt->mnt_sb->s_dev); struct list_head *head = &export_table[export_hash(clp, dentry)];
if (!clp) if (!clp)
return NULL; return NULL;
head = &clp->cl_export[hash]; list_for_each_entry(exp, head, ex_hash) {
list_for_each(p, head) { if (exp->ex_dentry == dentry &&
svc_export *exp = list_entry(p, svc_export, ex_hash); exp->ex_mnt == mnt &&
if (exp->ex_dentry == dentry && exp->ex_mnt == mnt) exp->ex_client == clp)
break;
}
return NULL;
}
/*
* Find the export entry for a given dentry. <gam3@acm.org>
*/
static svc_export *
exp_parent(svc_client *clp, struct super_block *sb, struct dentry *dentry)
{
struct list_head *head = &clp->cl_export[EXPORT_HASH(sb->s_dev)];
struct list_head *p;
spin_lock(&dcache_lock);
list_for_each(p, head) {
svc_export *exp = list_entry(p, svc_export, ex_hash);
if (is_subdir(dentry, exp->ex_dentry)) {
spin_unlock(&dcache_lock);
return exp; return exp;
} }
}
spin_unlock(&dcache_lock);
return NULL; return NULL;
} }
/* /*
* Find the child export entry for a given fs. This function is used * Find the export entry for a given dentry.
* only by the export syscall to keep the export tree consistent.
* <gam3@acm.org>
*/ */
static svc_export * struct svc_export *
exp_child(svc_client *clp, struct super_block *sb, struct dentry *dentry) exp_parent(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry)
{
struct list_head *head = &clp->cl_export[EXPORT_HASH(sb->s_dev)];
struct list_head *p;
struct dentry *ndentry;
spin_lock(&dcache_lock);
list_for_each(p, head) {
svc_export *exp = list_entry(p, svc_export, ex_hash);
ndentry = exp->ex_dentry;
if (ndentry && is_subdir(ndentry->d_parent, dentry)) {
spin_unlock(&dcache_lock);
return exp;
}
}
spin_unlock(&dcache_lock);
return NULL;
}
/* Update parent pointers of all exports */
static void exp_change_parents(svc_client *clp, svc_export *old, svc_export *new)
{ {
struct list_head *head = &clp->cl_list; svc_export *exp;
struct list_head *p;
list_for_each(p, head) { read_lock(&dparent_lock);
svc_export *exp = list_entry(p, svc_export, ex_list); exp = exp_get_by_name(clp, mnt, dentry);
if (exp->ex_parent == old) while (exp == NULL && dentry != dentry->d_parent) {
exp->ex_parent = new; dentry = dentry->d_parent;
exp = exp_get_by_name(clp, mnt, dentry);
} }
read_unlock(&dparent_lock);
return exp;
} }
/* /*
...@@ -217,21 +237,73 @@ exp_writeunlock(void) ...@@ -217,21 +237,73 @@ exp_writeunlock(void)
static void exp_fsid_unhash(struct svc_export *exp) static void exp_fsid_unhash(struct svc_export *exp)
{ {
struct svc_expkey *ek;
if ((exp->ex_flags & NFSEXP_FSID) == 0) if ((exp->ex_flags & NFSEXP_FSID) == 0)
return; return;
list_del_init(&exp->ex_fsid_hash); ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid);
if (ek) {
list_del(&ek->ek_hash);
kfree(ek);
}
} }
static void exp_fsid_hash(struct svc_client *clp, struct svc_export *exp) static int exp_fsid_hash(struct svc_client *clp, struct svc_export *exp)
{ {
struct list_head *head; struct list_head *head;
struct svc_expkey *ek;
if ((exp->ex_flags & NFSEXP_FSID) == 0) if ((exp->ex_flags & NFSEXP_FSID) == 0)
return; return 0;
head = clp->cl_expfsid + EXPORT_FSID_HASH(exp->ex_fsid);
list_add(&exp->ex_fsid_hash, head); ek = kmalloc(sizeof(*ek), GFP_KERNEL);
if (ek == NULL)
return -ENOMEM;
ek->ek_fsidtype = 1;
ek->ek_export = exp;
ek->ek_client = clp;
mk_fsid_v1(ek->ek_fsid, exp->ex_fsid);
head = &expkey_table[expkey_hash(clp, 1, ek->ek_fsid)];
list_add(&ek->ek_hash, head);
return 0;
}
static int exp_hash(struct svc_client *clp, struct svc_export *exp)
{
struct list_head *head;
struct svc_expkey *ek;
struct inode *inode;
ek = kmalloc(sizeof(*ek), GFP_KERNEL);
if (ek == NULL)
return -ENOMEM;
ek->ek_fsidtype = 0;
ek->ek_export = exp;
ek->ek_client = clp;
inode = exp->ex_dentry->d_inode;
mk_fsid_v0(ek->ek_fsid, inode->i_sb->s_dev, inode->i_ino);
head = &expkey_table[expkey_hash(clp, 0, ek->ek_fsid)];
list_add(&ek->ek_hash, head);
return 0;
}
static void exp_unhash(struct svc_export *exp)
{
struct svc_expkey *ek;
struct inode *inode = exp->ex_dentry->d_inode;
ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino);
if (ek) {
list_del(&ek->ek_hash);
kfree(ek);
}
} }
extern struct dentry * extern struct dentry *
...@@ -245,13 +317,11 @@ int ...@@ -245,13 +317,11 @@ int
exp_export(struct nfsctl_export *nxp) exp_export(struct nfsctl_export *nxp)
{ {
svc_client *clp; svc_client *clp;
svc_export *exp = NULL, *parent; svc_export *exp = NULL;
svc_export *fsid_exp; svc_export *fsid_exp;
struct nameidata nd; struct nameidata nd;
struct inode *inode = NULL; struct inode *inode = NULL;
int err; int err;
dev_t dev;
ino_t ino;
/* Consistency check */ /* Consistency check */
err = -EINVAL; err = -EINVAL;
...@@ -276,11 +346,9 @@ exp_export(struct nfsctl_export *nxp) ...@@ -276,11 +346,9 @@ exp_export(struct nfsctl_export *nxp)
if (err) if (err)
goto out_unlock; goto out_unlock;
inode = nd.dentry->d_inode; inode = nd.dentry->d_inode;
dev = inode->i_sb->s_dev;
ino = inode->i_ino;
err = -EINVAL; err = -EINVAL;
exp = exp_get(clp, dev, ino); exp = exp_get_by_name(clp, nd.mnt, nd.dentry);
/* must make sure there wont be an ex_fsid clash */ /* must make sure there wont be an ex_fsid clash */
if ((nxp->ex_flags & NFSEXP_FSID) && if ((nxp->ex_flags & NFSEXP_FSID) &&
...@@ -296,8 +364,8 @@ exp_export(struct nfsctl_export *nxp) ...@@ -296,8 +364,8 @@ exp_export(struct nfsctl_export *nxp)
exp->ex_anon_uid = nxp->ex_anon_uid; exp->ex_anon_uid = nxp->ex_anon_uid;
exp->ex_anon_gid = nxp->ex_anon_gid; exp->ex_anon_gid = nxp->ex_anon_gid;
exp->ex_fsid = nxp->ex_dev; exp->ex_fsid = nxp->ex_dev;
exp_fsid_hash(clp, exp);
err = 0; err = exp_fsid_hash(clp, exp);
goto finish; goto finish;
} }
...@@ -332,45 +400,30 @@ exp_export(struct nfsctl_export *nxp) ...@@ -332,45 +400,30 @@ exp_export(struct nfsctl_export *nxp)
inode->i_sb->s_export_op->find_exported_dentry = inode->i_sb->s_export_op->find_exported_dentry =
find_exported_dentry; find_exported_dentry;
if ((parent = exp_child(clp, inode->i_sb, nd.dentry)) != NULL) {
dprintk("exp_export: export not valid (Rule 3).\n");
goto finish;
}
/* Is this is a sub-export, must be a proper subset of FS */
if ((parent = exp_parent(clp, inode->i_sb, nd.dentry)) != NULL) {
dprintk("exp_export: sub-export not valid (Rule 2).\n");
goto finish;
}
err = -ENOMEM; err = -ENOMEM;
if (!(exp = kmalloc(sizeof(*exp), GFP_USER))) if (!(exp = kmalloc(sizeof(*exp), GFP_USER)))
goto finish; goto finish;
dprintk("nfsd: created export entry %p for client %p\n", exp, clp); dprintk("nfsd: created export entry %p for client %p\n", exp, clp);
strcpy(exp->ex_path, nxp->ex_path);
exp->ex_client = clp; exp->ex_client = clp;
exp->ex_parent = parent;
exp->ex_mnt = mntget(nd.mnt); exp->ex_mnt = mntget(nd.mnt);
exp->ex_dentry = dget(nd.dentry); exp->ex_dentry = dget(nd.dentry);
exp->ex_flags = nxp->ex_flags; exp->ex_flags = nxp->ex_flags;
exp->ex_dev = dev;
exp->ex_ino = ino;
exp->ex_anon_uid = nxp->ex_anon_uid; exp->ex_anon_uid = nxp->ex_anon_uid;
exp->ex_anon_gid = nxp->ex_anon_gid; exp->ex_anon_gid = nxp->ex_anon_gid;
exp->ex_fsid = nxp->ex_dev; exp->ex_fsid = nxp->ex_dev;
list_add_tail(&exp->ex_hash,
/* Update parent pointers of all exports */ &export_table[export_hash(clp, nd.dentry)]);
if (parent)
exp_change_parents(clp, parent, exp);
list_add(&exp->ex_hash, clp->cl_export + EXPORT_HASH(dev));
list_add_tail(&exp->ex_list, &clp->cl_list);
exp_fsid_hash(clp, exp);
err = 0; err = 0;
if (exp_hash(clp, exp) ||
exp_fsid_hash(clp, exp)) {
/* failed to create at least one index */
exp_do_unexport(exp);
err = -ENOMEM;
}
finish: finish:
path_release(&nd); path_release(&nd);
out_unlock: out_unlock:
...@@ -390,16 +443,12 @@ exp_do_unexport(svc_export *unexp) ...@@ -390,16 +443,12 @@ exp_do_unexport(svc_export *unexp)
struct vfsmount *mnt; struct vfsmount *mnt;
struct inode *inode; struct inode *inode;
list_del(&unexp->ex_list);
list_del(&unexp->ex_hash); list_del(&unexp->ex_hash);
exp_unhash(unexp);
exp_fsid_unhash(unexp); exp_fsid_unhash(unexp);
/* Update parent pointers. */
exp_change_parents(unexp->ex_client, unexp, unexp->ex_parent);
dentry = unexp->ex_dentry; dentry = unexp->ex_dentry;
mnt = unexp->ex_mnt; mnt = unexp->ex_mnt;
inode = dentry->d_inode; inode = dentry->d_inode;
if (unexp->ex_dev != inode->i_sb->s_dev || unexp->ex_ino != inode->i_ino)
printk(KERN_WARNING "nfsd: bad dentry in unexport!\n");
dput(dentry); dput(dentry);
mntput(mnt); mntput(mnt);
...@@ -412,12 +461,15 @@ exp_do_unexport(svc_export *unexp) ...@@ -412,12 +461,15 @@ exp_do_unexport(svc_export *unexp)
static void static void
exp_unexport_all(svc_client *clp) exp_unexport_all(svc_client *clp)
{ {
struct list_head *p = &clp->cl_list; struct list_head *lp, *tmp;
int index;
dprintk("unexporting all fs's for clnt %p\n", clp); dprintk("unexporting all fs's for clnt %p\n", clp);
while (!list_empty(p)) { for (index=0; index<EXPORT_HASHMAX; index++)
svc_export *exp = list_entry(p->next, svc_export, ex_list); list_for_each_safe(lp, tmp, &export_table[index]) {
svc_export *exp = list_entry(lp, struct svc_export, ex_hash);
if (exp->ex_client == clp)
exp_do_unexport(exp); exp_do_unexport(exp);
} }
} }
...@@ -476,7 +528,7 @@ exp_rootfh(struct svc_client *clp, char *path, struct knfsd_fh *f, int maxsize) ...@@ -476,7 +528,7 @@ exp_rootfh(struct svc_client *clp, char *path, struct knfsd_fh *f, int maxsize)
dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n", dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n",
path, nd.dentry, clp->cl_ident, path, nd.dentry, clp->cl_ident,
inode->i_sb->s_id, inode->i_ino); inode->i_sb->s_id, inode->i_ino);
exp = exp_parent(clp, inode->i_sb, nd.dentry); exp = exp_parent(clp, nd.mnt, nd.dentry);
if (!exp) { if (!exp) {
dprintk("nfsd: exp_rootfh export not found.\n"); dprintk("nfsd: exp_rootfh export not found.\n");
goto out; goto out;
...@@ -555,56 +607,52 @@ exp_getclientbyname(char *ident) ...@@ -555,56 +607,52 @@ exp_getclientbyname(char *ident)
static void *e_start(struct seq_file *m, loff_t *pos) static void *e_start(struct seq_file *m, loff_t *pos)
{ {
loff_t n = *pos; loff_t n = *pos;
unsigned client, export; unsigned hash, export;
svc_client *clp; svc_export *exp;
struct list_head *p;
exp_readlock(); exp_readlock();
if (!n--) if (!n--)
return (void *)1; return (void *)1;
client = n >> 32; hash = n >> 32;
export = n & ((1LL<<32) - 1); export = n & ((1LL<<32) - 1);
for (clp = clients; client && clp; clp = clp->cl_next, client--)
; list_for_each_entry(exp, &export_table[hash], ex_hash)
if (!clp)
return NULL;
list_for_each(p, &clp->cl_list)
if (!export--) if (!export--)
return list_entry(p, svc_export, ex_list); return exp;
n &= ~((1LL<<32) - 1); n &= ~((1LL<<32) - 1);
do { do {
clp = clp->cl_next; hash++;
n += 1LL<<32; n += 1LL<<32;
} while(clp && list_empty(&clp->cl_list)); } while(hash < EXPORT_HASHMAX && list_empty(&export_table[hash]));
if (!clp) if (hash >= EXPORT_HASHMAX)
return NULL; return NULL;
*pos = n+1; *pos = n+1;
return list_entry(clp->cl_list.next, svc_export, ex_list); return list_entry(export_table[hash].next, svc_export, ex_hash);
} }
static void *e_next(struct seq_file *m, void *p, loff_t *pos) static void *e_next(struct seq_file *m, void *p, loff_t *pos)
{ {
svc_export *exp = p; svc_export *exp = p;
svc_client *clp; int hash = (*pos >> 32);
if (p == (void *)1) if (p == (void *)1)
clp = clients; hash = 0;
else if (exp->ex_list.next == &exp->ex_client->cl_list) { else if (exp->ex_hash.next == &export_table[hash]) {
clp = exp->ex_client->cl_next; hash++;
*pos += 1LL<<32; *pos += 1LL<<32;
} else { } else {
++*pos; ++*pos;
return list_entry(exp->ex_list.next, svc_export, ex_list); return list_entry(exp->ex_hash.next, svc_export, ex_hash);
} }
*pos &= ~((1LL<<32) - 1); *pos &= ~((1LL<<32) - 1);
while (clp && list_empty(&clp->cl_list)) { while (hash < EXPORT_HASHMAX && list_empty(&export_table[hash])) {
clp = clp->cl_next; hash++;
*pos += 1LL<<32; *pos += 1LL<<32;
} }
if (!clp) if (hash >= EXPORT_HASHMAX)
return NULL; return NULL;
++*pos; ++*pos;
return list_entry(clp->cl_list.next, svc_export, ex_list); return list_entry(export_table[hash].next, svc_export, ex_hash);
} }
static void e_stop(struct seq_file *m, void *p) static void e_stop(struct seq_file *m, void *p)
...@@ -634,7 +682,7 @@ struct flags { ...@@ -634,7 +682,7 @@ struct flags {
{ 0, {"", ""}} { 0, {"", ""}}
}; };
static void exp_flags(struct seq_file *m, int flag, int fsid) static void exp_flags(struct seq_file *m, int flag, int fsid, uid_t anonu, uid_t anong)
{ {
int first = 0; int first = 0;
struct flags *flg; struct flags *flg;
...@@ -646,6 +694,10 @@ static void exp_flags(struct seq_file *m, int flag, int fsid) ...@@ -646,6 +694,10 @@ static void exp_flags(struct seq_file *m, int flag, int fsid)
} }
if (flag & NFSEXP_FSID) if (flag & NFSEXP_FSID)
seq_printf(m, "%sfsid=%d", first++?",":"", fsid); seq_printf(m, "%sfsid=%d", first++?",":"", fsid);
if (anonu != (uid_t)-2 && anonu != (0x10000-2))
seq_printf(m, "%sanonuid=%d", first++?",":"", anonu);
if (anong != (gid_t)-2 && anong != (0x10000-2))
seq_printf(m, "%sanongid=%d", first++?",":"", anong);
} }
static inline void mangle(struct seq_file *m, const char *s) static inline void mangle(struct seq_file *m, const char *s)
...@@ -657,7 +709,7 @@ static int e_show(struct seq_file *m, void *p) ...@@ -657,7 +709,7 @@ static int e_show(struct seq_file *m, void *p)
{ {
struct svc_export *exp = p; struct svc_export *exp = p;
struct svc_client *clp; struct svc_client *clp;
int j, first = 0; char *pbuf;
if (p == (void *)1) { if (p == (void *)1) {
seq_puts(m, "# Version 1.1\n"); seq_puts(m, "# Version 1.1\n");
...@@ -667,36 +719,16 @@ static int e_show(struct seq_file *m, void *p) ...@@ -667,36 +719,16 @@ static int e_show(struct seq_file *m, void *p)
clp = exp->ex_client; clp = exp->ex_client;
mangle(m, exp->ex_path); pbuf = m->private;
mangle(m, d_path(exp->ex_dentry, exp->ex_mnt,
pbuf, PAGE_SIZE));
seq_putc(m, '\t'); seq_putc(m, '\t');
mangle(m, clp->cl_ident); mangle(m, clp->cl_ident);
seq_putc(m, '('); seq_putc(m, '(');
exp_flags(m, exp->ex_flags, exp->ex_fsid); exp_flags(m, exp->ex_flags, exp->ex_fsid,
seq_puts(m, ") # "); exp->ex_anon_uid, exp->ex_anon_gid);
for (j = 0; j < clp->cl_naddr; j++) { seq_puts(m, ")\n");
struct svc_clnthash **hp, **head, *tmp;
struct in_addr addr = clp->cl_addr[j];
head = &clnt_hash[CLIENT_HASH(addr.s_addr)];
for (hp = head; (tmp = *hp) != NULL; hp = &(tmp->h_next)) {
if (tmp->h_addr.s_addr == addr.s_addr)
break;
}
if (tmp) {
if (first++)
seq_putc(m, ' ');
if (tmp->h_client != clp)
seq_putc(m, '(');
seq_printf(m, "%d.%d.%d.%d",
htonl(addr.s_addr) >> 24 & 0xff,
htonl(addr.s_addr) >> 16 & 0xff,
htonl(addr.s_addr) >> 8 & 0xff,
htonl(addr.s_addr) >> 0 & 0xff);
if (tmp->h_client != clp)
seq_putc(m, ')');
}
}
seq_putc(m, '\n');
return 0; return 0;
} }
...@@ -741,16 +773,10 @@ exp_addclient(struct nfsctl_client *ncp) ...@@ -741,16 +773,10 @@ exp_addclient(struct nfsctl_client *ncp)
if (!(clp = kmalloc(sizeof(*clp), GFP_KERNEL))) if (!(clp = kmalloc(sizeof(*clp), GFP_KERNEL)))
goto out_unlock; goto out_unlock;
memset(clp, 0, sizeof(*clp)); memset(clp, 0, sizeof(*clp));
for (i = 0; i < NFSCLNT_EXPMAX; i++) {
INIT_LIST_HEAD(&clp->cl_export[i]);
INIT_LIST_HEAD(&clp->cl_expfsid[i]);
}
INIT_LIST_HEAD(&clp->cl_list);
dprintk("created client %s (%p)\n", ncp->cl_ident, clp); dprintk("created client %s (%p)\n", ncp->cl_ident, clp);
strcpy(clp->cl_ident, ncp->cl_ident); strcpy(clp->cl_ident, ncp->cl_ident);
clp->cl_idlen = ilen;
} }
/* Allocate hash buckets */ /* Allocate hash buckets */
...@@ -765,19 +791,13 @@ exp_addclient(struct nfsctl_client *ncp) ...@@ -765,19 +791,13 @@ exp_addclient(struct nfsctl_client *ncp)
} }
} }
/* Copy addresses. */
for (i = 0; i < ncp->cl_naddr; i++) {
clp->cl_addr[i] = ncp->cl_addrlist[i];
}
clp->cl_naddr = ncp->cl_naddr;
/* Remove old client hash entries. */ /* Remove old client hash entries. */
if (change) if (change)
exp_unhashclient(clp); exp_unhashclient(clp);
/* Insert client into hashtable. */ /* Insert client into hashtable. */
for (i = 0; i < ncp->cl_naddr; i++) { for (i = 0; i < ncp->cl_naddr; i++) {
struct in_addr addr = clp->cl_addr[i]; struct in_addr addr = ncp->cl_addrlist[i];
int hash; int hash;
hash = CLIENT_HASH(addr.s_addr); hash = CLIENT_HASH(addr.s_addr);
...@@ -838,9 +858,7 @@ exp_freeclient(svc_client *clp) ...@@ -838,9 +858,7 @@ exp_freeclient(svc_client *clp)
{ {
exp_unhashclient(clp); exp_unhashclient(clp);
/* umap_free(&(clp->cl_umap)); */
exp_unexport_all(clp); exp_unexport_all(clp);
nfsd_lockd_unexport(clp);
kfree (clp); kfree (clp);
} }
...@@ -869,26 +887,12 @@ exp_unhashclient(svc_client *clp) ...@@ -869,26 +887,12 @@ exp_unhashclient(svc_client *clp)
} }
} }
} }
if (count != clp->cl_naddr)
printk(KERN_WARNING "nfsd: bad address count in freeclient!\n");
if (err) if (err)
goto again; goto again;
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
kfree (ch[i]); kfree (ch[i]);
} }
/*
* Lockd is shutting down and tells us to unregister all clients
*/
void
exp_nlmdetach(void)
{
struct svc_client *clp;
for (clp = clients; clp; clp = clp->cl_next)
nfsd_lockd_unexport(clp);
}
/* /*
* Verify that string is non-empty and does not exceed max length. * Verify that string is non-empty and does not exceed max length.
*/ */
...@@ -919,6 +923,12 @@ nfsd_export_init(void) ...@@ -919,6 +923,12 @@ nfsd_export_init(void)
clnt_hash[i] = NULL; clnt_hash[i] = NULL;
clients = NULL; clients = NULL;
for (i = 0; i < EXPORT_HASHMAX ; i++)
INIT_LIST_HEAD(&export_table[i]);
for (i = 0; i < EXPKEY_HASHMAX; i++)
INIT_LIST_HEAD(&expkey_table[i]);
} }
/* /*
......
...@@ -31,12 +31,19 @@ nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file *filp) ...@@ -31,12 +31,19 @@ nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file *filp)
memcpy((char*)&fh.fh_handle.fh_base, f->data, f->size); memcpy((char*)&fh.fh_handle.fh_base, f->data, f->size);
fh.fh_export = NULL; fh.fh_export = NULL;
exp_readlock();
rqstp->rq_client = exp_getclient(&rqstp->rq_addr);
if (rqstp->rq_client == NULL)
nfserr = nfserr_stale;
else
nfserr = nfsd_open(rqstp, &fh, S_IFREG, MAY_LOCK, filp); nfserr = nfsd_open(rqstp, &fh, S_IFREG, MAY_LOCK, filp);
if (!nfserr) { if (!nfserr) {
dget(filp->f_dentry); dget(filp->f_dentry);
mntget(filp->f_vfsmnt); mntget(filp->f_vfsmnt);
} }
fh_put(&fh); fh_put(&fh);
rqstp->rq_client = NULL;
exp_readunlock();
/* nlm and nfsd don't share error codes. /* nlm and nfsd don't share error codes.
* we invent: 0 = no error * we invent: 0 = no error
* 1 = stale file handle * 1 = stale file handle
...@@ -61,24 +68,10 @@ nlm_fclose(struct file *filp) ...@@ -61,24 +68,10 @@ nlm_fclose(struct file *filp)
} }
struct nlmsvc_binding nfsd_nlm_ops = { struct nlmsvc_binding nfsd_nlm_ops = {
.exp_readlock = exp_readlock, /* lock export table for reading */
.exp_unlock = exp_readunlock, /* unlock export table */
.exp_getclient = exp_getclient, /* look up NFS client */
.fopen = nlm_fopen, /* open file for locking */ .fopen = nlm_fopen, /* open file for locking */
.fclose = nlm_fclose, /* close file */ .fclose = nlm_fclose, /* close file */
.detach = exp_nlmdetach, /* lockd shutdown notification */
}; };
/*
* When removing an NFS client entry, notify lockd that it is gone.
* FIXME: We should do the same when unexporting an NFS volume.
*/
void
nfsd_lockd_unexport(struct svc_client *clnt)
{
nlmsvc_invalidate_client(clnt);
}
void void
nfsd_lockd_init(void) nfsd_lockd_init(void)
{ {
......
...@@ -127,13 +127,30 @@ static struct file_operations reader_ops = { ...@@ -127,13 +127,30 @@ static struct file_operations reader_ops = {
extern struct seq_operations nfs_exports_op; extern struct seq_operations nfs_exports_op;
static int exports_open(struct inode *inode, struct file *file) static int exports_open(struct inode *inode, struct file *file)
{ {
return seq_open(file, &nfs_exports_op); int res;
res = seq_open(file, &nfs_exports_op);
if (!res) {
char *namebuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (namebuf == NULL)
res = -ENOMEM;
else
((struct seq_file *)file->private_data)->private = namebuf;
}
return res;
} }
static int exports_release(struct inode *inode, struct file *file)
{
struct seq_file *m = (struct seq_file *)file->private_data;
kfree(m->private);
m->private = NULL;
return seq_release(inode, file);
}
static struct file_operations exports_operations = { static struct file_operations exports_operations = {
.open = exports_open, .open = exports_open,
.read = seq_read, .read = seq_read,
.llseek = seq_lseek, .llseek = seq_lseek,
.release = seq_release, .release = exports_release,
}; };
/* /*
......
...@@ -97,14 +97,10 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) ...@@ -97,14 +97,10 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
rqstp->rq_reffh = fh; rqstp->rq_reffh = fh;
if (!fhp->fh_dentry) { if (!fhp->fh_dentry) {
dev_t xdev = 0;
ino_t xino = 0;
__u32 *datap=NULL; __u32 *datap=NULL;
__u32 tfh[3]; /* filehandle fragment for oldstyle filehandles */ __u32 tfh[3]; /* filehandle fragment for oldstyle filehandles */
int fileid_type; int fileid_type;
int data_left = fh->fh_size/4; int data_left = fh->fh_size/4;
int nfsdev;
int fsid = 0;
error = nfserr_stale; error = nfserr_stale;
if (rqstp->rq_vers > 2) if (rqstp->rq_vers > 2)
...@@ -113,6 +109,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) ...@@ -113,6 +109,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
return nfserr_nofilehandle; return nfserr_nofilehandle;
if (fh->fh_version == 1) { if (fh->fh_version == 1) {
int len;
datap = fh->fh_auth; datap = fh->fh_auth;
if (--data_left<0) goto out; if (--data_left<0) goto out;
switch (fh->fh_auth_type) { switch (fh->fh_auth_type) {
...@@ -122,39 +119,37 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) ...@@ -122,39 +119,37 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
switch (fh->fh_fsid_type) { switch (fh->fh_fsid_type) {
case 0: case 0:
if ((data_left-=2)<0) goto out; len = 2;
nfsdev = ntohl(*datap++);
xdev = MKDEV(nfsdev>>16, nfsdev&0xFFFF);
xino = *datap++;
break; break;
case 1: case 1:
if ((data_left-=1)<0) goto out; len = 1;
fsid = *datap++;
break; break;
default: default:
goto out; goto out;
} }
if ((data_left -= len)<0) goto out;
exp = exp_find(rqstp->rq_client, fh->fh_fsid_type, datap);
datap += len;
} else { } else {
dev_t xdev;
ino_t xino;
if (fh->fh_size != NFS_FHSIZE) if (fh->fh_size != NFS_FHSIZE)
goto out; goto out;
/* assume old filehandle format */ /* assume old filehandle format */
xdev = u32_to_dev_t(fh->ofh_xdev); xdev = u32_to_dev_t(fh->ofh_xdev);
xino = u32_to_ino_t(fh->ofh_xino); xino = u32_to_ino_t(fh->ofh_xino);
mk_fsid_v0(tfh, xdev, xino);
exp = exp_find(rqstp->rq_client, 0, tfh);
} }
/* /*
* Look up the export entry. * Look up the export entry.
*/ */
error = nfserr_stale; error = nfserr_stale;
if (fh->fh_version == 1 && fh->fh_fsid_type == 1)
exp = exp_get_fsid(rqstp->rq_client, fsid);
else
exp = exp_get(rqstp->rq_client, xdev, xino);
if (!exp) { if (!exp)
/* export entry revoked */ /* export entry revoked */
goto out; goto out;
}
/* Check if the request originated from a secure port. */ /* Check if the request originated from a secure port. */
error = nfserr_perm; error = nfserr_perm;
...@@ -322,9 +317,11 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, st ...@@ -322,9 +317,11 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, st
struct inode * inode = dentry->d_inode; struct inode * inode = dentry->d_inode;
struct dentry *parent = dentry->d_parent; struct dentry *parent = dentry->d_parent;
__u32 *datap; __u32 *datap;
dev_t ex_dev = exp->ex_dentry->d_inode->i_sb->s_dev;
dprintk("nfsd: fh_compose(exp %02x:%02x/%ld %s/%s, ino=%ld)\n", dprintk("nfsd: fh_compose(exp %02x:%02x/%ld %s/%s, ino=%ld)\n",
MAJOR(exp->ex_dev), MINOR(exp->ex_dev), (long) exp->ex_ino, MAJOR(ex_dev), MINOR(ex_dev),
(long) exp->ex_dentry->d_inode->i_ino,
parent->d_name.name, dentry->d_name.name, parent->d_name.name, dentry->d_name.name,
(inode ? inode->i_ino : 0)); (inode ? inode->i_ino : 0));
...@@ -351,9 +348,9 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, st ...@@ -351,9 +348,9 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, st
memset(&fhp->fh_handle.fh_base, 0, NFS_FHSIZE); memset(&fhp->fh_handle.fh_base, 0, NFS_FHSIZE);
fhp->fh_handle.fh_size = NFS_FHSIZE; fhp->fh_handle.fh_size = NFS_FHSIZE;
fhp->fh_handle.ofh_dcookie = 0xfeebbaca; fhp->fh_handle.ofh_dcookie = 0xfeebbaca;
fhp->fh_handle.ofh_dev = htonl((MAJOR(exp->ex_dev)<<16)| MINOR(exp->ex_dev)); fhp->fh_handle.ofh_dev = htonl((MAJOR(ex_dev)<<16)| MINOR(ex_dev));
fhp->fh_handle.ofh_xdev = fhp->fh_handle.ofh_dev; fhp->fh_handle.ofh_xdev = fhp->fh_handle.ofh_dev;
fhp->fh_handle.ofh_xino = ino_t_to_u32(exp->ex_ino); fhp->fh_handle.ofh_xino = ino_t_to_u32(exp->ex_dentry->d_inode->i_ino);
fhp->fh_handle.ofh_dirino = ino_t_to_u32(parent_ino(dentry)); fhp->fh_handle.ofh_dirino = ino_t_to_u32(parent_ino(dentry));
if (inode) if (inode)
_fh_update_old(dentry, exp, &fhp->fh_handle); _fh_update_old(dentry, exp, &fhp->fh_handle);
...@@ -365,13 +362,14 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, st ...@@ -365,13 +362,14 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, st
(ref_fh_fsid_type == 1)) { (ref_fh_fsid_type == 1)) {
fhp->fh_handle.fh_fsid_type = 1; fhp->fh_handle.fh_fsid_type = 1;
/* fsid_type 1 == 4 bytes filesystem id */ /* fsid_type 1 == 4 bytes filesystem id */
*datap++ = exp->ex_fsid; mk_fsid_v1(datap, exp->ex_fsid);
datap += 1;
fhp->fh_handle.fh_size = 2*4; fhp->fh_handle.fh_size = 2*4;
} else { } else {
fhp->fh_handle.fh_fsid_type = 0; fhp->fh_handle.fh_fsid_type = 0;
/* fsid_type 0 == 2byte major, 2byte minor, 4byte inode */ /* fsid_type 0 == 2byte major, 2byte minor, 4byte inode */
*datap++ = htonl((MAJOR(exp->ex_dev)<<16)| MINOR(exp->ex_dev)); mk_fsid_v0(datap, ex_dev, exp->ex_dentry->d_inode->i_ino);
*datap++ = ino_t_to_u32(exp->ex_ino); datap += 2;
fhp->fh_handle.fh_size = 3*4; fhp->fh_handle.fh_size = 3*4;
} }
if (inode) { if (inode) {
......
...@@ -119,24 +119,24 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, ...@@ -119,24 +119,24 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
else { else {
/* checking mountpoint crossing is very different when stepping up */ /* checking mountpoint crossing is very different when stepping up */
struct svc_export *exp2 = NULL; struct svc_export *exp2 = NULL;
struct dentry *dp, *old; struct dentry *dp;
struct vfsmount *mnt = mntget(exp->ex_mnt); struct vfsmount *mnt = mntget(exp->ex_mnt);
dentry = dget(dparent); dentry = dget(dparent);
while(follow_up(&mnt, &dentry)) while(follow_up(&mnt, &dentry))
; ;
old = dentry;
read_lock(&dparent_lock); read_lock(&dparent_lock);
dp = dentry->d_parent; dp = dget(dentry->d_parent);
for ( ; !exp2 && dp->d_parent != dp; dp=dp->d_parent) read_unlock(&dparent_lock);
exp2 = exp_get_by_name(exp->ex_client, mnt, dp); dput(dentry);
dentry = dp;
exp2 = exp_parent(exp->ex_client, mnt, dentry);
if (!exp2) { if (!exp2) {
dput(dentry);
dentry = dget(dparent); dentry = dget(dparent);
} else { } else {
dget(dentry->d_parent);
exp = exp2; exp = exp2;
} }
read_unlock(&dparent_lock);
dput(old);
mntput(mnt); mntput(mnt);
} }
} else { } else {
......
...@@ -19,14 +19,10 @@ struct svc_client; /* opaque type */ ...@@ -19,14 +19,10 @@ struct svc_client; /* opaque type */
* This is the set of functions for lockd->nfsd communication * This is the set of functions for lockd->nfsd communication
*/ */
struct nlmsvc_binding { struct nlmsvc_binding {
void (*exp_readlock)(void);
void (*exp_unlock)(void);
struct svc_client * (*exp_getclient)(struct sockaddr_in *);
u32 (*fopen)(struct svc_rqst *, u32 (*fopen)(struct svc_rqst *,
struct nfs_fh *, struct nfs_fh *,
struct file *); struct file *);
void (*fclose)(struct file *); void (*fclose)(struct file *);
void (*detach)(void);
}; };
extern struct nlmsvc_binding * nlmsvc_ops; extern struct nlmsvc_binding * nlmsvc_ops;
...@@ -34,7 +30,6 @@ extern struct nlmsvc_binding * nlmsvc_ops; ...@@ -34,7 +30,6 @@ extern struct nlmsvc_binding * nlmsvc_ops;
/* /*
* Functions exported by the lockd module * Functions exported by the lockd module
*/ */
extern void nlmsvc_invalidate_client(struct svc_client *clnt);
extern int nlmclnt_proc(struct inode *, int, struct file_lock *); extern int nlmclnt_proc(struct inode *, int, struct file_lock *);
extern int lockd_up(void); extern int lockd_up(void);
extern void lockd_down(void); extern void lockd_down(void);
......
...@@ -39,13 +39,13 @@ ...@@ -39,13 +39,13 @@
struct nlm_host { struct nlm_host {
struct nlm_host * h_next; /* linked list (hash table) */ struct nlm_host * h_next; /* linked list (hash table) */
struct sockaddr_in h_addr; /* peer address */ struct sockaddr_in h_addr; /* peer address */
struct svc_client * h_exportent; /* NFS client */
struct rpc_clnt * h_rpcclnt; /* RPC client to talk to peer */ struct rpc_clnt * h_rpcclnt; /* RPC client to talk to peer */
char h_name[20]; /* remote hostname */ char h_name[20]; /* remote hostname */
u32 h_version; /* interface version */ u32 h_version; /* interface version */
unsigned short h_proto; /* transport proto */ unsigned short h_proto; /* transport proto */
unsigned short h_authflavor; /* RPC authentication type */ unsigned short h_authflavor; /* RPC authentication type */
unsigned short h_reclaiming : 1, unsigned short h_reclaiming : 1,
h_server : 1, /* server side, not client side */
h_inuse : 1, h_inuse : 1,
h_killed : 1, h_killed : 1,
h_monitored : 1; h_monitored : 1;
...@@ -143,13 +143,14 @@ void nlmclnt_freegrantargs(struct nlm_rqst *); ...@@ -143,13 +143,14 @@ void nlmclnt_freegrantargs(struct nlm_rqst *);
*/ */
struct nlm_host * nlmclnt_lookup_host(struct sockaddr_in *, int, int); struct nlm_host * nlmclnt_lookup_host(struct sockaddr_in *, int, int);
struct nlm_host * nlmsvc_lookup_host(struct svc_rqst *); struct nlm_host * nlmsvc_lookup_host(struct svc_rqst *);
struct nlm_host * nlm_lookup_host(struct svc_client *, struct nlm_host * nlm_lookup_host(int server, struct sockaddr_in *, int, int);
struct sockaddr_in *, int, int);
struct rpc_clnt * nlm_bind_host(struct nlm_host *); struct rpc_clnt * nlm_bind_host(struct nlm_host *);
void nlm_rebind_host(struct nlm_host *); void nlm_rebind_host(struct nlm_host *);
struct nlm_host * nlm_get_host(struct nlm_host *); struct nlm_host * nlm_get_host(struct nlm_host *);
void nlm_release_host(struct nlm_host *); void nlm_release_host(struct nlm_host *);
void nlm_shutdown_hosts(void); void nlm_shutdown_hosts(void);
extern struct nlm_host *nlm_find_client(void);
/* /*
* Server-side lock handling * Server-side lock handling
...@@ -173,6 +174,7 @@ u32 nlm_lookup_file(struct svc_rqst *, struct nlm_file **, ...@@ -173,6 +174,7 @@ u32 nlm_lookup_file(struct svc_rqst *, struct nlm_file **,
void nlm_release_file(struct nlm_file *); void nlm_release_file(struct nlm_file *);
void nlmsvc_mark_resources(void); 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);
static __inline__ struct inode * static __inline__ struct inode *
nlmsvc_file_inode(struct nlm_file *file) nlmsvc_file_inode(struct nlm_file *file)
......
...@@ -28,6 +28,7 @@ struct nsm_args { ...@@ -28,6 +28,7 @@ struct nsm_args {
u32 prog; /* RPC callback info */ u32 prog; /* RPC callback info */
u32 vers; u32 vers;
u32 proc; u32 proc;
u32 proto; /* protocol (udp/tcp) plus server/client flag */
}; };
/* /*
......
...@@ -76,6 +76,8 @@ struct nlm_reboot { ...@@ -76,6 +76,8 @@ struct nlm_reboot {
int len; int len;
u32 state; u32 state;
u32 addr; u32 addr;
u32 vers;
u32 proto;
}; };
/* /*
......
...@@ -23,23 +23,5 @@ ...@@ -23,23 +23,5 @@
*/ */
void nfsd_setuser(struct svc_rqst *, struct svc_export *); void nfsd_setuser(struct svc_rqst *, struct svc_export *);
#if 0
/*
* These must match the actual size of uid_t and gid_t
*/
#define UGID_BITS (8 * sizeof(uid_t))
#define UGID_SHIFT 8
#define UGID_MASK ((1 << UGID_SHIFT) - 1)
#define UGID_NRENTRIES ((1 << (UGID_BITS - UGID_SHIFT)) + 1)
#define UGID_NONE ((unsigned short)-1)
typedef struct svc_uidmap {
uid_t * um_ruid[UGID_NRENTRIES];
uid_t * um_luid[UGID_NRENTRIES];
gid_t * um_rgid[UGID_NRENTRIES];
gid_t * um_lgid[UGID_NRENTRIES];
} svc_uidmap;
#endif
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* LINUX_NFSD_AUTH_H */ #endif /* LINUX_NFSD_AUTH_H */
...@@ -45,38 +45,36 @@ ...@@ -45,38 +45,36 @@
#ifdef __KERNEL__ #ifdef __KERNEL__
/* The following are hashtable sizes and must be powers of 2 */
#define NFSCLNT_EXPMAX 16
struct svc_client { struct svc_client {
struct svc_client * cl_next; struct svc_client * cl_next;
char cl_ident[NFSCLNT_IDMAX]; char cl_ident[NFSCLNT_IDMAX];
int cl_idlen;
int cl_naddr;
struct in_addr cl_addr[NFSCLNT_ADDRMAX];
struct svc_uidmap * cl_umap;
struct list_head cl_export[NFSCLNT_EXPMAX];
struct list_head cl_expfsid[NFSCLNT_EXPMAX];
struct list_head cl_list;
}; };
struct svc_export { struct svc_export {
struct list_head ex_hash; struct list_head ex_hash;
struct list_head ex_fsid_hash;
struct list_head ex_list;
char ex_path[NFS_MAXPATHLEN+1];
struct svc_export * ex_parent;
struct svc_client * ex_client; struct svc_client * ex_client;
int ex_flags; int ex_flags;
struct vfsmount * ex_mnt; struct vfsmount * ex_mnt;
struct dentry * ex_dentry; struct dentry * ex_dentry;
dev_t ex_dev;
ino_t ex_ino;
uid_t ex_anon_uid; uid_t ex_anon_uid;
gid_t ex_anon_gid; gid_t ex_anon_gid;
int ex_fsid; int ex_fsid;
}; };
/* an "export key" (expkey) maps a filehandlefragement to an
* svc_export for a given client. There can be two per export, one
* for type 0 (dev/ino), one for type 1 (fsid)
*/
struct svc_expkey {
struct list_head ek_hash;
struct svc_client *ek_client;
int ek_fsidtype;
u32 ek_fsid[2];
struct svc_export *ek_export;
};
#define EX_SECURE(exp) (!((exp)->ex_flags & NFSEXP_INSECURE_PORT)) #define EX_SECURE(exp) (!((exp)->ex_flags & NFSEXP_INSECURE_PORT))
#define EX_ISSYNC(exp) (!((exp)->ex_flags & NFSEXP_ASYNC)) #define EX_ISSYNC(exp) (!((exp)->ex_flags & NFSEXP_ASYNC))
#define EX_RDONLY(exp) ((exp)->ex_flags & NFSEXP_READONLY) #define EX_RDONLY(exp) ((exp)->ex_flags & NFSEXP_READONLY)
...@@ -94,16 +92,25 @@ void exp_readlock(void); ...@@ -94,16 +92,25 @@ void exp_readlock(void);
void exp_readunlock(void); void exp_readunlock(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, dev_t dev, ino_t ino); struct svc_expkey * exp_find_key(struct svc_client *clp, int fsid_type, u32 *fsidv);
struct svc_export * exp_get_fsid(struct svc_client *clp, int fsid);
struct svc_export * exp_get_by_name(struct svc_client *clp, struct svc_export * exp_get_by_name(struct svc_client *clp,
struct vfsmount *mnt, struct vfsmount *mnt,
struct dentry *dentry); struct dentry *dentry);
struct svc_export * exp_parent(struct svc_client *clp, struct vfsmount *mnt,
struct dentry *dentry);
int exp_rootfh(struct svc_client *, int exp_rootfh(struct svc_client *,
char *path, struct knfsd_fh *, int maxsize); char *path, struct knfsd_fh *, int maxsize);
int nfserrno(int errno); int nfserrno(int errno);
void exp_nlmdetach(void);
static inline struct svc_export *
exp_find(struct svc_client *clp, int fsid_type, u32 *fsidv)
{
struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv);
if (ek)
return ek->ek_export;
else
return NULL;
}
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
......
...@@ -199,6 +199,19 @@ typedef struct svc_fh { ...@@ -199,6 +199,19 @@ typedef struct svc_fh {
} svc_fh; } svc_fh;
static inline void mk_fsid_v0(u32 *fsidv, dev_t dev, ino_t ino)
{
fsidv[0] = htonl((MAJOR(dev)<<16) |
MINOR(dev));
fsidv[1] = ino_t_to_u32(ino);
}
static inline void mk_fsid_v1(u32 *fsidv, u32 fsid)
{
fsidv[0] = fsid;
}
/* /*
* Shorthand for dprintk()'s * Shorthand for dprintk()'s
*/ */
......
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