Skip to content

Commit

Permalink
Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
Browse files Browse the repository at this point in the history
* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6:
  [NFS] Set CONFIG_KEYS when CONFIG_NFS_USE_KERNEL_DNS is set
  AFS: Implement an autocell mount capability [ver #2]
  DNS: If the DNS server returns an error, allow that to be cached [ver #2]
  NFS: Use kernel DNS resolver [ver #2]
  cifs: update README to include details about 'fsc' option
  • Loading branch information
torvalds committed Aug 13, 2010
2 parents c029b55 + 3f43231 commit 2897c68
Show file tree
Hide file tree
Showing 13 changed files with 409 additions and 51 deletions.
56 changes: 42 additions & 14 deletions fs/afs/cell.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,20 @@ static struct afs_cell *afs_cell_root;
* allocate a cell record and fill in its name, VL server address list and
* allocate an anonymous key
*/
static struct afs_cell *afs_cell_alloc(const char *name, char *vllist)
static struct afs_cell *afs_cell_alloc(const char *name, unsigned namelen,
char *vllist)
{
struct afs_cell *cell;
struct key *key;
size_t namelen;
char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next;
char *dvllist = NULL, *_vllist = NULL;
char delimiter = ':';
int ret;

_enter("%s,%s", name, vllist);
_enter("%*.*s,%s", namelen, namelen, name ?: "", vllist);

BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */

namelen = strlen(name);
if (namelen > AFS_MAXCELLNAME) {
_leave(" = -ENAMETOOLONG");
return ERR_PTR(-ENAMETOOLONG);
Expand Down Expand Up @@ -73,6 +72,10 @@ static struct afs_cell *afs_cell_alloc(const char *name, char *vllist)
if (!vllist || strlen(vllist) < 7) {
ret = dns_query("afsdb", name, namelen, "ipv4", &dvllist, NULL);
if (ret < 0) {
if (ret == -ENODATA || ret == -EAGAIN || ret == -ENOKEY)
/* translate these errors into something
* userspace might understand */
ret = -EDESTADDRREQ;
_leave(" = %d", ret);
return ERR_PTR(ret);
}
Expand Down Expand Up @@ -138,26 +141,29 @@ static struct afs_cell *afs_cell_alloc(const char *name, char *vllist)
}

/*
* create a cell record
* - "name" is the name of the cell
* - "vllist" is a colon separated list of IP addresses in "a.b.c.d" format
* afs_cell_crate() - create a cell record
* @name: is the name of the cell.
* @namsesz: is the strlen of the cell name.
* @vllist: is a colon separated list of IP addresses in "a.b.c.d" format.
* @retref: is T to return the cell reference when the cell exists.
*/
struct afs_cell *afs_cell_create(const char *name, char *vllist)
struct afs_cell *afs_cell_create(const char *name, unsigned namesz,
char *vllist, bool retref)
{
struct afs_cell *cell;
int ret;

_enter("%s,%s", name, vllist);
_enter("%*.*s,%s", namesz, namesz, name ?: "", vllist);

down_write(&afs_cells_sem);
read_lock(&afs_cells_lock);
list_for_each_entry(cell, &afs_cells, link) {
if (strcasecmp(cell->name, name) == 0)
if (strncasecmp(cell->name, name, namesz) == 0)
goto duplicate_name;
}
read_unlock(&afs_cells_lock);

cell = afs_cell_alloc(name, vllist);
cell = afs_cell_alloc(name, namesz, vllist);
if (IS_ERR(cell)) {
_leave(" = %ld", PTR_ERR(cell));
up_write(&afs_cells_sem);
Expand Down Expand Up @@ -197,8 +203,18 @@ struct afs_cell *afs_cell_create(const char *name, char *vllist)
return ERR_PTR(ret);

duplicate_name:
if (retref && !IS_ERR(cell))
afs_get_cell(cell);

read_unlock(&afs_cells_lock);
up_write(&afs_cells_sem);

if (retref) {
_leave(" = %p", cell);
return cell;
}

_leave(" = -EEXIST");
return ERR_PTR(-EEXIST);
}

Expand Down Expand Up @@ -229,7 +245,7 @@ int afs_cell_init(char *rootcell)
*cp++ = 0;

/* allocate a cell record for the root cell */
new_root = afs_cell_create(rootcell, cp);
new_root = afs_cell_create(rootcell, strlen(rootcell), cp, false);
if (IS_ERR(new_root)) {
_leave(" = %ld", PTR_ERR(new_root));
return PTR_ERR(new_root);
Expand All @@ -249,11 +265,12 @@ int afs_cell_init(char *rootcell)
/*
* lookup a cell record
*/
struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz)
struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz,
bool dns_cell)
{
struct afs_cell *cell;

_enter("\"%*.*s\",", namesz, namesz, name ? name : "");
_enter("\"%*.*s\",", namesz, namesz, name ?: "");

down_read(&afs_cells_sem);
read_lock(&afs_cells_lock);
Expand All @@ -267,6 +284,8 @@ struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz)
}
}
cell = ERR_PTR(-ENOENT);
if (dns_cell)
goto create_cell;
found:
;
} else {
Expand All @@ -289,6 +308,15 @@ struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz)
up_read(&afs_cells_sem);
_leave(" = %p", cell);
return cell;

create_cell:
read_unlock(&afs_cells_lock);
up_read(&afs_cells_sem);

cell = afs_cell_create(name, namesz, NULL, true);

_leave(" = %p", cell);
return cell;
}

#if 0
Expand Down
47 changes: 45 additions & 2 deletions fs/afs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,40 @@ static int afs_do_lookup(struct inode *dir, struct dentry *dentry,
return 0;
}

/*
* Try to auto mount the mountpoint with pseudo directory, if the autocell
* operation is setted.
*/
static struct inode *afs_try_auto_mntpt(
int ret, struct dentry *dentry, struct inode *dir, struct key *key,
struct afs_fid *fid)
{
const char *devname = dentry->d_name.name;
struct afs_vnode *vnode = AFS_FS_I(dir);
struct inode *inode;

_enter("%d, %p{%s}, {%x:%u}, %p",
ret, dentry, devname, vnode->fid.vid, vnode->fid.vnode, key);

if (ret != -ENOENT ||
!test_bit(AFS_VNODE_AUTOCELL, &vnode->flags))
goto out;

inode = afs_iget_autocell(dir, devname, strlen(devname), key);
if (IS_ERR(inode)) {
ret = PTR_ERR(inode);
goto out;
}

*fid = AFS_FS_I(inode)->fid;
_leave("= %p", inode);
return inode;

out:
_leave("= %d", ret);
return ERR_PTR(ret);
}

/*
* look up an entry in a directory
*/
Expand Down Expand Up @@ -520,6 +554,13 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,

ret = afs_do_lookup(dir, dentry, &fid, key);
if (ret < 0) {
inode = afs_try_auto_mntpt(ret, dentry, dir, key, &fid);
if (!IS_ERR(inode)) {
key_put(key);
goto success;
}

ret = PTR_ERR(inode);
key_put(key);
if (ret == -ENOENT) {
d_add(dentry, NULL);
Expand All @@ -539,6 +580,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
return ERR_CAST(inode);
}

success:
dentry->d_op = &afs_fs_dentry_operations;

d_add(dentry, inode);
Expand Down Expand Up @@ -696,8 +738,9 @@ static int afs_d_delete(struct dentry *dentry)
goto zap;

if (dentry->d_inode &&
test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dentry->d_inode)->flags))
goto zap;
(test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dentry->d_inode)->flags) ||
test_bit(AFS_VNODE_PSEUDODIR, &AFS_FS_I(dentry->d_inode)->flags)))
goto zap;

_leave(" = 0 [keep]");
return 0;
Expand Down
86 changes: 86 additions & 0 deletions fs/afs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#include <linux/fs.h>
#include <linux/pagemap.h>
#include <linux/sched.h>
#include <linux/mount.h>
#include <linux/namei.h>
#include "internal.h"

struct afs_iget_data {
Expand Down Expand Up @@ -101,6 +103,16 @@ static int afs_iget5_test(struct inode *inode, void *opaque)
inode->i_version == data->fid.unique;
}

/*
* iget5() comparator for inode created by autocell operations
*
* These pseudo inodes don't match anything.
*/
static int afs_iget5_autocell_test(struct inode *inode, void *opaque)
{
return 0;
}

/*
* iget5() inode initialiser
*/
Expand All @@ -117,6 +129,67 @@ static int afs_iget5_set(struct inode *inode, void *opaque)
return 0;
}

/*
* inode retrieval for autocell
*/
struct inode *afs_iget_autocell(struct inode *dir, const char *dev_name,
int namesz, struct key *key)
{
struct afs_iget_data data;
struct afs_super_info *as;
struct afs_vnode *vnode;
struct super_block *sb;
struct inode *inode;
static atomic_t afs_autocell_ino;

_enter("{%x:%u},%*.*s,",
AFS_FS_I(dir)->fid.vid, AFS_FS_I(dir)->fid.vnode,
namesz, namesz, dev_name ?: "");

sb = dir->i_sb;
as = sb->s_fs_info;
data.volume = as->volume;
data.fid.vid = as->volume->vid;
data.fid.unique = 0;
data.fid.vnode = 0;

inode = iget5_locked(sb, atomic_inc_return(&afs_autocell_ino),
afs_iget5_autocell_test, afs_iget5_set,
&data);
if (!inode) {
_leave(" = -ENOMEM");
return ERR_PTR(-ENOMEM);
}

_debug("GOT INODE %p { ino=%lu, vl=%x, vn=%x, u=%x }",
inode, inode->i_ino, data.fid.vid, data.fid.vnode,
data.fid.unique);

vnode = AFS_FS_I(inode);

/* there shouldn't be an existing inode */
BUG_ON(!(inode->i_state & I_NEW));

inode->i_size = 0;
inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
inode->i_op = &afs_autocell_inode_operations;
inode->i_nlink = 2;
inode->i_uid = 0;
inode->i_gid = 0;
inode->i_ctime.tv_sec = get_seconds();
inode->i_ctime.tv_nsec = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime;
inode->i_blocks = 0;
inode->i_version = 0;
inode->i_generation = 0;

set_bit(AFS_VNODE_PSEUDODIR, &vnode->flags);
inode->i_flags |= S_NOATIME;
unlock_new_inode(inode);
_leave(" = %p", inode);
return inode;
}

/*
* inode retrieval
*/
Expand Down Expand Up @@ -313,6 +386,19 @@ int afs_getattr(struct vfsmount *mnt, struct dentry *dentry,
return 0;
}

/*
* discard an AFS inode
*/
int afs_drop_inode(struct inode *inode)
{
_enter("");

if (test_bit(AFS_VNODE_PSEUDODIR, &AFS_FS_I(inode)->flags))
return generic_delete_inode(inode);
else
return generic_drop_inode(inode);
}

/*
* clear an AFS inode
*/
Expand Down
11 changes: 9 additions & 2 deletions fs/afs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ typedef enum {
struct afs_mount_params {
bool rwpath; /* T if the parent should be considered R/W */
bool force; /* T to force cell type */
bool autocell; /* T if set auto mount operation */
afs_voltype_t type; /* type of volume requested */
int volnamesz; /* size of volume name */
const char *volname; /* name of volume to mount */
Expand Down Expand Up @@ -358,6 +359,8 @@ struct afs_vnode {
#define AFS_VNODE_READLOCKED 7 /* set if vnode is read-locked on the server */
#define AFS_VNODE_WRITELOCKED 8 /* set if vnode is write-locked on the server */
#define AFS_VNODE_UNLOCKING 9 /* set if vnode is being unlocked on the server */
#define AFS_VNODE_AUTOCELL 10 /* set if Vnode is an auto mount point */
#define AFS_VNODE_PSEUDODIR 11 /* set if Vnode is a pseudo directory */

long acl_order; /* ACL check count (callback break count) */

Expand Down Expand Up @@ -468,8 +471,8 @@ extern struct list_head afs_proc_cells;

#define afs_get_cell(C) do { atomic_inc(&(C)->usage); } while(0)
extern int afs_cell_init(char *);
extern struct afs_cell *afs_cell_create(const char *, char *);
extern struct afs_cell *afs_cell_lookup(const char *, unsigned);
extern struct afs_cell *afs_cell_create(const char *, unsigned, char *, bool);
extern struct afs_cell *afs_cell_lookup(const char *, unsigned, bool);
extern struct afs_cell *afs_grab_cell(struct afs_cell *);
extern void afs_put_cell(struct afs_cell *);
extern void afs_cell_purge(void);
Expand Down Expand Up @@ -558,6 +561,8 @@ extern int afs_fs_release_lock(struct afs_server *, struct key *,
/*
* inode.c
*/
extern struct inode *afs_iget_autocell(struct inode *, const char *, int,
struct key *);
extern struct inode *afs_iget(struct super_block *, struct key *,
struct afs_fid *, struct afs_file_status *,
struct afs_callback *);
Expand All @@ -566,6 +571,7 @@ extern int afs_validate(struct afs_vnode *, struct key *);
extern int afs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
extern int afs_setattr(struct dentry *, struct iattr *);
extern void afs_evict_inode(struct inode *);
extern int afs_drop_inode(struct inode *);

/*
* main.c
Expand All @@ -581,6 +587,7 @@ extern int afs_abort_to_error(u32);
* mntpt.c
*/
extern const struct inode_operations afs_mntpt_inode_operations;
extern const struct inode_operations afs_autocell_inode_operations;
extern const struct file_operations afs_mntpt_file_operations;

extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *);
Expand Down
Loading

0 comments on commit 2897c68

Please sign in to comment.