Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

+409 -51
+42 -14
fs/afs/cell.c
··· 31 31 * allocate a cell record and fill in its name, VL server address list and 32 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 37 struct afs_cell *cell; 37 38 struct key *key; 38 - size_t namelen; 39 39 char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next; 40 40 char *dvllist = NULL, *_vllist = NULL; 41 41 char delimiter = ':'; 42 42 int ret; 43 43 44 - _enter("%s,%s", name, vllist); 44 + _enter("%*.*s,%s", namelen, namelen, name ?: "", vllist); 45 45 46 46 BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */ 47 47 48 - namelen = strlen(name); 49 48 if (namelen > AFS_MAXCELLNAME) { 50 49 _leave(" = -ENAMETOOLONG"); 51 50 return ERR_PTR(-ENAMETOOLONG); ··· 72 73 if (!vllist || strlen(vllist) < 7) { 73 74 ret = dns_query("afsdb", name, namelen, "ipv4", &dvllist, NULL); 74 75 if (ret < 0) { 76 + if (ret == -ENODATA || ret == -EAGAIN || ret == -ENOKEY) 77 + /* translate these errors into something 78 + * userspace might understand */ 79 + ret = -EDESTADDRREQ; 75 80 _leave(" = %d", ret); 76 81 return ERR_PTR(ret); 77 82 } ··· 141 138 } 142 139 143 140 /* 144 - * create a cell record 145 - * - "name" is the name of the cell 146 - * - "vllist" is a colon separated list of IP addresses in "a.b.c.d" format 141 + * afs_cell_crate() - create a cell record 142 + * @name: is the name of the cell. 143 + * @namsesz: is the strlen of the cell name. 144 + * @vllist: is a colon separated list of IP addresses in "a.b.c.d" format. 145 + * @retref: is T to return the cell reference when the cell exists. 147 146 */ 148 - struct afs_cell *afs_cell_create(const char *name, char *vllist) 147 + struct afs_cell *afs_cell_create(const char *name, unsigned namesz, 148 + char *vllist, bool retref) 149 149 { 150 150 struct afs_cell *cell; 151 151 int ret; 152 152 153 - _enter("%s,%s", name, vllist); 153 + _enter("%*.*s,%s", namesz, namesz, name ?: "", vllist); 154 154 155 155 down_write(&afs_cells_sem); 156 156 read_lock(&afs_cells_lock); 157 157 list_for_each_entry(cell, &afs_cells, link) { 158 - if (strcasecmp(cell->name, name) == 0) 158 + if (strncasecmp(cell->name, name, namesz) == 0) 159 159 goto duplicate_name; 160 160 } 161 161 read_unlock(&afs_cells_lock); 162 162 163 - cell = afs_cell_alloc(name, vllist); 163 + cell = afs_cell_alloc(name, namesz, vllist); 164 164 if (IS_ERR(cell)) { 165 165 _leave(" = %ld", PTR_ERR(cell)); 166 166 up_write(&afs_cells_sem); ··· 203 197 return ERR_PTR(ret); 204 198 205 199 duplicate_name: 200 + if (retref && !IS_ERR(cell)) 201 + afs_get_cell(cell); 202 + 206 203 read_unlock(&afs_cells_lock); 207 204 up_write(&afs_cells_sem); 205 + 206 + if (retref) { 207 + _leave(" = %p", cell); 208 + return cell; 209 + } 210 + 211 + _leave(" = -EEXIST"); 208 212 return ERR_PTR(-EEXIST); 209 213 } 210 214 ··· 245 229 *cp++ = 0; 246 230 247 231 /* allocate a cell record for the root cell */ 248 - new_root = afs_cell_create(rootcell, cp); 232 + new_root = afs_cell_create(rootcell, strlen(rootcell), cp, false); 249 233 if (IS_ERR(new_root)) { 250 234 _leave(" = %ld", PTR_ERR(new_root)); 251 235 return PTR_ERR(new_root); ··· 265 249 /* 266 250 * lookup a cell record 267 251 */ 268 - struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz) 252 + struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz, 253 + bool dns_cell) 269 254 { 270 255 struct afs_cell *cell; 271 256 272 - _enter("\"%*.*s\",", namesz, namesz, name ? name : ""); 257 + _enter("\"%*.*s\",", namesz, namesz, name ?: ""); 273 258 274 259 down_read(&afs_cells_sem); 275 260 read_lock(&afs_cells_lock); ··· 284 267 } 285 268 } 286 269 cell = ERR_PTR(-ENOENT); 270 + if (dns_cell) 271 + goto create_cell; 287 272 found: 288 273 ; 289 274 } else { ··· 306 287 307 288 read_unlock(&afs_cells_lock); 308 289 up_read(&afs_cells_sem); 290 + _leave(" = %p", cell); 291 + return cell; 292 + 293 + create_cell: 294 + read_unlock(&afs_cells_lock); 295 + up_read(&afs_cells_sem); 296 + 297 + cell = afs_cell_create(name, namesz, NULL, true); 298 + 309 299 _leave(" = %p", cell); 310 300 return cell; 311 301 }
+45 -2
fs/afs/dir.c
··· 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 514 * look up an entry in a directory 481 515 */ 482 516 static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, ··· 554 520 555 521 ret = afs_do_lookup(dir, dentry, &fid, key); 556 522 if (ret < 0) { 523 + inode = afs_try_auto_mntpt(ret, dentry, dir, key, &fid); 524 + if (!IS_ERR(inode)) { 525 + key_put(key); 526 + goto success; 527 + } 528 + 529 + ret = PTR_ERR(inode); 557 530 key_put(key); 558 531 if (ret == -ENOENT) { 559 532 d_add(dentry, NULL); ··· 580 539 return ERR_CAST(inode); 581 540 } 582 541 542 + success: 583 543 dentry->d_op = &afs_fs_dentry_operations; 584 544 585 545 d_add(dentry, inode); ··· 738 696 goto zap; 739 697 740 698 if (dentry->d_inode && 741 - test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dentry->d_inode)->flags)) 742 - goto zap; 699 + (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dentry->d_inode)->flags) || 700 + test_bit(AFS_VNODE_PSEUDODIR, &AFS_FS_I(dentry->d_inode)->flags))) 701 + goto zap; 743 702 744 703 _leave(" = 0 [keep]"); 745 704 return 0;
+86
fs/afs/inode.c
··· 19 19 #include <linux/fs.h> 20 20 #include <linux/pagemap.h> 21 21 #include <linux/sched.h> 22 + #include <linux/mount.h> 23 + #include <linux/namei.h> 22 24 #include "internal.h" 23 25 24 26 struct afs_iget_data { ··· 104 102 } 105 103 106 104 /* 105 + * iget5() comparator for inode created by autocell operations 106 + * 107 + * These pseudo inodes don't match anything. 108 + */ 109 + static int afs_iget5_autocell_test(struct inode *inode, void *opaque) 110 + { 111 + return 0; 112 + } 113 + 114 + /* 107 115 * iget5() inode initialiser 108 116 */ 109 117 static int afs_iget5_set(struct inode *inode, void *opaque) ··· 127 115 vnode->volume = data->volume; 128 116 129 117 return 0; 118 + } 119 + 120 + /* 121 + * inode retrieval for autocell 122 + */ 123 + struct inode *afs_iget_autocell(struct inode *dir, const char *dev_name, 124 + int namesz, struct key *key) 125 + { 126 + struct afs_iget_data data; 127 + struct afs_super_info *as; 128 + struct afs_vnode *vnode; 129 + struct super_block *sb; 130 + struct inode *inode; 131 + static atomic_t afs_autocell_ino; 132 + 133 + _enter("{%x:%u},%*.*s,", 134 + AFS_FS_I(dir)->fid.vid, AFS_FS_I(dir)->fid.vnode, 135 + namesz, namesz, dev_name ?: ""); 136 + 137 + sb = dir->i_sb; 138 + as = sb->s_fs_info; 139 + data.volume = as->volume; 140 + data.fid.vid = as->volume->vid; 141 + data.fid.unique = 0; 142 + data.fid.vnode = 0; 143 + 144 + inode = iget5_locked(sb, atomic_inc_return(&afs_autocell_ino), 145 + afs_iget5_autocell_test, afs_iget5_set, 146 + &data); 147 + if (!inode) { 148 + _leave(" = -ENOMEM"); 149 + return ERR_PTR(-ENOMEM); 150 + } 151 + 152 + _debug("GOT INODE %p { ino=%lu, vl=%x, vn=%x, u=%x }", 153 + inode, inode->i_ino, data.fid.vid, data.fid.vnode, 154 + data.fid.unique); 155 + 156 + vnode = AFS_FS_I(inode); 157 + 158 + /* there shouldn't be an existing inode */ 159 + BUG_ON(!(inode->i_state & I_NEW)); 160 + 161 + inode->i_size = 0; 162 + inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; 163 + inode->i_op = &afs_autocell_inode_operations; 164 + inode->i_nlink = 2; 165 + inode->i_uid = 0; 166 + inode->i_gid = 0; 167 + inode->i_ctime.tv_sec = get_seconds(); 168 + inode->i_ctime.tv_nsec = 0; 169 + inode->i_atime = inode->i_mtime = inode->i_ctime; 170 + inode->i_blocks = 0; 171 + inode->i_version = 0; 172 + inode->i_generation = 0; 173 + 174 + set_bit(AFS_VNODE_PSEUDODIR, &vnode->flags); 175 + inode->i_flags |= S_NOATIME; 176 + unlock_new_inode(inode); 177 + _leave(" = %p", inode); 178 + return inode; 130 179 } 131 180 132 181 /* ··· 384 311 385 312 generic_fillattr(inode, stat); 386 313 return 0; 314 + } 315 + 316 + /* 317 + * discard an AFS inode 318 + */ 319 + int afs_drop_inode(struct inode *inode) 320 + { 321 + _enter(""); 322 + 323 + if (test_bit(AFS_VNODE_PSEUDODIR, &AFS_FS_I(inode)->flags)) 324 + return generic_delete_inode(inode); 325 + else 326 + return generic_drop_inode(inode); 387 327 } 388 328 389 329 /*
+9 -2
fs/afs/internal.h
··· 42 42 struct afs_mount_params { 43 43 bool rwpath; /* T if the parent should be considered R/W */ 44 44 bool force; /* T to force cell type */ 45 + bool autocell; /* T if set auto mount operation */ 45 46 afs_voltype_t type; /* type of volume requested */ 46 47 int volnamesz; /* size of volume name */ 47 48 const char *volname; /* name of volume to mount */ ··· 359 358 #define AFS_VNODE_READLOCKED 7 /* set if vnode is read-locked on the server */ 360 359 #define AFS_VNODE_WRITELOCKED 8 /* set if vnode is write-locked on the server */ 361 360 #define AFS_VNODE_UNLOCKING 9 /* set if vnode is being unlocked on the server */ 361 + #define AFS_VNODE_AUTOCELL 10 /* set if Vnode is an auto mount point */ 362 + #define AFS_VNODE_PSEUDODIR 11 /* set if Vnode is a pseudo directory */ 362 363 363 364 long acl_order; /* ACL check count (callback break count) */ 364 365 ··· 471 468 472 469 #define afs_get_cell(C) do { atomic_inc(&(C)->usage); } while(0) 473 470 extern int afs_cell_init(char *); 474 - extern struct afs_cell *afs_cell_create(const char *, char *); 475 - extern struct afs_cell *afs_cell_lookup(const char *, unsigned); 471 + extern struct afs_cell *afs_cell_create(const char *, unsigned, char *, bool); 472 + extern struct afs_cell *afs_cell_lookup(const char *, unsigned, bool); 476 473 extern struct afs_cell *afs_grab_cell(struct afs_cell *); 477 474 extern void afs_put_cell(struct afs_cell *); 478 475 extern void afs_cell_purge(void); ··· 561 558 /* 562 559 * inode.c 563 560 */ 561 + extern struct inode *afs_iget_autocell(struct inode *, const char *, int, 562 + struct key *); 564 563 extern struct inode *afs_iget(struct super_block *, struct key *, 565 564 struct afs_fid *, struct afs_file_status *, 566 565 struct afs_callback *); ··· 571 566 extern int afs_getattr(struct vfsmount *, struct dentry *, struct kstat *); 572 567 extern int afs_setattr(struct dentry *, struct iattr *); 573 568 extern void afs_evict_inode(struct inode *); 569 + extern int afs_drop_inode(struct inode *); 574 570 575 571 /* 576 572 * main.c ··· 587 581 * mntpt.c 588 582 */ 589 583 extern const struct inode_operations afs_mntpt_inode_operations; 584 + extern const struct inode_operations afs_autocell_inode_operations; 590 585 extern const struct file_operations afs_mntpt_file_operations; 591 586 592 587 extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *);
+55 -23
fs/afs/mntpt.c
··· 38 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 46 static LIST_HEAD(afs_vfsmounts); 42 47 static DECLARE_DELAYED_WORK(afs_mntpt_expiry_timer, afs_mntpt_expiry_timed_out); 43 48 ··· 141 136 { 142 137 struct afs_super_info *super; 143 138 struct vfsmount *mnt; 139 + struct afs_vnode *vnode; 144 140 struct page *page; 145 - size_t size; 146 - char *buf, *devname, *options; 141 + char *devname, *options; 142 + bool rwpath = false; 147 143 int ret; 148 144 149 145 _enter("{%s}", mntpt->d_name.name); 150 146 151 147 BUG_ON(!mntpt->d_inode); 152 - 153 - ret = -EINVAL; 154 - size = mntpt->d_inode->i_size; 155 - if (size > PAGE_SIZE - 1) 156 - goto error_no_devname; 157 148 158 149 ret = -ENOMEM; 159 150 devname = (char *) get_zeroed_page(GFP_KERNEL); ··· 160 159 if (!options) 161 160 goto error_no_options; 162 161 163 - /* read the contents of the AFS special symlink */ 164 - page = read_mapping_page(mntpt->d_inode->i_mapping, 0, NULL); 165 - if (IS_ERR(page)) { 166 - ret = PTR_ERR(page); 167 - goto error_no_page; 162 + vnode = AFS_FS_I(mntpt->d_inode); 163 + if (test_bit(AFS_VNODE_PSEUDODIR, &vnode->flags)) { 164 + /* if the directory is a pseudo directory, use the d_name */ 165 + static const char afs_root_cell[] = ":root.cell."; 166 + unsigned size = mntpt->d_name.len; 167 + 168 + ret = -ENOENT; 169 + if (size < 2 || size > AFS_MAXCELLNAME) 170 + goto error_no_page; 171 + 172 + if (mntpt->d_name.name[0] == '.') { 173 + devname[0] = '#'; 174 + memcpy(devname + 1, mntpt->d_name.name, size - 1); 175 + memcpy(devname + size, afs_root_cell, 176 + sizeof(afs_root_cell)); 177 + rwpath = true; 178 + } else { 179 + devname[0] = '%'; 180 + memcpy(devname + 1, mntpt->d_name.name, size); 181 + memcpy(devname + size + 1, afs_root_cell, 182 + sizeof(afs_root_cell)); 183 + } 184 + } else { 185 + /* read the contents of the AFS special symlink */ 186 + loff_t size = i_size_read(mntpt->d_inode); 187 + char *buf; 188 + 189 + ret = -EINVAL; 190 + if (size > PAGE_SIZE - 1) 191 + goto error_no_page; 192 + 193 + page = read_mapping_page(mntpt->d_inode->i_mapping, 0, NULL); 194 + if (IS_ERR(page)) { 195 + ret = PTR_ERR(page); 196 + goto error_no_page; 197 + } 198 + 199 + ret = -EIO; 200 + if (PageError(page)) 201 + goto error; 202 + 203 + buf = kmap_atomic(page, KM_USER0); 204 + memcpy(devname, buf, size); 205 + kunmap_atomic(buf, KM_USER0); 206 + page_cache_release(page); 207 + page = NULL; 168 208 } 169 - 170 - ret = -EIO; 171 - if (PageError(page)) 172 - goto error; 173 - 174 - buf = kmap_atomic(page, KM_USER0); 175 - memcpy(devname, buf, size); 176 - kunmap_atomic(buf, KM_USER0); 177 - page_cache_release(page); 178 - page = NULL; 179 209 180 210 /* work out what options we want */ 181 211 super = AFS_FS_S(mntpt->d_sb); 182 212 memcpy(options, "cell=", 5); 183 213 strcpy(options + 5, super->volume->cell->name); 184 - if (super->volume->type == AFSVL_RWVOL) 214 + if (super->volume->type == AFSVL_RWVOL || rwpath) 185 215 strcat(options, ",rwpath"); 186 216 187 217 /* try and do the mount */
+1 -1
fs/afs/proc.c
··· 294 294 if (strcmp(kbuf, "add") == 0) { 295 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 298 if (IS_ERR(cell)) { 299 299 ret = PTR_ERR(cell); 300 300 goto done;
+16 -4
fs/afs/super.c
··· 16 16 17 17 #include <linux/kernel.h> 18 18 #include <linux/module.h> 19 + #include <linux/mount.h> 19 20 #include <linux/init.h> 20 21 #include <linux/slab.h> 21 22 #include <linux/smp_lock.h> ··· 49 48 static const struct super_operations afs_super_ops = { 50 49 .statfs = afs_statfs, 51 50 .alloc_inode = afs_alloc_inode, 51 + .drop_inode = afs_drop_inode, 52 52 .destroy_inode = afs_destroy_inode, 53 53 .evict_inode = afs_evict_inode, 54 54 .put_super = afs_put_super, ··· 64 62 afs_opt_cell, 65 63 afs_opt_rwpath, 66 64 afs_opt_vol, 65 + afs_opt_autocell, 67 66 }; 68 67 69 68 static const match_table_t afs_options_list = { 70 69 { afs_opt_cell, "cell=%s" }, 71 70 { afs_opt_rwpath, "rwpath" }, 72 71 { afs_opt_vol, "vol=%s" }, 72 + { afs_opt_autocell, "autocell" }, 73 73 { afs_no_opt, NULL }, 74 74 }; 75 75 ··· 155 151 switch (token) { 156 152 case afs_opt_cell: 157 153 cell = afs_cell_lookup(args[0].from, 158 - args[0].to - args[0].from); 154 + args[0].to - args[0].from, 155 + false); 159 156 if (IS_ERR(cell)) 160 157 return PTR_ERR(cell); 161 158 afs_put_cell(params->cell); ··· 169 164 170 165 case afs_opt_vol: 171 166 *devname = args[0].from; 167 + break; 168 + 169 + case afs_opt_autocell: 170 + params->autocell = 1; 172 171 break; 173 172 174 173 default: ··· 261 252 262 253 /* lookup the cell record */ 263 254 if (cellname || !params->cell) { 264 - cell = afs_cell_lookup(cellname, cellnamesz); 255 + cell = afs_cell_lookup(cellname, cellnamesz, true); 265 256 if (IS_ERR(cell)) { 266 - printk(KERN_ERR "kAFS: unable to lookup cell '%s'\n", 267 - cellname ?: ""); 257 + printk(KERN_ERR "kAFS: unable to lookup cell '%*.*s'\n", 258 + cellnamesz, cellnamesz, cellname ?: ""); 268 259 return PTR_ERR(cell); 269 260 } 270 261 afs_put_cell(params->cell); ··· 329 320 inode = afs_iget(sb, params->key, &fid, NULL, NULL); 330 321 if (IS_ERR(inode)) 331 322 goto error_inode; 323 + 324 + if (params->autocell) 325 + set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags); 332 326 333 327 ret = -ENOMEM; 334 328 root = d_alloc_root(inode);
+10
fs/cifs/README
··· 301 301 gid Set the default gid for inodes (similar to above). 302 302 file_mode If CIFS Unix extensions are not supported by the server 303 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 314 dir_mode If CIFS Unix extensions are not supported by the server 305 315 this overrides the default mode for directory inodes. 306 316 port attempt to contact the server on this tcp port, before
+17
fs/nfs/Kconfig
··· 100 100 help 101 101 Say Y here if you want NFS data to be cached locally on disc through 102 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
+24
fs/nfs/dns_resolve.c
··· 6 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 32 #include <linux/hash.h> 10 33 #include <linux/string.h> 11 34 #include <linux/kmod.h> ··· 369 346 nfs_cache_unregister(&nfs_dns_resolve); 370 347 } 371 348 349 + #endif
+12
fs/nfs/dns_resolve.h
··· 6 6 7 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 19 extern int nfs_dns_resolver_init(void); 10 20 extern void nfs_dns_resolver_destroy(void); 21 + #endif 22 + 11 23 extern ssize_t nfs_dns_resolve_name(char *name, size_t namelen, 12 24 struct sockaddr *sa, size_t salen); 13 25
+87 -5
net/dns_resolver/dns_key.c
··· 29 29 #include <linux/kernel.h> 30 30 #include <linux/keyctl.h> 31 31 #include <linux/err.h> 32 + #include <linux/seq_file.h> 32 33 #include <keys/dns_resolver-type.h> 33 34 #include <keys/user-type.h> 34 35 #include "internal.h" ··· 43 42 MODULE_PARM_DESC(debug, "DNS Resolver debugging mask"); 44 43 45 44 const struct cred *dns_resolver_cache; 45 + 46 + #define DNS_ERRORNO_OPTION "dnserror" 46 47 47 48 /* 48 49 * Instantiate a user defined key for dns_resolver. ··· 62 59 dns_resolver_instantiate(struct key *key, const void *_data, size_t datalen) 63 60 { 64 61 struct user_key_payload *upayload; 62 + unsigned long derrno; 65 63 int ret; 66 64 size_t result_len = 0; 67 - const char *data = _data, *opt; 65 + const char *data = _data, *end, *opt; 68 66 69 67 kenter("%%%d,%s,'%s',%zu", 70 68 key->serial, key->description, data, datalen); ··· 75 71 datalen--; 76 72 77 73 /* deal with any options embedded in the data */ 74 + end = data + datalen; 78 75 opt = memchr(data, '#', datalen); 79 76 if (!opt) { 80 - kdebug("no options currently supported"); 81 - return -EINVAL; 77 + /* no options: the entire data is the result */ 78 + kdebug("no options"); 79 + result_len = datalen; 80 + } else { 81 + const char *next_opt; 82 + 83 + result_len = opt - data; 84 + opt++; 85 + kdebug("options: '%s'", opt); 86 + do { 87 + const char *eq; 88 + int opt_len, opt_nlen, opt_vlen, tmp; 89 + 90 + next_opt = memchr(opt, '#', end - opt) ?: end; 91 + opt_len = next_opt - opt; 92 + if (!opt_len) { 93 + printk(KERN_WARNING 94 + "Empty option to dns_resolver key %d\n", 95 + key->serial); 96 + return -EINVAL; 97 + } 98 + 99 + eq = memchr(opt, '=', opt_len) ?: end; 100 + opt_nlen = eq - opt; 101 + eq++; 102 + opt_vlen = next_opt - eq; /* will be -1 if no value */ 103 + 104 + tmp = opt_vlen >= 0 ? opt_vlen : 0; 105 + kdebug("option '%*.*s' val '%*.*s'", 106 + opt_nlen, opt_nlen, opt, tmp, tmp, eq); 107 + 108 + /* see if it's an error number representing a DNS error 109 + * that's to be recorded as the result in this key */ 110 + if (opt_nlen == sizeof(DNS_ERRORNO_OPTION) - 1 && 111 + memcmp(opt, DNS_ERRORNO_OPTION, opt_nlen) == 0) { 112 + kdebug("dns error number option"); 113 + if (opt_vlen <= 0) 114 + goto bad_option_value; 115 + 116 + ret = strict_strtoul(eq, 10, &derrno); 117 + if (ret < 0) 118 + goto bad_option_value; 119 + 120 + if (derrno < 1 || derrno > 511) 121 + goto bad_option_value; 122 + 123 + kdebug("dns error no. = %lu", derrno); 124 + key->type_data.x[0] = -derrno; 125 + continue; 126 + } 127 + 128 + bad_option_value: 129 + printk(KERN_WARNING 130 + "Option '%*.*s' to dns_resolver key %d:" 131 + " bad/missing value\n", 132 + opt_nlen, opt_nlen, opt, key->serial); 133 + return -EINVAL; 134 + } while (opt = next_opt + 1, opt < end); 82 135 } 83 136 84 - result_len = datalen; 137 + /* don't cache the result if we're caching an error saying there's no 138 + * result */ 139 + if (key->type_data.x[0]) { 140 + kleave(" = 0 [h_error %ld]", key->type_data.x[0]); 141 + return 0; 142 + } 143 + 144 + kdebug("store result"); 85 145 ret = key_payload_reserve(key, result_len); 86 146 if (ret < 0) 87 147 return -EINVAL; ··· 203 135 return ret; 204 136 } 205 137 138 + /* 139 + * Describe a DNS key 140 + */ 141 + static void dns_resolver_describe(const struct key *key, struct seq_file *m) 142 + { 143 + int err = key->type_data.x[0]; 144 + 145 + seq_puts(m, key->description); 146 + if (err) 147 + seq_printf(m, ": %d", err); 148 + else 149 + seq_printf(m, ": %u", key->datalen); 150 + } 151 + 206 152 struct key_type key_type_dns_resolver = { 207 153 .name = "dns_resolver", 208 154 .instantiate = dns_resolver_instantiate, 209 155 .match = dns_resolver_match, 210 156 .revoke = user_revoke, 211 157 .destroy = user_destroy, 212 - .describe = user_describe, 158 + .describe = dns_resolver_describe, 213 159 .read = user_read, 214 160 }; 215 161
+5
net/dns_resolver/dns_query.c
··· 136 136 if (ret < 0) 137 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 144 upayload = rcu_dereference_protected(rkey->payload.data, 140 145 lockdep_is_held(&rkey->sem)); 141 146 len = upayload->datalen;