Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
* 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
This commit is contained in:
@@ -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 a cell record and fill in its name, VL server address list and
|
||||||
* allocate an anonymous key
|
* 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 afs_cell *cell;
|
||||||
struct key *key;
|
struct key *key;
|
||||||
size_t namelen;
|
|
||||||
char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next;
|
char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next;
|
||||||
char *dvllist = NULL, *_vllist = NULL;
|
char *dvllist = NULL, *_vllist = NULL;
|
||||||
char delimiter = ':';
|
char delimiter = ':';
|
||||||
int ret;
|
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 */
|
BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */
|
||||||
|
|
||||||
namelen = strlen(name);
|
|
||||||
if (namelen > AFS_MAXCELLNAME) {
|
if (namelen > AFS_MAXCELLNAME) {
|
||||||
_leave(" = -ENAMETOOLONG");
|
_leave(" = -ENAMETOOLONG");
|
||||||
return ERR_PTR(-ENAMETOOLONG);
|
return ERR_PTR(-ENAMETOOLONG);
|
||||||
@@ -73,6 +72,10 @@ static struct afs_cell *afs_cell_alloc(const char *name, char *vllist)
|
|||||||
if (!vllist || strlen(vllist) < 7) {
|
if (!vllist || strlen(vllist) < 7) {
|
||||||
ret = dns_query("afsdb", name, namelen, "ipv4", &dvllist, NULL);
|
ret = dns_query("afsdb", name, namelen, "ipv4", &dvllist, NULL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
if (ret == -ENODATA || ret == -EAGAIN || ret == -ENOKEY)
|
||||||
|
/* translate these errors into something
|
||||||
|
* userspace might understand */
|
||||||
|
ret = -EDESTADDRREQ;
|
||||||
_leave(" = %d", ret);
|
_leave(" = %d", ret);
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
}
|
}
|
||||||
@@ -138,26 +141,29 @@ error:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* create a cell record
|
* afs_cell_crate() - create a cell record
|
||||||
* - "name" is the name of the cell
|
* @name: is the name of the cell.
|
||||||
* - "vllist" is a colon separated list of IP addresses in "a.b.c.d" format
|
* @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;
|
struct afs_cell *cell;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
_enter("%s,%s", name, vllist);
|
_enter("%*.*s,%s", namesz, namesz, name ?: "", vllist);
|
||||||
|
|
||||||
down_write(&afs_cells_sem);
|
down_write(&afs_cells_sem);
|
||||||
read_lock(&afs_cells_lock);
|
read_lock(&afs_cells_lock);
|
||||||
list_for_each_entry(cell, &afs_cells, link) {
|
list_for_each_entry(cell, &afs_cells, link) {
|
||||||
if (strcasecmp(cell->name, name) == 0)
|
if (strncasecmp(cell->name, name, namesz) == 0)
|
||||||
goto duplicate_name;
|
goto duplicate_name;
|
||||||
}
|
}
|
||||||
read_unlock(&afs_cells_lock);
|
read_unlock(&afs_cells_lock);
|
||||||
|
|
||||||
cell = afs_cell_alloc(name, vllist);
|
cell = afs_cell_alloc(name, namesz, vllist);
|
||||||
if (IS_ERR(cell)) {
|
if (IS_ERR(cell)) {
|
||||||
_leave(" = %ld", PTR_ERR(cell));
|
_leave(" = %ld", PTR_ERR(cell));
|
||||||
up_write(&afs_cells_sem);
|
up_write(&afs_cells_sem);
|
||||||
@@ -197,8 +203,18 @@ error:
|
|||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
|
|
||||||
duplicate_name:
|
duplicate_name:
|
||||||
|
if (retref && !IS_ERR(cell))
|
||||||
|
afs_get_cell(cell);
|
||||||
|
|
||||||
read_unlock(&afs_cells_lock);
|
read_unlock(&afs_cells_lock);
|
||||||
up_write(&afs_cells_sem);
|
up_write(&afs_cells_sem);
|
||||||
|
|
||||||
|
if (retref) {
|
||||||
|
_leave(" = %p", cell);
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
_leave(" = -EEXIST");
|
||||||
return ERR_PTR(-EEXIST);
|
return ERR_PTR(-EEXIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,7 +245,7 @@ int afs_cell_init(char *rootcell)
|
|||||||
*cp++ = 0;
|
*cp++ = 0;
|
||||||
|
|
||||||
/* allocate a cell record for the root cell */
|
/* 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)) {
|
if (IS_ERR(new_root)) {
|
||||||
_leave(" = %ld", PTR_ERR(new_root));
|
_leave(" = %ld", PTR_ERR(new_root));
|
||||||
return PTR_ERR(new_root);
|
return PTR_ERR(new_root);
|
||||||
@@ -249,11 +265,12 @@ int afs_cell_init(char *rootcell)
|
|||||||
/*
|
/*
|
||||||
* lookup a cell record
|
* 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;
|
struct afs_cell *cell;
|
||||||
|
|
||||||
_enter("\"%*.*s\",", namesz, namesz, name ? name : "");
|
_enter("\"%*.*s\",", namesz, namesz, name ?: "");
|
||||||
|
|
||||||
down_read(&afs_cells_sem);
|
down_read(&afs_cells_sem);
|
||||||
read_lock(&afs_cells_lock);
|
read_lock(&afs_cells_lock);
|
||||||
@@ -267,6 +284,8 @@ struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
cell = ERR_PTR(-ENOENT);
|
cell = ERR_PTR(-ENOENT);
|
||||||
|
if (dns_cell)
|
||||||
|
goto create_cell;
|
||||||
found:
|
found:
|
||||||
;
|
;
|
||||||
} else {
|
} else {
|
||||||
@@ -289,6 +308,15 @@ struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz)
|
|||||||
up_read(&afs_cells_sem);
|
up_read(&afs_cells_sem);
|
||||||
_leave(" = %p", cell);
|
_leave(" = %p", cell);
|
||||||
return 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
|
#if 0
|
||||||
|
47
fs/afs/dir.c
47
fs/afs/dir.c
@@ -476,6 +476,40 @@ static int afs_do_lookup(struct inode *dir, struct dentry *dentry,
|
|||||||
return 0;
|
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
|
* look up an entry in a directory
|
||||||
*/
|
*/
|
||||||
@@ -520,6 +554,13 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
|
|||||||
|
|
||||||
ret = afs_do_lookup(dir, dentry, &fid, key);
|
ret = afs_do_lookup(dir, dentry, &fid, key);
|
||||||
if (ret < 0) {
|
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);
|
key_put(key);
|
||||||
if (ret == -ENOENT) {
|
if (ret == -ENOENT) {
|
||||||
d_add(dentry, NULL);
|
d_add(dentry, NULL);
|
||||||
@@ -539,6 +580,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
|
|||||||
return ERR_CAST(inode);
|
return ERR_CAST(inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
success:
|
||||||
dentry->d_op = &afs_fs_dentry_operations;
|
dentry->d_op = &afs_fs_dentry_operations;
|
||||||
|
|
||||||
d_add(dentry, inode);
|
d_add(dentry, inode);
|
||||||
@@ -696,8 +738,9 @@ static int afs_d_delete(struct dentry *dentry)
|
|||||||
goto zap;
|
goto zap;
|
||||||
|
|
||||||
if (dentry->d_inode &&
|
if (dentry->d_inode &&
|
||||||
test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dentry->d_inode)->flags))
|
(test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dentry->d_inode)->flags) ||
|
||||||
goto zap;
|
test_bit(AFS_VNODE_PSEUDODIR, &AFS_FS_I(dentry->d_inode)->flags)))
|
||||||
|
goto zap;
|
||||||
|
|
||||||
_leave(" = 0 [keep]");
|
_leave(" = 0 [keep]");
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -19,6 +19,8 @@
|
|||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/pagemap.h>
|
#include <linux/pagemap.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
|
#include <linux/mount.h>
|
||||||
|
#include <linux/namei.h>
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
struct afs_iget_data {
|
struct afs_iget_data {
|
||||||
@@ -101,6 +103,16 @@ static int afs_iget5_test(struct inode *inode, void *opaque)
|
|||||||
inode->i_version == data->fid.unique;
|
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
|
* iget5() inode initialiser
|
||||||
*/
|
*/
|
||||||
@@ -117,6 +129,67 @@ static int afs_iget5_set(struct inode *inode, void *opaque)
|
|||||||
return 0;
|
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
|
* inode retrieval
|
||||||
*/
|
*/
|
||||||
@@ -313,6 +386,19 @@ int afs_getattr(struct vfsmount *mnt, struct dentry *dentry,
|
|||||||
return 0;
|
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
|
* clear an AFS inode
|
||||||
*/
|
*/
|
||||||
|
@@ -42,6 +42,7 @@ typedef enum {
|
|||||||
struct afs_mount_params {
|
struct afs_mount_params {
|
||||||
bool rwpath; /* T if the parent should be considered R/W */
|
bool rwpath; /* T if the parent should be considered R/W */
|
||||||
bool force; /* T to force cell type */
|
bool force; /* T to force cell type */
|
||||||
|
bool autocell; /* T if set auto mount operation */
|
||||||
afs_voltype_t type; /* type of volume requested */
|
afs_voltype_t type; /* type of volume requested */
|
||||||
int volnamesz; /* size of volume name */
|
int volnamesz; /* size of volume name */
|
||||||
const char *volname; /* name of volume to mount */
|
const char *volname; /* name of volume to mount */
|
||||||
@@ -358,6 +359,8 @@ struct afs_vnode {
|
|||||||
#define AFS_VNODE_READLOCKED 7 /* set if vnode is read-locked on the server */
|
#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_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_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) */
|
long acl_order; /* ACL check count (callback break count) */
|
||||||
|
|
||||||
@@ -468,8 +471,8 @@ extern struct list_head afs_proc_cells;
|
|||||||
|
|
||||||
#define afs_get_cell(C) do { atomic_inc(&(C)->usage); } while(0)
|
#define afs_get_cell(C) do { atomic_inc(&(C)->usage); } while(0)
|
||||||
extern int afs_cell_init(char *);
|
extern int afs_cell_init(char *);
|
||||||
extern struct afs_cell *afs_cell_create(const char *, char *);
|
extern struct afs_cell *afs_cell_create(const char *, unsigned, char *, bool);
|
||||||
extern struct afs_cell *afs_cell_lookup(const char *, unsigned);
|
extern struct afs_cell *afs_cell_lookup(const char *, unsigned, bool);
|
||||||
extern struct afs_cell *afs_grab_cell(struct afs_cell *);
|
extern struct afs_cell *afs_grab_cell(struct afs_cell *);
|
||||||
extern void afs_put_cell(struct afs_cell *);
|
extern void afs_put_cell(struct afs_cell *);
|
||||||
extern void afs_cell_purge(void);
|
extern void afs_cell_purge(void);
|
||||||
@@ -558,6 +561,8 @@ extern int afs_fs_release_lock(struct afs_server *, struct key *,
|
|||||||
/*
|
/*
|
||||||
* inode.c
|
* 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 *,
|
extern struct inode *afs_iget(struct super_block *, struct key *,
|
||||||
struct afs_fid *, struct afs_file_status *,
|
struct afs_fid *, struct afs_file_status *,
|
||||||
struct afs_callback *);
|
struct afs_callback *);
|
||||||
@@ -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_getattr(struct vfsmount *, struct dentry *, struct kstat *);
|
||||||
extern int afs_setattr(struct dentry *, struct iattr *);
|
extern int afs_setattr(struct dentry *, struct iattr *);
|
||||||
extern void afs_evict_inode(struct inode *);
|
extern void afs_evict_inode(struct inode *);
|
||||||
|
extern int afs_drop_inode(struct inode *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* main.c
|
* main.c
|
||||||
@@ -581,6 +587,7 @@ extern int afs_abort_to_error(u32);
|
|||||||
* mntpt.c
|
* mntpt.c
|
||||||
*/
|
*/
|
||||||
extern const struct inode_operations afs_mntpt_inode_operations;
|
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 const struct file_operations afs_mntpt_file_operations;
|
||||||
|
|
||||||
extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *);
|
extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *);
|
||||||
|
@@ -38,6 +38,11 @@ const struct inode_operations afs_mntpt_inode_operations = {
|
|||||||
.getattr = afs_getattr,
|
.getattr = afs_getattr,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const struct inode_operations afs_autocell_inode_operations = {
|
||||||
|
.follow_link = afs_mntpt_follow_link,
|
||||||
|
.getattr = afs_getattr,
|
||||||
|
};
|
||||||
|
|
||||||
static LIST_HEAD(afs_vfsmounts);
|
static LIST_HEAD(afs_vfsmounts);
|
||||||
static DECLARE_DELAYED_WORK(afs_mntpt_expiry_timer, afs_mntpt_expiry_timed_out);
|
static DECLARE_DELAYED_WORK(afs_mntpt_expiry_timer, afs_mntpt_expiry_timed_out);
|
||||||
|
|
||||||
@@ -136,20 +141,16 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
|
|||||||
{
|
{
|
||||||
struct afs_super_info *super;
|
struct afs_super_info *super;
|
||||||
struct vfsmount *mnt;
|
struct vfsmount *mnt;
|
||||||
|
struct afs_vnode *vnode;
|
||||||
struct page *page;
|
struct page *page;
|
||||||
size_t size;
|
char *devname, *options;
|
||||||
char *buf, *devname, *options;
|
bool rwpath = false;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
_enter("{%s}", mntpt->d_name.name);
|
_enter("{%s}", mntpt->d_name.name);
|
||||||
|
|
||||||
BUG_ON(!mntpt->d_inode);
|
BUG_ON(!mntpt->d_inode);
|
||||||
|
|
||||||
ret = -EINVAL;
|
|
||||||
size = mntpt->d_inode->i_size;
|
|
||||||
if (size > PAGE_SIZE - 1)
|
|
||||||
goto error_no_devname;
|
|
||||||
|
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
devname = (char *) get_zeroed_page(GFP_KERNEL);
|
devname = (char *) get_zeroed_page(GFP_KERNEL);
|
||||||
if (!devname)
|
if (!devname)
|
||||||
@@ -159,28 +160,59 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
|
|||||||
if (!options)
|
if (!options)
|
||||||
goto error_no_options;
|
goto error_no_options;
|
||||||
|
|
||||||
/* read the contents of the AFS special symlink */
|
vnode = AFS_FS_I(mntpt->d_inode);
|
||||||
page = read_mapping_page(mntpt->d_inode->i_mapping, 0, NULL);
|
if (test_bit(AFS_VNODE_PSEUDODIR, &vnode->flags)) {
|
||||||
if (IS_ERR(page)) {
|
/* if the directory is a pseudo directory, use the d_name */
|
||||||
ret = PTR_ERR(page);
|
static const char afs_root_cell[] = ":root.cell.";
|
||||||
goto error_no_page;
|
unsigned size = mntpt->d_name.len;
|
||||||
|
|
||||||
|
ret = -ENOENT;
|
||||||
|
if (size < 2 || size > AFS_MAXCELLNAME)
|
||||||
|
goto error_no_page;
|
||||||
|
|
||||||
|
if (mntpt->d_name.name[0] == '.') {
|
||||||
|
devname[0] = '#';
|
||||||
|
memcpy(devname + 1, mntpt->d_name.name, size - 1);
|
||||||
|
memcpy(devname + size, afs_root_cell,
|
||||||
|
sizeof(afs_root_cell));
|
||||||
|
rwpath = true;
|
||||||
|
} else {
|
||||||
|
devname[0] = '%';
|
||||||
|
memcpy(devname + 1, mntpt->d_name.name, size);
|
||||||
|
memcpy(devname + size + 1, afs_root_cell,
|
||||||
|
sizeof(afs_root_cell));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* read the contents of the AFS special symlink */
|
||||||
|
loff_t size = i_size_read(mntpt->d_inode);
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
ret = -EINVAL;
|
||||||
|
if (size > PAGE_SIZE - 1)
|
||||||
|
goto error_no_page;
|
||||||
|
|
||||||
|
page = read_mapping_page(mntpt->d_inode->i_mapping, 0, NULL);
|
||||||
|
if (IS_ERR(page)) {
|
||||||
|
ret = PTR_ERR(page);
|
||||||
|
goto error_no_page;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = -EIO;
|
||||||
|
if (PageError(page))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
buf = kmap_atomic(page, KM_USER0);
|
||||||
|
memcpy(devname, buf, size);
|
||||||
|
kunmap_atomic(buf, KM_USER0);
|
||||||
|
page_cache_release(page);
|
||||||
|
page = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = -EIO;
|
|
||||||
if (PageError(page))
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
buf = kmap_atomic(page, KM_USER0);
|
|
||||||
memcpy(devname, buf, size);
|
|
||||||
kunmap_atomic(buf, KM_USER0);
|
|
||||||
page_cache_release(page);
|
|
||||||
page = NULL;
|
|
||||||
|
|
||||||
/* work out what options we want */
|
/* work out what options we want */
|
||||||
super = AFS_FS_S(mntpt->d_sb);
|
super = AFS_FS_S(mntpt->d_sb);
|
||||||
memcpy(options, "cell=", 5);
|
memcpy(options, "cell=", 5);
|
||||||
strcpy(options + 5, super->volume->cell->name);
|
strcpy(options + 5, super->volume->cell->name);
|
||||||
if (super->volume->type == AFSVL_RWVOL)
|
if (super->volume->type == AFSVL_RWVOL || rwpath)
|
||||||
strcat(options, ",rwpath");
|
strcat(options, ",rwpath");
|
||||||
|
|
||||||
/* try and do the mount */
|
/* try and do the mount */
|
||||||
|
@@ -294,7 +294,7 @@ static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
|
|||||||
if (strcmp(kbuf, "add") == 0) {
|
if (strcmp(kbuf, "add") == 0) {
|
||||||
struct afs_cell *cell;
|
struct afs_cell *cell;
|
||||||
|
|
||||||
cell = afs_cell_create(name, args);
|
cell = afs_cell_create(name, strlen(name), args, false);
|
||||||
if (IS_ERR(cell)) {
|
if (IS_ERR(cell)) {
|
||||||
ret = PTR_ERR(cell);
|
ret = PTR_ERR(cell);
|
||||||
goto done;
|
goto done;
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/mount.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/smp_lock.h>
|
#include <linux/smp_lock.h>
|
||||||
@@ -48,6 +49,7 @@ struct file_system_type afs_fs_type = {
|
|||||||
static const struct super_operations afs_super_ops = {
|
static const struct super_operations afs_super_ops = {
|
||||||
.statfs = afs_statfs,
|
.statfs = afs_statfs,
|
||||||
.alloc_inode = afs_alloc_inode,
|
.alloc_inode = afs_alloc_inode,
|
||||||
|
.drop_inode = afs_drop_inode,
|
||||||
.destroy_inode = afs_destroy_inode,
|
.destroy_inode = afs_destroy_inode,
|
||||||
.evict_inode = afs_evict_inode,
|
.evict_inode = afs_evict_inode,
|
||||||
.put_super = afs_put_super,
|
.put_super = afs_put_super,
|
||||||
@@ -62,12 +64,14 @@ enum {
|
|||||||
afs_opt_cell,
|
afs_opt_cell,
|
||||||
afs_opt_rwpath,
|
afs_opt_rwpath,
|
||||||
afs_opt_vol,
|
afs_opt_vol,
|
||||||
|
afs_opt_autocell,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const match_table_t afs_options_list = {
|
static const match_table_t afs_options_list = {
|
||||||
{ afs_opt_cell, "cell=%s" },
|
{ afs_opt_cell, "cell=%s" },
|
||||||
{ afs_opt_rwpath, "rwpath" },
|
{ afs_opt_rwpath, "rwpath" },
|
||||||
{ afs_opt_vol, "vol=%s" },
|
{ afs_opt_vol, "vol=%s" },
|
||||||
|
{ afs_opt_autocell, "autocell" },
|
||||||
{ afs_no_opt, NULL },
|
{ afs_no_opt, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -151,7 +155,8 @@ static int afs_parse_options(struct afs_mount_params *params,
|
|||||||
switch (token) {
|
switch (token) {
|
||||||
case afs_opt_cell:
|
case afs_opt_cell:
|
||||||
cell = afs_cell_lookup(args[0].from,
|
cell = afs_cell_lookup(args[0].from,
|
||||||
args[0].to - args[0].from);
|
args[0].to - args[0].from,
|
||||||
|
false);
|
||||||
if (IS_ERR(cell))
|
if (IS_ERR(cell))
|
||||||
return PTR_ERR(cell);
|
return PTR_ERR(cell);
|
||||||
afs_put_cell(params->cell);
|
afs_put_cell(params->cell);
|
||||||
@@ -166,6 +171,10 @@ static int afs_parse_options(struct afs_mount_params *params,
|
|||||||
*devname = args[0].from;
|
*devname = args[0].from;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case afs_opt_autocell:
|
||||||
|
params->autocell = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printk(KERN_ERR "kAFS:"
|
printk(KERN_ERR "kAFS:"
|
||||||
" Unknown or invalid mount option: '%s'\n", p);
|
" Unknown or invalid mount option: '%s'\n", p);
|
||||||
@@ -252,10 +261,10 @@ static int afs_parse_device_name(struct afs_mount_params *params,
|
|||||||
|
|
||||||
/* lookup the cell record */
|
/* lookup the cell record */
|
||||||
if (cellname || !params->cell) {
|
if (cellname || !params->cell) {
|
||||||
cell = afs_cell_lookup(cellname, cellnamesz);
|
cell = afs_cell_lookup(cellname, cellnamesz, true);
|
||||||
if (IS_ERR(cell)) {
|
if (IS_ERR(cell)) {
|
||||||
printk(KERN_ERR "kAFS: unable to lookup cell '%s'\n",
|
printk(KERN_ERR "kAFS: unable to lookup cell '%*.*s'\n",
|
||||||
cellname ?: "");
|
cellnamesz, cellnamesz, cellname ?: "");
|
||||||
return PTR_ERR(cell);
|
return PTR_ERR(cell);
|
||||||
}
|
}
|
||||||
afs_put_cell(params->cell);
|
afs_put_cell(params->cell);
|
||||||
@@ -321,6 +330,9 @@ static int afs_fill_super(struct super_block *sb, void *data)
|
|||||||
if (IS_ERR(inode))
|
if (IS_ERR(inode))
|
||||||
goto error_inode;
|
goto error_inode;
|
||||||
|
|
||||||
|
if (params->autocell)
|
||||||
|
set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags);
|
||||||
|
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
root = d_alloc_root(inode);
|
root = d_alloc_root(inode);
|
||||||
if (!root)
|
if (!root)
|
||||||
|
@@ -301,6 +301,16 @@ A partial list of the supported mount options follows:
|
|||||||
gid Set the default gid for inodes (similar to above).
|
gid Set the default gid for inodes (similar to above).
|
||||||
file_mode If CIFS Unix extensions are not supported by the server
|
file_mode If CIFS Unix extensions are not supported by the server
|
||||||
this overrides the default mode for file inodes.
|
this overrides the default mode for file inodes.
|
||||||
|
fsc Enable local disk caching using FS-Cache (off by default). This
|
||||||
|
option could be useful to improve performance on a slow link,
|
||||||
|
heavily loaded server and/or network where reading from the
|
||||||
|
disk is faster than reading from the server (over the network).
|
||||||
|
This could also impact scalability positively as the
|
||||||
|
number of calls to the server are reduced. However, local
|
||||||
|
caching is not suitable for all workloads for e.g. read-once
|
||||||
|
type workloads. So, you need to consider carefully your
|
||||||
|
workload/scenario before using this option. Currently, local
|
||||||
|
disk caching is functional for CIFS files opened as read-only.
|
||||||
dir_mode If CIFS Unix extensions are not supported by the server
|
dir_mode If CIFS Unix extensions are not supported by the server
|
||||||
this overrides the default mode for directory inodes.
|
this overrides the default mode for directory inodes.
|
||||||
port attempt to contact the server on this tcp port, before
|
port attempt to contact the server on this tcp port, before
|
||||||
|
@@ -100,3 +100,20 @@ config NFS_FSCACHE
|
|||||||
help
|
help
|
||||||
Say Y here if you want NFS data to be cached locally on disc through
|
Say Y here if you want NFS data to be cached locally on disc through
|
||||||
the general filesystem cache manager
|
the general filesystem cache manager
|
||||||
|
|
||||||
|
config NFS_USE_LEGACY_DNS
|
||||||
|
bool "Use the legacy NFS DNS resolver"
|
||||||
|
depends on NFS_V4
|
||||||
|
help
|
||||||
|
The kernel now provides a method for translating a host name into an
|
||||||
|
IP address. Select Y here if you would rather use your own DNS
|
||||||
|
resolver script.
|
||||||
|
|
||||||
|
If unsure, say N
|
||||||
|
|
||||||
|
config NFS_USE_KERNEL_DNS
|
||||||
|
bool
|
||||||
|
depends on NFS_V4 && !NFS_USE_LEGACY_DNS
|
||||||
|
select DNS_RESOLVER
|
||||||
|
select KEYS
|
||||||
|
default y
|
||||||
|
@@ -6,6 +6,29 @@
|
|||||||
* Resolves DNS hostnames into valid ip addresses
|
* Resolves DNS hostnames into valid ip addresses
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifdef CONFIG_NFS_USE_KERNEL_DNS
|
||||||
|
|
||||||
|
#include <linux/sunrpc/clnt.h>
|
||||||
|
#include <linux/dns_resolver.h>
|
||||||
|
|
||||||
|
ssize_t nfs_dns_resolve_name(char *name, size_t namelen,
|
||||||
|
struct sockaddr *sa, size_t salen)
|
||||||
|
{
|
||||||
|
ssize_t ret;
|
||||||
|
char *ip_addr = NULL;
|
||||||
|
int ip_len;
|
||||||
|
|
||||||
|
ip_len = dns_query(NULL, name, namelen, NULL, &ip_addr, NULL);
|
||||||
|
if (ip_len > 0)
|
||||||
|
ret = rpc_pton(ip_addr, ip_len, sa, salen);
|
||||||
|
else
|
||||||
|
ret = -ESRCH;
|
||||||
|
kfree(ip_addr);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
#include <linux/hash.h>
|
#include <linux/hash.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/kmod.h>
|
#include <linux/kmod.h>
|
||||||
@@ -346,3 +369,4 @@ void nfs_dns_resolver_destroy(void)
|
|||||||
nfs_cache_unregister(&nfs_dns_resolve);
|
nfs_cache_unregister(&nfs_dns_resolve);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@@ -6,8 +6,20 @@
|
|||||||
|
|
||||||
#define NFS_DNS_HOSTNAME_MAXLEN (128)
|
#define NFS_DNS_HOSTNAME_MAXLEN (128)
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_NFS_USE_KERNEL_DNS
|
||||||
|
static inline int nfs_dns_resolver_init(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void nfs_dns_resolver_destroy(void)
|
||||||
|
{}
|
||||||
|
#else
|
||||||
extern int nfs_dns_resolver_init(void);
|
extern int nfs_dns_resolver_init(void);
|
||||||
extern void nfs_dns_resolver_destroy(void);
|
extern void nfs_dns_resolver_destroy(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
extern ssize_t nfs_dns_resolve_name(char *name, size_t namelen,
|
extern ssize_t nfs_dns_resolve_name(char *name, size_t namelen,
|
||||||
struct sockaddr *sa, size_t salen);
|
struct sockaddr *sa, size_t salen);
|
||||||
|
|
||||||
|
@@ -29,6 +29,7 @@
|
|||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/keyctl.h>
|
#include <linux/keyctl.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
|
#include <linux/seq_file.h>
|
||||||
#include <keys/dns_resolver-type.h>
|
#include <keys/dns_resolver-type.h>
|
||||||
#include <keys/user-type.h>
|
#include <keys/user-type.h>
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
@@ -43,6 +44,8 @@ MODULE_PARM_DESC(debug, "DNS Resolver debugging mask");
|
|||||||
|
|
||||||
const struct cred *dns_resolver_cache;
|
const struct cred *dns_resolver_cache;
|
||||||
|
|
||||||
|
#define DNS_ERRORNO_OPTION "dnserror"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Instantiate a user defined key for dns_resolver.
|
* Instantiate a user defined key for dns_resolver.
|
||||||
*
|
*
|
||||||
@@ -59,9 +62,10 @@ static int
|
|||||||
dns_resolver_instantiate(struct key *key, const void *_data, size_t datalen)
|
dns_resolver_instantiate(struct key *key, const void *_data, size_t datalen)
|
||||||
{
|
{
|
||||||
struct user_key_payload *upayload;
|
struct user_key_payload *upayload;
|
||||||
|
unsigned long derrno;
|
||||||
int ret;
|
int ret;
|
||||||
size_t result_len = 0;
|
size_t result_len = 0;
|
||||||
const char *data = _data, *opt;
|
const char *data = _data, *end, *opt;
|
||||||
|
|
||||||
kenter("%%%d,%s,'%s',%zu",
|
kenter("%%%d,%s,'%s',%zu",
|
||||||
key->serial, key->description, data, datalen);
|
key->serial, key->description, data, datalen);
|
||||||
@@ -71,13 +75,77 @@ dns_resolver_instantiate(struct key *key, const void *_data, size_t datalen)
|
|||||||
datalen--;
|
datalen--;
|
||||||
|
|
||||||
/* deal with any options embedded in the data */
|
/* deal with any options embedded in the data */
|
||||||
|
end = data + datalen;
|
||||||
opt = memchr(data, '#', datalen);
|
opt = memchr(data, '#', datalen);
|
||||||
if (!opt) {
|
if (!opt) {
|
||||||
kdebug("no options currently supported");
|
/* no options: the entire data is the result */
|
||||||
return -EINVAL;
|
kdebug("no options");
|
||||||
|
result_len = datalen;
|
||||||
|
} else {
|
||||||
|
const char *next_opt;
|
||||||
|
|
||||||
|
result_len = opt - data;
|
||||||
|
opt++;
|
||||||
|
kdebug("options: '%s'", opt);
|
||||||
|
do {
|
||||||
|
const char *eq;
|
||||||
|
int opt_len, opt_nlen, opt_vlen, tmp;
|
||||||
|
|
||||||
|
next_opt = memchr(opt, '#', end - opt) ?: end;
|
||||||
|
opt_len = next_opt - opt;
|
||||||
|
if (!opt_len) {
|
||||||
|
printk(KERN_WARNING
|
||||||
|
"Empty option to dns_resolver key %d\n",
|
||||||
|
key->serial);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
eq = memchr(opt, '=', opt_len) ?: end;
|
||||||
|
opt_nlen = eq - opt;
|
||||||
|
eq++;
|
||||||
|
opt_vlen = next_opt - eq; /* will be -1 if no value */
|
||||||
|
|
||||||
|
tmp = opt_vlen >= 0 ? opt_vlen : 0;
|
||||||
|
kdebug("option '%*.*s' val '%*.*s'",
|
||||||
|
opt_nlen, opt_nlen, opt, tmp, tmp, eq);
|
||||||
|
|
||||||
|
/* see if it's an error number representing a DNS error
|
||||||
|
* that's to be recorded as the result in this key */
|
||||||
|
if (opt_nlen == sizeof(DNS_ERRORNO_OPTION) - 1 &&
|
||||||
|
memcmp(opt, DNS_ERRORNO_OPTION, opt_nlen) == 0) {
|
||||||
|
kdebug("dns error number option");
|
||||||
|
if (opt_vlen <= 0)
|
||||||
|
goto bad_option_value;
|
||||||
|
|
||||||
|
ret = strict_strtoul(eq, 10, &derrno);
|
||||||
|
if (ret < 0)
|
||||||
|
goto bad_option_value;
|
||||||
|
|
||||||
|
if (derrno < 1 || derrno > 511)
|
||||||
|
goto bad_option_value;
|
||||||
|
|
||||||
|
kdebug("dns error no. = %lu", derrno);
|
||||||
|
key->type_data.x[0] = -derrno;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bad_option_value:
|
||||||
|
printk(KERN_WARNING
|
||||||
|
"Option '%*.*s' to dns_resolver key %d:"
|
||||||
|
" bad/missing value\n",
|
||||||
|
opt_nlen, opt_nlen, opt, key->serial);
|
||||||
|
return -EINVAL;
|
||||||
|
} while (opt = next_opt + 1, opt < end);
|
||||||
}
|
}
|
||||||
|
|
||||||
result_len = datalen;
|
/* don't cache the result if we're caching an error saying there's no
|
||||||
|
* result */
|
||||||
|
if (key->type_data.x[0]) {
|
||||||
|
kleave(" = 0 [h_error %ld]", key->type_data.x[0]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
kdebug("store result");
|
||||||
ret = key_payload_reserve(key, result_len);
|
ret = key_payload_reserve(key, result_len);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -135,13 +203,27 @@ no_match:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Describe a DNS key
|
||||||
|
*/
|
||||||
|
static void dns_resolver_describe(const struct key *key, struct seq_file *m)
|
||||||
|
{
|
||||||
|
int err = key->type_data.x[0];
|
||||||
|
|
||||||
|
seq_puts(m, key->description);
|
||||||
|
if (err)
|
||||||
|
seq_printf(m, ": %d", err);
|
||||||
|
else
|
||||||
|
seq_printf(m, ": %u", key->datalen);
|
||||||
|
}
|
||||||
|
|
||||||
struct key_type key_type_dns_resolver = {
|
struct key_type key_type_dns_resolver = {
|
||||||
.name = "dns_resolver",
|
.name = "dns_resolver",
|
||||||
.instantiate = dns_resolver_instantiate,
|
.instantiate = dns_resolver_instantiate,
|
||||||
.match = dns_resolver_match,
|
.match = dns_resolver_match,
|
||||||
.revoke = user_revoke,
|
.revoke = user_revoke,
|
||||||
.destroy = user_destroy,
|
.destroy = user_destroy,
|
||||||
.describe = user_describe,
|
.describe = dns_resolver_describe,
|
||||||
.read = user_read,
|
.read = user_read,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -136,6 +136,11 @@ int dns_query(const char *type, const char *name, size_t namelen,
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto put;
|
goto put;
|
||||||
|
|
||||||
|
/* If the DNS server gave an error, return that to the caller */
|
||||||
|
ret = rkey->type_data.x[0];
|
||||||
|
if (ret)
|
||||||
|
goto put;
|
||||||
|
|
||||||
upayload = rcu_dereference_protected(rkey->payload.data,
|
upayload = rcu_dereference_protected(rkey->payload.data,
|
||||||
lockdep_is_held(&rkey->sem));
|
lockdep_is_held(&rkey->sem));
|
||||||
len = upayload->datalen;
|
len = upayload->datalen;
|
||||||
|
Reference in New Issue
Block a user