diff options
| -rw-r--r-- | fs/afs/cell.c | 56 | ||||
| -rw-r--r-- | fs/afs/dir.c | 47 | ||||
| -rw-r--r-- | fs/afs/inode.c | 86 | ||||
| -rw-r--r-- | fs/afs/internal.h | 11 | ||||
| -rw-r--r-- | fs/afs/mntpt.c | 78 | ||||
| -rw-r--r-- | fs/afs/proc.c | 2 | ||||
| -rw-r--r-- | fs/afs/super.c | 20 | ||||
| -rw-r--r-- | fs/cifs/README | 10 | ||||
| -rw-r--r-- | fs/nfs/Kconfig | 17 | ||||
| -rw-r--r-- | fs/nfs/dns_resolve.c | 24 | ||||
| -rw-r--r-- | fs/nfs/dns_resolve.h | 12 | ||||
| -rw-r--r-- | net/dns_resolver/dns_key.c | 92 | ||||
| -rw-r--r-- | net/dns_resolver/dns_query.c | 5 |
13 files changed, 409 insertions, 51 deletions
diff --git a/fs/afs/cell.c b/fs/afs/cell.c index ffea35c63879..0d5eeadf6121 100644 --- a/fs/afs/cell.c +++ b/fs/afs/cell.c | |||
| @@ -31,21 +31,20 @@ static struct afs_cell *afs_cell_root; | |||
| 31 | * allocate a cell record and fill in its name, VL server address list and | 31 | * allocate a cell record and fill in its name, VL server address list and |
| 32 | * allocate an anonymous key | 32 | * allocate an anonymous key |
| 33 | */ | 33 | */ |
| 34 | static struct afs_cell *afs_cell_alloc(const char *name, char *vllist) | 34 | static struct afs_cell *afs_cell_alloc(const char *name, unsigned namelen, |
| 35 | char *vllist) | ||
| 35 | { | 36 | { |
| 36 | struct afs_cell *cell; | 37 | struct afs_cell *cell; |
| 37 | struct key *key; | 38 | struct key *key; |
| 38 | size_t namelen; | ||
| 39 | char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next; | 39 | char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next; |
| 40 | char *dvllist = NULL, *_vllist = NULL; | 40 | char *dvllist = NULL, *_vllist = NULL; |
| 41 | char delimiter = ':'; | 41 | char delimiter = ':'; |
| 42 | int ret; | 42 | int ret; |
| 43 | 43 | ||
| 44 | _enter("%s,%s", name, vllist); | 44 | _enter("%*.*s,%s", namelen, namelen, name ?: "", vllist); |
| 45 | 45 | ||
| 46 | BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */ | 46 | BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */ |
| 47 | 47 | ||
| 48 | namelen = strlen(name); | ||
| 49 | if (namelen > AFS_MAXCELLNAME) { | 48 | if (namelen > AFS_MAXCELLNAME) { |
| 50 | _leave(" = -ENAMETOOLONG"); | 49 | _leave(" = -ENAMETOOLONG"); |
| 51 | return ERR_PTR(-ENAMETOOLONG); | 50 | return ERR_PTR(-ENAMETOOLONG); |
| @@ -73,6 +72,10 @@ static struct afs_cell *afs_cell_alloc(const char *name, char *vllist) | |||
| 73 | if (!vllist || strlen(vllist) < 7) { | 72 | if (!vllist || strlen(vllist) < 7) { |
| 74 | ret = dns_query("afsdb", name, namelen, "ipv4", &dvllist, NULL); | 73 | ret = dns_query("afsdb", name, namelen, "ipv4", &dvllist, NULL); |
| 75 | if (ret < 0) { | 74 | if (ret < 0) { |
| 75 | if (ret == -ENODATA || ret == -EAGAIN || ret == -ENOKEY) | ||
| 76 | /* translate these errors into something | ||
| 77 | * userspace might understand */ | ||
| 78 | ret = -EDESTADDRREQ; | ||
| 76 | _leave(" = %d", ret); | 79 | _leave(" = %d", ret); |
| 77 | return ERR_PTR(ret); | 80 | return ERR_PTR(ret); |
| 78 | } | 81 | } |
| @@ -138,26 +141,29 @@ error: | |||
| 138 | } | 141 | } |
| 139 | 142 | ||
| 140 | /* | 143 | /* |
| 141 | * create a cell record | 144 | * afs_cell_crate() - create a cell record |
| 142 | * - "name" is the name of the cell | 145 | * @name: is the name of the cell. |
| 143 | * - "vllist" is a colon separated list of IP addresses in "a.b.c.d" format | 146 | * @namsesz: is the strlen of the cell name. |
| 147 | * @vllist: is a colon separated list of IP addresses in "a.b.c.d" format. | ||
| 148 | * @retref: is T to return the cell reference when the cell exists. | ||
| 144 | */ | 149 | */ |
| 145 | struct afs_cell *afs_cell_create(const char *name, char *vllist) | 150 | struct afs_cell *afs_cell_create(const char *name, unsigned namesz, |
| 151 | char *vllist, bool retref) | ||
| 146 | { | 152 | { |
| 147 | struct afs_cell *cell; | 153 | struct afs_cell *cell; |
| 148 | int ret; | 154 | int ret; |
| 149 | 155 | ||
| 150 | _enter("%s,%s", name, vllist); | 156 | _enter("%*.*s,%s", namesz, namesz, name ?: "", vllist); |
| 151 | 157 | ||
| 152 | down_write(&afs_cells_sem); | 158 | down_write(&afs_cells_sem); |
| 153 | read_lock(&afs_cells_lock); | 159 | read_lock(&afs_cells_lock); |
| 154 | list_for_each_entry(cell, &afs_cells, link) { | 160 | list_for_each_entry(cell, &afs_cells, link) { |
| 155 | if (strcasecmp(cell->name, name) == 0) | 161 | if (strncasecmp(cell->name, name, namesz) == 0) |
| 156 | goto duplicate_name; | 162 | goto duplicate_name; |
| 157 | } | 163 | } |
| 158 | read_unlock(&afs_cells_lock); | 164 | read_unlock(&afs_cells_lock); |
| 159 | 165 | ||
| 160 | cell = afs_cell_alloc(name, vllist); | 166 | cell = afs_cell_alloc(name, namesz, vllist); |
| 161 | if (IS_ERR(cell)) { | 167 | if (IS_ERR(cell)) { |
| 162 | _leave(" = %ld", PTR_ERR(cell)); | 168 | _leave(" = %ld", PTR_ERR(cell)); |
| 163 | up_write(&afs_cells_sem); | 169 | up_write(&afs_cells_sem); |
| @@ -197,8 +203,18 @@ error: | |||
| 197 | return ERR_PTR(ret); | 203 | return ERR_PTR(ret); |
| 198 | 204 | ||
| 199 | duplicate_name: | 205 | duplicate_name: |
| 206 | if (retref && !IS_ERR(cell)) | ||
| 207 | afs_get_cell(cell); | ||
| 208 | |||
| 200 | read_unlock(&afs_cells_lock); | 209 | read_unlock(&afs_cells_lock); |
| 201 | up_write(&afs_cells_sem); | 210 | up_write(&afs_cells_sem); |
| 211 | |||
| 212 | if (retref) { | ||
| 213 | _leave(" = %p", cell); | ||
| 214 | return cell; | ||
| 215 | } | ||
| 216 | |||
| 217 | _leave(" = -EEXIST"); | ||
| 202 | return ERR_PTR(-EEXIST); | 218 | return ERR_PTR(-EEXIST); |
| 203 | } | 219 | } |
| 204 | 220 | ||
| @@ -229,7 +245,7 @@ int afs_cell_init(char *rootcell) | |||
| 229 | *cp++ = 0; | 245 | *cp++ = 0; |
| 230 | 246 | ||
| 231 | /* allocate a cell record for the root cell */ | 247 | /* allocate a cell record for the root cell */ |
| 232 | new_root = afs_cell_create(rootcell, cp); | 248 | new_root = afs_cell_create(rootcell, strlen(rootcell), cp, false); |
| 233 | if (IS_ERR(new_root)) { | 249 | if (IS_ERR(new_root)) { |
| 234 | _leave(" = %ld", PTR_ERR(new_root)); | 250 | _leave(" = %ld", PTR_ERR(new_root)); |
| 235 | return PTR_ERR(new_root); | 251 | return PTR_ERR(new_root); |
| @@ -249,11 +265,12 @@ int afs_cell_init(char *rootcell) | |||
| 249 | /* | 265 | /* |
| 250 | * lookup a cell record | 266 | * lookup a cell record |
| 251 | */ | 267 | */ |
| 252 | struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz) | 268 | struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz, |
| 269 | bool dns_cell) | ||
| 253 | { | 270 | { |
| 254 | struct afs_cell *cell; | 271 | struct afs_cell *cell; |
| 255 | 272 | ||
| 256 | _enter("\"%*.*s\",", namesz, namesz, name ? name : ""); | 273 | _enter("\"%*.*s\",", namesz, namesz, name ?: ""); |
| 257 | 274 | ||
| 258 | down_read(&afs_cells_sem); | 275 | down_read(&afs_cells_sem); |
| 259 | read_lock(&afs_cells_lock); | 276 | read_lock(&afs_cells_lock); |
| @@ -267,6 +284,8 @@ struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz) | |||
| 267 | } | 284 | } |
| 268 | } | 285 | } |
| 269 | cell = ERR_PTR(-ENOENT); | 286 | cell = ERR_PTR(-ENOENT); |
| 287 | if (dns_cell) | ||
| 288 | goto create_cell; | ||
| 270 | found: | 289 | found: |
| 271 | ; | 290 | ; |
| 272 | } else { | 291 | } else { |
| @@ -289,6 +308,15 @@ struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz) | |||
| 289 | up_read(&afs_cells_sem); | 308 | up_read(&afs_cells_sem); |
| 290 | _leave(" = %p", cell); | 309 | _leave(" = %p", cell); |
| 291 | return cell; | 310 | return cell; |
| 311 | |||
| 312 | create_cell: | ||
| 313 | read_unlock(&afs_cells_lock); | ||
| 314 | up_read(&afs_cells_sem); | ||
| 315 | |||
| 316 | cell = afs_cell_create(name, namesz, NULL, true); | ||
| 317 | |||
| 318 | _leave(" = %p", cell); | ||
| 319 | return cell; | ||
| 292 | } | 320 | } |
| 293 | 321 | ||
| 294 | #if 0 | 322 | #if 0 |
diff --git a/fs/afs/dir.c b/fs/afs/dir.c index b42d5cc1d6d2..0d38c09bd55e 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c | |||
| @@ -477,6 +477,40 @@ static int afs_do_lookup(struct inode *dir, struct dentry *dentry, | |||
| 477 | } | 477 | } |
| 478 | 478 | ||
| 479 | /* | 479 | /* |
| 480 | * Try to auto mount the mountpoint with pseudo directory, if the autocell | ||
| 481 | * operation is setted. | ||
| 482 | */ | ||
| 483 | static struct inode *afs_try_auto_mntpt( | ||
| 484 | int ret, struct dentry *dentry, struct inode *dir, struct key *key, | ||
| 485 | struct afs_fid *fid) | ||
| 486 | { | ||
| 487 | const char *devname = dentry->d_name.name; | ||
| 488 | struct afs_vnode *vnode = AFS_FS_I(dir); | ||
| 489 | struct inode *inode; | ||
| 490 | |||
| 491 | _enter("%d, %p{%s}, {%x:%u}, %p", | ||
| 492 | ret, dentry, devname, vnode->fid.vid, vnode->fid.vnode, key); | ||
| 493 | |||
| 494 | if (ret != -ENOENT || | ||
| 495 | !test_bit(AFS_VNODE_AUTOCELL, &vnode->flags)) | ||
| 496 | goto out; | ||
| 497 | |||
| 498 | inode = afs_iget_autocell(dir, devname, strlen(devname), key); | ||
| 499 | if (IS_ERR(inode)) { | ||
| 500 | ret = PTR_ERR(inode); | ||
| 501 | goto out; | ||
| 502 | } | ||
| 503 | |||
| 504 | *fid = AFS_FS_I(inode)->fid; | ||
| 505 | _leave("= %p", inode); | ||
| 506 | return inode; | ||
| 507 | |||
| 508 | out: | ||
| 509 | _leave("= %d", ret); | ||
| 510 | return ERR_PTR(ret); | ||
| 511 | } | ||
| 512 | |||
| 513 | /* | ||
| 480 | * look up an entry in a directory | 514 | * look up an entry in a directory |
| 481 | */ | 515 | */ |
| 482 | static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, | 516 | static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, |
| @@ -520,6 +554,13 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, | |||
| 520 | 554 | ||
| 521 | ret = afs_do_lookup(dir, dentry, &fid, key); | 555 | ret = afs_do_lookup(dir, dentry, &fid, key); |
| 522 | if (ret < 0) { | 556 | if (ret < 0) { |
| 557 | inode = afs_try_auto_mntpt(ret, dentry, dir, key, &fid); | ||
| 558 | if (!IS_ERR(inode)) { | ||
| 559 | key_put(key); | ||
| 560 | goto success; | ||
| 561 | } | ||
| 562 | |||
| 563 | ret = PTR_ERR(inode); | ||
| 523 | key_put(key); | 564 | key_put(key); |
| 524 | if (ret == -ENOENT) { | 565 | if (ret == -ENOENT) { |
| 525 | d_add(dentry, NULL); | 566 | d_add(dentry, NULL); |
| @@ -539,6 +580,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, | |||
| 539 | return ERR_CAST(inode); | 580 | return ERR_CAST(inode); |
| 540 | } | 581 | } |
| 541 | 582 | ||
| 583 | success: | ||
| 542 | dentry->d_op = &afs_fs_dentry_operations; | 584 | dentry->d_op = &afs_fs_dentry_operations; |
| 543 | 585 | ||
| 544 | d_add(dentry, inode); | 586 | d_add(dentry, inode); |
| @@ -696,8 +738,9 @@ static int afs_d_delete(struct dentry *dentry) | |||
| 696 | goto zap; | 738 | goto zap; |
| 697 | 739 | ||
| 698 | if (dentry->d_inode && | 740 | if (dentry->d_inode && |
| 699 | test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dentry->d_inode)->flags)) | 741 | (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dentry->d_inode)->flags) || |
| 700 | goto zap; | 742 | test_bit(AFS_VNODE_PSEUDODIR, &AFS_FS_I(dentry->d_inode)->flags))) |
| 743 | goto zap; | ||
| 701 | 744 | ||
| 702 | _leave(" = 0 [keep]"); | 745 | _leave(" = 0 [keep]"); |
| 703 | return 0; | 746 | return 0; |
diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 320ffef11574..0747339011c3 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c | |||
| @@ -19,6 +19,8 @@ | |||
| 19 | #include <linux/fs.h> | 19 | #include <linux/fs.h> |
| 20 | #include <linux/pagemap.h> | 20 | #include <linux/pagemap.h> |
| 21 | #include <linux/sched.h> | 21 | #include <linux/sched.h> |
| 22 | #include <linux/mount.h> | ||
| 23 | #include <linux/namei.h> | ||
| 22 | #include "internal.h" | 24 | #include "internal.h" |
| 23 | 25 | ||
| 24 | struct afs_iget_data { | 26 | struct afs_iget_data { |
| @@ -102,6 +104,16 @@ static int afs_iget5_test(struct inode *inode, void *opaque) | |||
| 102 | } | 104 | } |
| 103 | 105 | ||
| 104 | /* | 106 | /* |
| 107 | * iget5() comparator for inode created by autocell operations | ||
| 108 | * | ||
| 109 | * These pseudo inodes don't match anything. | ||
| 110 | */ | ||
| 111 | static int afs_iget5_autocell_test(struct inode *inode, void *opaque) | ||
| 112 | { | ||
| 113 | return 0; | ||
| 114 | } | ||
| 115 | |||
| 116 | /* | ||
| 105 | * iget5() inode initialiser | 117 | * iget5() inode initialiser |
| 106 | */ | 118 | */ |
| 107 | static int afs_iget5_set(struct inode *inode, void *opaque) | 119 | static int afs_iget5_set(struct inode *inode, void *opaque) |
| @@ -118,6 +130,67 @@ static int afs_iget5_set(struct inode *inode, void *opaque) | |||
| 118 | } | 130 | } |
| 119 | 131 | ||
| 120 | /* | 132 | /* |
| 133 | * inode retrieval for autocell | ||
| 134 | */ | ||
| 135 | struct inode *afs_iget_autocell(struct inode *dir, const char *dev_name, | ||
| 136 | int namesz, struct key *key) | ||
| 137 | { | ||
| 138 | struct afs_iget_data data; | ||
| 139 | struct afs_super_info *as; | ||
| 140 | struct afs_vnode *vnode; | ||
| 141 | struct super_block *sb; | ||
| 142 | struct inode *inode; | ||
| 143 | static atomic_t afs_autocell_ino; | ||
| 144 | |||
| 145 | _enter("{%x:%u},%*.*s,", | ||
| 146 | AFS_FS_I(dir)->fid.vid, AFS_FS_I(dir)->fid.vnode, | ||
| 147 | namesz, namesz, dev_name ?: ""); | ||
| 148 | |||
| 149 | sb = dir->i_sb; | ||
| 150 | as = sb->s_fs_info; | ||
| 151 | data.volume = as->volume; | ||
| 152 | data.fid.vid = as->volume->vid; | ||
| 153 | data.fid.unique = 0; | ||
| 154 | data.fid.vnode = 0; | ||
| 155 | |||
| 156 | inode = iget5_locked(sb, atomic_inc_return(&afs_autocell_ino), | ||
| 157 | afs_iget5_autocell_test, afs_iget5_set, | ||
| 158 | &data); | ||
| 159 | if (!inode) { | ||
| 160 | _leave(" = -ENOMEM"); | ||
| 161 | return ERR_PTR(-ENOMEM); | ||
| 162 | } | ||
| 163 | |||
| 164 | _debug("GOT INODE %p { ino=%lu, vl=%x, vn=%x, u=%x }", | ||
| 165 | inode, inode->i_ino, data.fid.vid, data.fid.vnode, | ||
| 166 | data.fid.unique); | ||
| 167 | |||
| 168 | vnode = AFS_FS_I(inode); | ||
| 169 | |||
| 170 | /* there shouldn't be an existing inode */ | ||
| 171 | BUG_ON(!(inode->i_state & I_NEW)); | ||
| 172 | |||
| 173 | inode->i_size = 0; | ||
| 174 | inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; | ||
| 175 | inode->i_op = &afs_autocell_inode_operations; | ||
| 176 | inode->i_nlink = 2; | ||
| 177 | inode->i_uid = 0; | ||
| 178 | inode->i_gid = 0; | ||
| 179 | inode->i_ctime.tv_sec = get_seconds(); | ||
| 180 | inode->i_ctime.tv_nsec = 0; | ||
| 181 | inode->i_atime = inode->i_mtime = inode->i_ctime; | ||
| 182 | inode->i_blocks = 0; | ||
| 183 | inode->i_version = 0; | ||
| 184 | inode->i_generation = 0; | ||
| 185 | |||
| 186 | set_bit(AFS_VNODE_PSEUDODIR, &vnode->flags); | ||
| 187 | inode->i_flags |= S_NOATIME; | ||
| 188 | unlock_new_inode(inode); | ||
| 189 | _leave(" = %p", inode); | ||
| 190 | return inode; | ||
| 191 | } | ||
| 192 | |||
| 193 | /* | ||
| 121 | * inode retrieval | 194 | * inode retrieval |
| 122 | */ | 195 | */ |
| 123 | struct inode *afs_iget(struct super_block *sb, struct key *key, | 196 | struct inode *afs_iget(struct super_block *sb, struct key *key, |
| @@ -314,6 +387,19 @@ int afs_getattr(struct vfsmount *mnt, struct dentry *dentry, | |||
| 314 | } | 387 | } |
| 315 | 388 | ||
| 316 | /* | 389 | /* |
| 390 | * discard an AFS inode | ||
| 391 | */ | ||
| 392 | int afs_drop_inode(struct inode *inode) | ||
| 393 | { | ||
| 394 | _enter(""); | ||
| 395 | |||
| 396 | if (test_bit(AFS_VNODE_PSEUDODIR, &AFS_FS_I(inode)->flags)) | ||
| 397 | return generic_delete_inode(inode); | ||
| 398 | else | ||
| 399 | return generic_drop_inode(inode); | ||
| 400 | } | ||
| 401 | |||
| 402 | /* | ||
| 317 | * clear an AFS inode | 403 | * clear an AFS inode |
| 318 | */ | 404 | */ |
| 319 | void afs_evict_inode(struct inode *inode) | 405 | void afs_evict_inode(struct inode *inode) |
diff --git a/fs/afs/internal.h b/fs/afs/internal.h index c6c93f180707..cca8eef736fc 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h | |||
| @@ -42,6 +42,7 @@ typedef enum { | |||
| 42 | struct afs_mount_params { | 42 | struct afs_mount_params { |
| 43 | bool rwpath; /* T if the parent should be considered R/W */ | 43 | bool rwpath; /* T if the parent should be considered R/W */ |
| 44 | bool force; /* T to force cell type */ | 44 | bool force; /* T to force cell type */ |
| 45 | bool autocell; /* T if set auto mount operation */ | ||
| 45 | afs_voltype_t type; /* type of volume requested */ | 46 | afs_voltype_t type; /* type of volume requested */ |
| 46 | int volnamesz; /* size of volume name */ | 47 | int volnamesz; /* size of volume name */ |
| 47 | const char *volname; /* name of volume to mount */ | 48 | const char *volname; /* name of volume to mount */ |
| @@ -358,6 +359,8 @@ struct afs_vnode { | |||
| 358 | #define AFS_VNODE_READLOCKED 7 /* set if vnode is read-locked on the server */ | 359 | #define AFS_VNODE_READLOCKED 7 /* set if vnode is read-locked on the server */ |
| 359 | #define AFS_VNODE_WRITELOCKED 8 /* set if vnode is write-locked on the server */ | 360 | #define AFS_VNODE_WRITELOCKED 8 /* set if vnode is write-locked on the server */ |
| 360 | #define AFS_VNODE_UNLOCKING 9 /* set if vnode is being unlocked on the server */ | 361 | #define AFS_VNODE_UNLOCKING 9 /* set if vnode is being unlocked on the server */ |
| 362 | #define AFS_VNODE_AUTOCELL 10 /* set if Vnode is an auto mount point */ | ||
| 363 | #define AFS_VNODE_PSEUDODIR 11 /* set if Vnode is a pseudo directory */ | ||
| 361 | 364 | ||
| 362 | long acl_order; /* ACL check count (callback break count) */ | 365 | long acl_order; /* ACL check count (callback break count) */ |
| 363 | 366 | ||
| @@ -468,8 +471,8 @@ extern struct list_head afs_proc_cells; | |||
| 468 | 471 | ||
| 469 | #define afs_get_cell(C) do { atomic_inc(&(C)->usage); } while(0) | 472 | #define afs_get_cell(C) do { atomic_inc(&(C)->usage); } while(0) |
| 470 | extern int afs_cell_init(char *); | 473 | extern int afs_cell_init(char *); |
| 471 | extern struct afs_cell *afs_cell_create(const char *, char *); | 474 | extern struct afs_cell *afs_cell_create(const char *, unsigned, char *, bool); |
| 472 | extern struct afs_cell *afs_cell_lookup(const char *, unsigned); | 475 | extern struct afs_cell *afs_cell_lookup(const char *, unsigned, bool); |
| 473 | extern struct afs_cell *afs_grab_cell(struct afs_cell *); | 476 | extern struct afs_cell *afs_grab_cell(struct afs_cell *); |
| 474 | extern void afs_put_cell(struct afs_cell *); | 477 | extern void afs_put_cell(struct afs_cell *); |
| 475 | extern void afs_cell_purge(void); | 478 | extern void afs_cell_purge(void); |
| @@ -558,6 +561,8 @@ extern int afs_fs_release_lock(struct afs_server *, struct key *, | |||
| 558 | /* | 561 | /* |
| 559 | * inode.c | 562 | * inode.c |
| 560 | */ | 563 | */ |
| 564 | extern struct inode *afs_iget_autocell(struct inode *, const char *, int, | ||
| 565 | struct key *); | ||
| 561 | extern struct inode *afs_iget(struct super_block *, struct key *, | 566 | extern struct inode *afs_iget(struct super_block *, struct key *, |
| 562 | struct afs_fid *, struct afs_file_status *, | 567 | struct afs_fid *, struct afs_file_status *, |
| 563 | struct afs_callback *); | 568 | struct afs_callback *); |
| @@ -566,6 +571,7 @@ extern int afs_validate(struct afs_vnode *, struct key *); | |||
| 566 | extern int afs_getattr(struct vfsmount *, struct dentry *, struct kstat *); | 571 | extern int afs_getattr(struct vfsmount *, struct dentry *, struct kstat *); |
| 567 | extern int afs_setattr(struct dentry *, struct iattr *); | 572 | extern int afs_setattr(struct dentry *, struct iattr *); |
| 568 | extern void afs_evict_inode(struct inode *); | 573 | extern void afs_evict_inode(struct inode *); |
| 574 | extern int afs_drop_inode(struct inode *); | ||
| 569 | 575 | ||
| 570 | /* | 576 | /* |
| 571 | * main.c | 577 | * main.c |
| @@ -581,6 +587,7 @@ extern int afs_abort_to_error(u32); | |||
| 581 | * mntpt.c | 587 | * mntpt.c |
| 582 | */ | 588 | */ |
| 583 | extern const struct inode_operations afs_mntpt_inode_operations; | 589 | extern const struct inode_operations afs_mntpt_inode_operations; |
| 590 | extern const struct inode_operations afs_autocell_inode_operations; | ||
| 584 | extern const struct file_operations afs_mntpt_file_operations; | 591 | extern const struct file_operations afs_mntpt_file_operations; |
| 585 | 592 | ||
| 586 | extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *); | 593 | extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *); |
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index a9e23039ea34..6d552686c498 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c | |||
| @@ -38,6 +38,11 @@ const struct inode_operations afs_mntpt_inode_operations = { | |||
| 38 | .getattr = afs_getattr, | 38 | .getattr = afs_getattr, |
| 39 | }; | 39 | }; |
| 40 | 40 | ||
| 41 | const struct inode_operations afs_autocell_inode_operations = { | ||
| 42 | .follow_link = afs_mntpt_follow_link, | ||
| 43 | .getattr = afs_getattr, | ||
| 44 | }; | ||
| 45 | |||
| 41 | static LIST_HEAD(afs_vfsmounts); | 46 | static LIST_HEAD(afs_vfsmounts); |
| 42 | static DECLARE_DELAYED_WORK(afs_mntpt_expiry_timer, afs_mntpt_expiry_timed_out); | 47 | static DECLARE_DELAYED_WORK(afs_mntpt_expiry_timer, afs_mntpt_expiry_timed_out); |
| 43 | 48 | ||
| @@ -136,20 +141,16 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) | |||
| 136 | { | 141 | { |
| 137 | struct afs_super_info *super; | 142 | struct afs_super_info *super; |
| 138 | struct vfsmount *mnt; | 143 | struct vfsmount *mnt; |
| 144 | struct afs_vnode *vnode; | ||
| 139 | struct page *page; | 145 | struct page *page; |
| 140 | size_t size; | 146 | char *devname, *options; |
| 141 | char *buf, *devname, *options; | 147 | bool rwpath = false; |
| 142 | int ret; | 148 | int ret; |
| 143 | 149 | ||
| 144 | _enter("{%s}", mntpt->d_name.name); | 150 | _enter("{%s}", mntpt->d_name.name); |
| 145 | 151 | ||
| 146 | BUG_ON(!mntpt->d_inode); | 152 | BUG_ON(!mntpt->d_inode); |
| 147 | 153 | ||
| 148 | ret = -EINVAL; | ||
| 149 | size = mntpt->d_inode->i_size; | ||
| 150 | if (size > PAGE_SIZE - 1) | ||
| 151 | goto error_no_devname; | ||
| 152 | |||
| 153 | ret = -ENOMEM; | 154 | ret = -ENOMEM; |
| 154 | devname = (char *) get_zeroed_page(GFP_KERNEL); | 155 | devname = (char *) get_zeroed_page(GFP_KERNEL); |
| 155 | if (!devname) | 156 | if (!devname) |
| @@ -159,28 +160,59 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) | |||
| 159 | if (!options) | 160 | if (!options) |
| 160 | goto error_no_options; | 161 | goto error_no_options; |
| 161 | 162 | ||
| 162 | /* read the contents of the AFS special symlink */ | 163 | vnode = AFS_FS_I(mntpt->d_inode); |
| 163 | page = read_mapping_page(mntpt->d_inode->i_mapping, 0, NULL); | 164 | if (test_bit(AFS_VNODE_PSEUDODIR, &vnode->flags)) { |
| 164 | if (IS_ERR(page)) { | 165 | /* if the directory is a pseudo directory, use the d_name */ |
| 165 | ret = PTR_ERR(page); | 166 | static const char afs_root_cell[] = ":root.cell."; |
| 166 | goto error_no_page; | 167 | unsigned size = mntpt->d_name.len; |
| 168 | |||
| 169 | ret = -ENOENT; | ||
| 170 | if (size < 2 || size > AFS_MAXCELLNAME) | ||
| 171 | goto error_no_page; | ||
| 172 | |||
| 173 | if (mntpt->d_name.name[0] == '.') { | ||
| 174 | devname[0] = '#'; | ||
| 175 | memcpy(devname + 1, mntpt->d_name.name, size - 1); | ||
| 176 | memcpy(devname + size, afs_root_cell, | ||
| 177 | sizeof(afs_root_cell)); | ||
| 178 | rwpath = true; | ||
| 179 | } else { | ||
| 180 | devname[0] = '%'; | ||
| 181 | memcpy(devname + 1, mntpt->d_name.name, size); | ||
| 182 | memcpy(devname + size + 1, afs_root_cell, | ||
| 183 | sizeof(afs_root_cell)); | ||
| 184 | } | ||
| 185 | } else { | ||
| 186 | /* read the contents of the AFS special symlink */ | ||
| 187 | loff_t size = i_size_read(mntpt->d_inode); | ||
| 188 | char *buf; | ||
| 189 | |||
| 190 | ret = -EINVAL; | ||
| 191 | if (size > PAGE_SIZE - 1) | ||
| 192 | goto error_no_page; | ||
| 193 | |||
| 194 | page = read_mapping_page(mntpt->d_inode->i_mapping, 0, NULL); | ||
| 195 | if (IS_ERR(page)) { | ||
| 196 | ret = PTR_ERR(page); | ||
| 197 | goto error_no_page; | ||
| 198 | } | ||
| 199 | |||
| 200 | ret = -EIO; | ||
| 201 | if (PageError(page)) | ||
| 202 | goto error; | ||
| 203 | |||
| 204 | buf = kmap_atomic(page, KM_USER0); | ||
| 205 | memcpy(devname, buf, size); | ||
| 206 | kunmap_atomic(buf, KM_USER0); | ||
| 207 | page_cache_release(page); | ||
| 208 | page = NULL; | ||
| 167 | } | 209 | } |
| 168 | 210 | ||
| 169 | ret = -EIO; | ||
| 170 | if (PageError(page)) | ||
| 171 | goto error; | ||
| 172 | |||
| 173 | buf = kmap_atomic(page, KM_USER0); | ||
| 174 | memcpy(devname, buf, size); | ||
| 175 | kunmap_atomic(buf, KM_USER0); | ||
| 176 | page_cache_release(page); | ||
| 177 | page = NULL; | ||
| 178 | |||
| 179 | /* work out what options we want */ | 211 | /* work out what options we want */ |
| 180 | super = AFS_FS_S(mntpt->d_sb); | 212 | super = AFS_FS_S(mntpt->d_sb); |
| 181 | memcpy(options, "cell=", 5); | 213 | memcpy(options, "cell=", 5); |
| 182 | strcpy(options + 5, super->volume->cell->name); | 214 | strcpy(options + 5, super->volume->cell->name); |
| 183 | if (super->volume->type == AFSVL_RWVOL) | 215 | if (super->volume->type == AFSVL_RWVOL || rwpath) |
| 184 | strcat(options, ",rwpath"); | 216 | strcat(options, ",rwpath"); |
| 185 | 217 | ||
| 186 | /* try and do the mount */ | 218 | /* try and do the mount */ |
diff --git a/fs/afs/proc.c b/fs/afs/proc.c index 852739d262a9..096b23f821a1 100644 --- a/fs/afs/proc.c +++ b/fs/afs/proc.c | |||
| @@ -294,7 +294,7 @@ static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf, | |||
| 294 | if (strcmp(kbuf, "add") == 0) { | 294 | if (strcmp(kbuf, "add") == 0) { |
| 295 | struct afs_cell *cell; | 295 | struct afs_cell *cell; |
| 296 | 296 | ||
| 297 | cell = afs_cell_create(name, args); | 297 | cell = afs_cell_create(name, strlen(name), args, false); |
| 298 | if (IS_ERR(cell)) { | 298 | if (IS_ERR(cell)) { |
| 299 | ret = PTR_ERR(cell); | 299 | ret = PTR_ERR(cell); |
| 300 | goto done; | 300 | goto done; |
diff --git a/fs/afs/super.c b/fs/afs/super.c index 9cf80f02da16..77e1e5a61154 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | 16 | ||
| 17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
| 18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
| 19 | #include <linux/mount.h> | ||
| 19 | #include <linux/init.h> | 20 | #include <linux/init.h> |
| 20 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
| 21 | #include <linux/smp_lock.h> | 22 | #include <linux/smp_lock.h> |
| @@ -48,6 +49,7 @@ struct file_system_type afs_fs_type = { | |||
| 48 | static const struct super_operations afs_super_ops = { | 49 | static const struct super_operations afs_super_ops = { |
| 49 | .statfs = afs_statfs, | 50 | .statfs = afs_statfs, |
| 50 | .alloc_inode = afs_alloc_inode, | 51 | .alloc_inode = afs_alloc_inode, |
| 52 | .drop_inode = afs_drop_inode, | ||
| 51 | .destroy_inode = afs_destroy_inode, | 53 | .destroy_inode = afs_destroy_inode, |
| 52 | .evict_inode = afs_evict_inode, | 54 | .evict_inode = afs_evict_inode, |
| 53 | .put_super = afs_put_super, | 55 | .put_super = afs_put_super, |
| @@ -62,12 +64,14 @@ enum { | |||
| 62 | afs_opt_cell, | 64 | afs_opt_cell, |
| 63 | afs_opt_rwpath, | 65 | afs_opt_rwpath, |
| 64 | afs_opt_vol, | 66 | afs_opt_vol, |
| 67 | afs_opt_autocell, | ||
| 65 | }; | 68 | }; |
| 66 | 69 | ||
| 67 | static const match_table_t afs_options_list = { | 70 | static const match_table_t afs_options_list = { |
| 68 | { afs_opt_cell, "cell=%s" }, | 71 | { afs_opt_cell, "cell=%s" }, |
| 69 | { afs_opt_rwpath, "rwpath" }, | 72 | { afs_opt_rwpath, "rwpath" }, |
| 70 | { afs_opt_vol, "vol=%s" }, | 73 | { afs_opt_vol, "vol=%s" }, |
| 74 | { afs_opt_autocell, "autocell" }, | ||
| 71 | { afs_no_opt, NULL }, | 75 | { afs_no_opt, NULL }, |
| 72 | }; | 76 | }; |
| 73 | 77 | ||
| @@ -151,7 +155,8 @@ static int afs_parse_options(struct afs_mount_params *params, | |||
| 151 | switch (token) { | 155 | switch (token) { |
| 152 | case afs_opt_cell: | 156 | case afs_opt_cell: |
| 153 | cell = afs_cell_lookup(args[0].from, | 157 | cell = afs_cell_lookup(args[0].from, |
| 154 | args[0].to - args[0].from); | 158 | args[0].to - args[0].from, |
| 159 | false); | ||
| 155 | if (IS_ERR(cell)) | 160 | if (IS_ERR(cell)) |
| 156 | return PTR_ERR(cell); | 161 | return PTR_ERR(cell); |
| 157 | afs_put_cell(params->cell); | 162 | afs_put_cell(params->cell); |
| @@ -166,6 +171,10 @@ static int afs_parse_options(struct afs_mount_params *params, | |||
| 166 | *devname = args[0].from; | 171 | *devname = args[0].from; |
| 167 | break; | 172 | break; |
| 168 | 173 | ||
| 174 | case afs_opt_autocell: | ||
| 175 | params->autocell = 1; | ||
| 176 | break; | ||
| 177 | |||
| 169 | default: | 178 | default: |
| 170 | printk(KERN_ERR "kAFS:" | 179 | printk(KERN_ERR "kAFS:" |
| 171 | " Unknown or invalid mount option: '%s'\n", p); | 180 | " Unknown or invalid mount option: '%s'\n", p); |
| @@ -252,10 +261,10 @@ static int afs_parse_device_name(struct afs_mount_params *params, | |||
| 252 | 261 | ||
| 253 | /* lookup the cell record */ | 262 | /* lookup the cell record */ |
| 254 | if (cellname || !params->cell) { | 263 | if (cellname || !params->cell) { |
| 255 | cell = afs_cell_lookup(cellname, cellnamesz); | 264 | cell = afs_cell_lookup(cellname, cellnamesz, true); |
| 256 | if (IS_ERR(cell)) { | 265 | if (IS_ERR(cell)) { |
| 257 | printk(KERN_ERR "kAFS: unable to lookup cell '%s'\n", | 266 | printk(KERN_ERR "kAFS: unable to lookup cell '%*.*s'\n", |
| 258 | cellname ?: ""); | 267 | cellnamesz, cellnamesz, cellname ?: ""); |
| 259 | return PTR_ERR(cell); | 268 | return PTR_ERR(cell); |
| 260 | } | 269 | } |
| 261 | afs_put_cell(params->cell); | 270 | afs_put_cell(params->cell); |
| @@ -321,6 +330,9 @@ static int afs_fill_super(struct super_block *sb, void *data) | |||
| 321 | if (IS_ERR(inode)) | 330 | if (IS_ERR(inode)) |
| 322 | goto error_inode; | 331 | goto error_inode; |
| 323 | 332 | ||
| 333 | if (params->autocell) | ||
| 334 | set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags); | ||
| 335 | |||
| 324 | ret = -ENOMEM; | 336 | ret = -ENOMEM; |
| 325 | root = d_alloc_root(inode); | 337 | root = d_alloc_root(inode); |
| 326 | if (!root) | 338 | if (!root) |
diff --git a/fs/cifs/README b/fs/cifs/README index a7081eeeb85d..7099a526f775 100644 --- a/fs/cifs/README +++ b/fs/cifs/README | |||
| @@ -301,6 +301,16 @@ A partial list of the supported mount options follows: | |||
| 301 | gid Set the default gid for inodes (similar to above). | 301 | gid Set the default gid for inodes (similar to above). |
| 302 | file_mode If CIFS Unix extensions are not supported by the server | 302 | file_mode If CIFS Unix extensions are not supported by the server |
| 303 | this overrides the default mode for file inodes. | 303 | this overrides the default mode for file inodes. |
| 304 | fsc Enable local disk caching using FS-Cache (off by default). This | ||
| 305 | option could be useful to improve performance on a slow link, | ||
| 306 | heavily loaded server and/or network where reading from the | ||
| 307 | disk is faster than reading from the server (over the network). | ||
| 308 | This could also impact scalability positively as the | ||
| 309 | number of calls to the server are reduced. However, local | ||
| 310 | caching is not suitable for all workloads for e.g. read-once | ||
| 311 | type workloads. So, you need to consider carefully your | ||
| 312 | workload/scenario before using this option. Currently, local | ||
| 313 | disk caching is functional for CIFS files opened as read-only. | ||
| 304 | dir_mode If CIFS Unix extensions are not supported by the server | 314 | dir_mode If CIFS Unix extensions are not supported by the server |
| 305 | this overrides the default mode for directory inodes. | 315 | this overrides the default mode for directory inodes. |
| 306 | port attempt to contact the server on this tcp port, before | 316 | port attempt to contact the server on this tcp port, before |
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig index cc1bb33b59b8..26a510a7be09 100644 --- a/fs/nfs/Kconfig +++ b/fs/nfs/Kconfig | |||
| @@ -100,3 +100,20 @@ config NFS_FSCACHE | |||
| 100 | help | 100 | help |
| 101 | Say Y here if you want NFS data to be cached locally on disc through | 101 | Say Y here if you want NFS data to be cached locally on disc through |
| 102 | the general filesystem cache manager | 102 | the general filesystem cache manager |
| 103 | |||
| 104 | config NFS_USE_LEGACY_DNS | ||
| 105 | bool "Use the legacy NFS DNS resolver" | ||
| 106 | depends on NFS_V4 | ||
| 107 | help | ||
| 108 | The kernel now provides a method for translating a host name into an | ||
| 109 | IP address. Select Y here if you would rather use your own DNS | ||
| 110 | resolver script. | ||
| 111 | |||
| 112 | If unsure, say N | ||
| 113 | |||
| 114 | config NFS_USE_KERNEL_DNS | ||
| 115 | bool | ||
| 116 | depends on NFS_V4 && !NFS_USE_LEGACY_DNS | ||
| 117 | select DNS_RESOLVER | ||
| 118 | select KEYS | ||
| 119 | default y | ||
diff --git a/fs/nfs/dns_resolve.c b/fs/nfs/dns_resolve.c index 76fd235d0024..dba50a5625db 100644 --- a/fs/nfs/dns_resolve.c +++ b/fs/nfs/dns_resolve.c | |||
| @@ -6,6 +6,29 @@ | |||
| 6 | * Resolves DNS hostnames into valid ip addresses | 6 | * Resolves DNS hostnames into valid ip addresses |
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #ifdef CONFIG_NFS_USE_KERNEL_DNS | ||
| 10 | |||
| 11 | #include <linux/sunrpc/clnt.h> | ||
| 12 | #include <linux/dns_resolver.h> | ||
| 13 | |||
| 14 | ssize_t nfs_dns_resolve_name(char *name, size_t namelen, | ||
| 15 | struct sockaddr *sa, size_t salen) | ||
| 16 | { | ||
| 17 | ssize_t ret; | ||
| 18 | char *ip_addr = NULL; | ||
| 19 | int ip_len; | ||
| 20 | |||
| 21 | ip_len = dns_query(NULL, name, namelen, NULL, &ip_addr, NULL); | ||
| 22 | if (ip_len > 0) | ||
| 23 | ret = rpc_pton(ip_addr, ip_len, sa, salen); | ||
| 24 | else | ||
| 25 | ret = -ESRCH; | ||
| 26 | kfree(ip_addr); | ||
| 27 | return ret; | ||
| 28 | } | ||
| 29 | |||
| 30 | #else | ||
| 31 | |||
| 9 | #include <linux/hash.h> | 32 | #include <linux/hash.h> |
| 10 | #include <linux/string.h> | 33 | #include <linux/string.h> |
| 11 | #include <linux/kmod.h> | 34 | #include <linux/kmod.h> |
| @@ -346,3 +369,4 @@ void nfs_dns_resolver_destroy(void) | |||
| 346 | nfs_cache_unregister(&nfs_dns_resolve); | 369 | nfs_cache_unregister(&nfs_dns_resolve); |
| 347 | } | 370 | } |
| 348 | 371 | ||
| 372 | #endif | ||
diff --git a/fs/nfs/dns_resolve.h b/fs/nfs/dns_resolve.h index a3f0938babf7..199bb5543a91 100644 --- a/fs/nfs/dns_resolve.h +++ b/fs/nfs/dns_resolve.h | |||
| @@ -6,8 +6,20 @@ | |||
| 6 | 6 | ||
| 7 | #define NFS_DNS_HOSTNAME_MAXLEN (128) | 7 | #define NFS_DNS_HOSTNAME_MAXLEN (128) |
| 8 | 8 | ||
| 9 | |||
| 10 | #ifdef CONFIG_NFS_USE_KERNEL_DNS | ||
| 11 | static inline int nfs_dns_resolver_init(void) | ||
| 12 | { | ||
| 13 | return 0; | ||
| 14 | } | ||
| 15 | |||
| 16 | static inline void nfs_dns_resolver_destroy(void) | ||
| 17 | {} | ||
| 18 | #else | ||
| 9 | extern int nfs_dns_resolver_init(void); | 19 | extern int nfs_dns_resolver_init(void); |
| 10 | extern void nfs_dns_resolver_destroy(void); | 20 | extern void nfs_dns_resolver_destroy(void); |
| 21 | #endif | ||
| 22 | |||
| 11 | extern ssize_t nfs_dns_resolve_name(char *name, size_t namelen, | 23 | extern ssize_t nfs_dns_resolve_name(char *name, size_t namelen, |
| 12 | struct sockaddr *sa, size_t salen); | 24 | struct sockaddr *sa, size_t salen); |
| 13 | 25 | ||
diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c index 400a04d5c9a1..739435a6af39 100644 --- a/net/dns_resolver/dns_key.c +++ b/net/dns_resolver/dns_key.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
| 30 | #include <linux/keyctl.h> | 30 | #include <linux/keyctl.h> |
| 31 | #include <linux/err.h> | 31 | #include <linux/err.h> |
| 32 | #include <linux/seq_file.h> | ||
| 32 | #include <keys/dns_resolver-type.h> | 33 | #include <keys/dns_resolver-type.h> |
| 33 | #include <keys/user-type.h> | 34 | #include <keys/user-type.h> |
| 34 | #include "internal.h" | 35 | #include "internal.h" |
| @@ -43,6 +44,8 @@ MODULE_PARM_DESC(debug, "DNS Resolver debugging mask"); | |||
| 43 | 44 | ||
| 44 | const struct cred *dns_resolver_cache; | 45 | const struct cred *dns_resolver_cache; |
| 45 | 46 | ||
| 47 | #define DNS_ERRORNO_OPTION "dnserror" | ||
| 48 | |||
| 46 | /* | 49 | /* |
| 47 | * Instantiate a user defined key for dns_resolver. | 50 | * Instantiate a user defined key for dns_resolver. |
| 48 | * | 51 | * |
| @@ -59,9 +62,10 @@ static int | |||
| 59 | dns_resolver_instantiate(struct key *key, const void *_data, size_t datalen) | 62 | dns_resolver_instantiate(struct key *key, const void *_data, size_t datalen) |
| 60 | { | 63 | { |
| 61 | struct user_key_payload *upayload; | 64 | struct user_key_payload *upayload; |
| 65 | unsigned long derrno; | ||
| 62 | int ret; | 66 | int ret; |
| 63 | size_t result_len = 0; | 67 | size_t result_len = 0; |
| 64 | const char *data = _data, *opt; | 68 | const char *data = _data, *end, *opt; |
| 65 | 69 | ||
| 66 | kenter("%%%d,%s,'%s',%zu", | 70 | kenter("%%%d,%s,'%s',%zu", |
| 67 | key->serial, key->description, data, datalen); | 71 | key->serial, key->description, data, datalen); |
| @@ -71,13 +75,77 @@ dns_resolver_instantiate(struct key *key, const void *_data, size_t datalen) | |||
| 71 | datalen--; | 75 | datalen--; |
| 72 | 76 | ||
| 73 | /* deal with any options embedded in the data */ | 77 | /* deal with any options embedded in the data */ |
| 78 | end = data + datalen; | ||
| 74 | opt = memchr(data, '#', datalen); | 79 | opt = memchr(data, '#', datalen); |
| 75 | if (!opt) { | 80 | if (!opt) { |
| 76 | kdebug("no options currently supported"); | 81 | /* no options: the entire data is the result */ |
| 77 | return -EINVAL; | 82 | kdebug("no options"); |
| 83 | result_len = datalen; | ||
| 84 | } else { | ||
| 85 | const char *next_opt; | ||
| 86 | |||
| 87 | result_len = opt - data; | ||
| 88 | opt++; | ||
| 89 | kdebug("options: '%s'", opt); | ||
| 90 | do { | ||
| 91 | const char *eq; | ||
| 92 | int opt_len, opt_nlen, opt_vlen, tmp; | ||
| 93 | |||
| 94 | next_opt = memchr(opt, '#', end - opt) ?: end; | ||
| 95 | opt_len = next_opt - opt; | ||
| 96 | if (!opt_len) { | ||
| 97 | printk(KERN_WARNING | ||
| 98 | "Empty option to dns_resolver key %d\n", | ||
| 99 | key->serial); | ||
| 100 | return -EINVAL; | ||
| 101 | } | ||
| 102 | |||
| 103 | eq = memchr(opt, '=', opt_len) ?: end; | ||
| 104 | opt_nlen = eq - opt; | ||
| 105 | eq++; | ||
| 106 | opt_vlen = next_opt - eq; /* will be -1 if no value */ | ||
| 107 | |||
| 108 | tmp = opt_vlen >= 0 ? opt_vlen : 0; | ||
| 109 | kdebug("option '%*.*s' val '%*.*s'", | ||
| 110 | opt_nlen, opt_nlen, opt, tmp, tmp, eq); | ||
| 111 | |||
| 112 | /* see if it's an error number representing a DNS error | ||
| 113 | * that's to be recorded as the result in this key */ | ||
| 114 | if (opt_nlen == sizeof(DNS_ERRORNO_OPTION) - 1 && | ||
| 115 | memcmp(opt, DNS_ERRORNO_OPTION, opt_nlen) == 0) { | ||
| 116 | kdebug("dns error number option"); | ||
| 117 | if (opt_vlen <= 0) | ||
| 118 | goto bad_option_value; | ||
| 119 | |||
| 120 | ret = strict_strtoul(eq, 10, &derrno); | ||
| 121 | if (ret < 0) | ||
| 122 | goto bad_option_value; | ||
| 123 | |||
| 124 | if (derrno < 1 || derrno > 511) | ||
| 125 | goto bad_option_value; | ||
| 126 | |||
| 127 | kdebug("dns error no. = %lu", derrno); | ||
| 128 | key->type_data.x[0] = -derrno; | ||
| 129 | continue; | ||
| 130 | } | ||
| 131 | |||
| 132 | bad_option_value: | ||
| 133 | printk(KERN_WARNING | ||
| 134 | "Option '%*.*s' to dns_resolver key %d:" | ||
| 135 | " bad/missing value\n", | ||
| 136 | opt_nlen, opt_nlen, opt, key->serial); | ||
| 137 | return -EINVAL; | ||
| 138 | } while (opt = next_opt + 1, opt < end); | ||
| 139 | } | ||
| 140 | |||
| 141 | /* don't cache the result if we're caching an error saying there's no | ||
| 142 | * result */ | ||
| 143 | if (key->type_data.x[0]) { | ||
| 144 | kleave(" = 0 [h_error %ld]", key->type_data.x[0]); | ||
| 145 | return 0; | ||
| 78 | } | 146 | } |
| 79 | 147 | ||
| 80 | result_len = datalen; | 148 | kdebug("store result"); |
| 81 | ret = key_payload_reserve(key, result_len); | 149 | ret = key_payload_reserve(key, result_len); |
| 82 | if (ret < 0) | 150 | if (ret < 0) |
| 83 | return -EINVAL; | 151 | return -EINVAL; |
| @@ -135,13 +203,27 @@ no_match: | |||
| 135 | return ret; | 203 | return ret; |
| 136 | } | 204 | } |
| 137 | 205 | ||
| 206 | /* | ||
| 207 | * Describe a DNS key | ||
| 208 | */ | ||
| 209 | static void dns_resolver_describe(const struct key *key, struct seq_file *m) | ||
| 210 | { | ||
| 211 | int err = key->type_data.x[0]; | ||
| 212 | |||
| 213 | seq_puts(m, key->description); | ||
| 214 | if (err) | ||
| 215 | seq_printf(m, ": %d", err); | ||
| 216 | else | ||
| 217 | seq_printf(m, ": %u", key->datalen); | ||
| 218 | } | ||
| 219 | |||
| 138 | struct key_type key_type_dns_resolver = { | 220 | struct key_type key_type_dns_resolver = { |
| 139 | .name = "dns_resolver", | 221 | .name = "dns_resolver", |
| 140 | .instantiate = dns_resolver_instantiate, | 222 | .instantiate = dns_resolver_instantiate, |
| 141 | .match = dns_resolver_match, | 223 | .match = dns_resolver_match, |
| 142 | .revoke = user_revoke, | 224 | .revoke = user_revoke, |
| 143 | .destroy = user_destroy, | 225 | .destroy = user_destroy, |
| 144 | .describe = user_describe, | 226 | .describe = dns_resolver_describe, |
| 145 | .read = user_read, | 227 | .read = user_read, |
| 146 | }; | 228 | }; |
| 147 | 229 | ||
diff --git a/net/dns_resolver/dns_query.c b/net/dns_resolver/dns_query.c index 03d5255f5cf2..c32be292c7e3 100644 --- a/net/dns_resolver/dns_query.c +++ b/net/dns_resolver/dns_query.c | |||
| @@ -136,6 +136,11 @@ int dns_query(const char *type, const char *name, size_t namelen, | |||
| 136 | if (ret < 0) | 136 | if (ret < 0) |
| 137 | goto put; | 137 | goto put; |
| 138 | 138 | ||
| 139 | /* If the DNS server gave an error, return that to the caller */ | ||
| 140 | ret = rkey->type_data.x[0]; | ||
| 141 | if (ret) | ||
| 142 | goto put; | ||
| 143 | |||
| 139 | upayload = rcu_dereference_protected(rkey->payload.data, | 144 | upayload = rcu_dereference_protected(rkey->payload.data, |
| 140 | lockdep_is_held(&rkey->sem)); | 145 | lockdep_is_held(&rkey->sem)); |
| 141 | len = upayload->datalen; | 146 | len = upayload->datalen; |
