Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 3126
b: refs/heads/master
c: 190e4fb
h: refs/heads/master
v: v3
  • Loading branch information
NeilBrown authored and Linus Torvalds committed Jun 24, 2005
1 parent 7fb120e commit 009826b
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 3 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: cb36d6345752fa24827044c68e15f6708a40d9f6
refs/heads/master: 190e4fbf96037e5e526ba3210f2bcc2a3b6fe964
166 changes: 166 additions & 0 deletions trunk/fs/nfsd/nfs4recover.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,37 @@
#include <linux/nfs4.h>
#include <linux/nfsd/state.h>
#include <linux/nfsd/xdr4.h>
#include <linux/param.h>
#include <linux/file.h>
#include <linux/namei.h>
#include <asm/uaccess.h>
#include <asm/scatterlist.h>
#include <linux/crypto.h>


#define NFSDDBG_FACILITY NFSDDBG_PROC

/* Globals */
char recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery";
static struct nameidata rec_dir;
static int rec_dir_init = 0;

static void
nfs4_save_user(uid_t *saveuid, gid_t *savegid)
{
*saveuid = current->fsuid;
*savegid = current->fsgid;
current->fsuid = 0;
current->fsgid = 0;
}

static void
nfs4_reset_user(uid_t saveuid, gid_t savegid)
{
current->fsuid = saveuid;
current->fsgid = savegid;
}

static void
md5_to_hex(char *out, char *md5)
{
Expand Down Expand Up @@ -95,3 +119,145 @@ nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname)
crypto_free_tfm(tfm);
return status;
}

typedef int (recdir_func)(struct dentry *, struct dentry *);

struct dentry_list {
struct dentry *dentry;
struct list_head list;
};

struct dentry_list_arg {
struct list_head dentries;
struct dentry *parent;
};

static int
nfsd4_build_dentrylist(void *arg, const char *name, int namlen,
loff_t offset, ino_t ino, unsigned int d_type)
{
struct dentry_list_arg *dla = arg;
struct list_head *dentries = &dla->dentries;
struct dentry *parent = dla->parent;
struct dentry *dentry;
struct dentry_list *child;

if (name && isdotent(name, namlen))
return nfs_ok;
dentry = lookup_one_len(name, parent, namlen);
if (IS_ERR(dentry))
return PTR_ERR(dentry);
child = kmalloc(sizeof(*child), GFP_KERNEL);
if (child == NULL)
return -ENOMEM;
child->dentry = dentry;
list_add(&child->list, dentries);
return 0;
}

static int
nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f)
{
struct file *filp;
struct dentry_list_arg dla = {
.parent = dir,
};
struct list_head *dentries = &dla.dentries;
struct dentry_list *child;
uid_t uid;
gid_t gid;
int status;

if (!rec_dir_init)
return 0;

nfs4_save_user(&uid, &gid);

filp = dentry_open(dget(dir), mntget(rec_dir.mnt),
O_RDWR);
status = PTR_ERR(filp);
if (IS_ERR(filp))
goto out;
INIT_LIST_HEAD(dentries);
status = vfs_readdir(filp, nfsd4_build_dentrylist, &dla);
fput(filp);
while (!list_empty(dentries)) {
child = list_entry(dentries->next, struct dentry_list, list);
status = f(dir, child->dentry);
if (status)
goto out;
list_del(&child->list);
dput(child->dentry);
kfree(child);
}
out:
while (!list_empty(dentries)) {
child = list_entry(dentries->next, struct dentry_list, list);
list_del(&child->list);
dput(child->dentry);
kfree(child);
}
nfs4_reset_user(uid, gid);
return status;
}

static int
load_recdir(struct dentry *parent, struct dentry *child)
{
if (child->d_name.len != HEXDIR_LEN - 1) {
printk("nfsd4: illegal name %s in recovery directory\n",
child->d_name.name);
/* Keep trying; maybe the others are OK: */
return nfs_ok;
}
nfs4_client_to_reclaim(child->d_name.name);
return nfs_ok;
}

int
nfsd4_recdir_load(void) {
int status;

status = nfsd4_list_rec_dir(rec_dir.dentry, load_recdir);
if (status)
printk("nfsd4: failed loading clients from recovery"
" directory %s\n", rec_dir.dentry->d_name.name);
return status;
}

/*
* Hold reference to the recovery directory.
*/

void
nfsd4_init_recdir(char *rec_dirname)
{
uid_t uid = 0;
gid_t gid = 0;
int status;

printk("NFSD: Using %s as the NFSv4 state recovery directory\n",
rec_dirname);

BUG_ON(rec_dir_init);

nfs4_save_user(&uid, &gid);

status = path_lookup(rec_dirname, LOOKUP_FOLLOW, &rec_dir);
if (status == -ENOENT)
printk("NFSD: recovery directory %s doesn't exist\n",
rec_dirname);

if (!status)
rec_dir_init = 1;
nfs4_reset_user(uid, gid);
}

void
nfsd4_shutdown_recdir(void)
{
if (!rec_dir_init)
return;
rec_dir_init = 0;
path_release(&rec_dir);
}
18 changes: 16 additions & 2 deletions trunk/fs/nfsd/nfs4state.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ static stateid_t onestateid; /* bits all 1 */
static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags);
static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid);
static void release_stateid_lockowners(struct nfs4_stateid *open_stp);
extern char recovery_dirname[];

/* Locking:
*
Expand Down Expand Up @@ -3091,8 +3092,8 @@ alloc_reclaim(void)
/*
* failure => all reset bets are off, nfserr_no_grace...
*/
static int
nfs4_client_to_reclaim(char *name)
int
nfs4_client_to_reclaim(const char *name)
{
unsigned int strhashval;
struct nfs4_client_reclaim *crp = NULL;
Expand Down Expand Up @@ -3202,6 +3203,17 @@ nfs4_state_init(void)
reclaim_str_hashtbl_size = 0;
}

static void
nfsd4_load_reboot_recovery_data(void)
{
int status;

nfsd4_init_recdir(recovery_dirname);
status = nfsd4_recdir_load();
if (status)
printk("NFSD: Failure reading reboot recovery data\n");
}

/* initialization to perform when the nfsd service is started: */

static void
Expand All @@ -3228,6 +3240,7 @@ nfs4_state_start(void)
status = nfsd4_init_slabs();
if (status)
return status;
nfsd4_load_reboot_recovery_data();
__nfs4_state_start();
nfs4_init = 1;
return 0;
Expand Down Expand Up @@ -3286,6 +3299,7 @@ __nfs4_state_shutdown(void)
cancel_delayed_work(&laundromat_work);
flush_workqueue(laundry_wq);
destroy_workqueue(laundry_wq);
nfsd4_shutdown_recdir();
nfs4_init = 0;
}

Expand Down
4 changes: 4 additions & 0 deletions trunk/include/linux/nfsd/state.h
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,10 @@ extern void nfsd4_probe_callback(struct nfs4_client *clp);
extern void nfsd4_cb_recall(struct nfs4_delegation *dp);
extern void nfs4_put_delegation(struct nfs4_delegation *dp);
extern int nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname);
extern void nfsd4_init_recdir(char *recdir_name);
extern int nfsd4_recdir_load(void);
extern void nfsd4_shutdown_recdir(void);
extern int nfs4_client_to_reclaim(const char *name);

static inline void
nfs4_put_stateowner(struct nfs4_stateowner *so)
Expand Down

0 comments on commit 009826b

Please sign in to comment.