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

[PATCH] knfsd: add some new fsid types

Add support for using a filesystem UUID to identify and export point in the
filehandle.

For NFSv2, this UUID is xor-ed down to 4 or 8 bytes so that it doesn't take up
too much room. For NFSv3+, we use the full 16 bytes, and possibly also a
64bit inode number for exports beneath the root of a filesystem.

When generating an fsid to return in 'stat' information, use the UUID (hashed
down to size) if it is available and a small 'fsid' was not specifically
provided.

Signed-off-by: Neil Brown <neilb@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

NeilBrown and committed by
Linus Torvalds
af6a4e28 982aedfd

+242 -130
+69 -37
fs/nfsd/export.c
··· 190 190 struct cache_head *h) 191 191 { 192 192 struct svc_expkey *ek ; 193 + int i; 193 194 194 195 if (h ==NULL) { 195 196 seq_puts(m, "#domain fsidtype fsid [path]\n"); 196 197 return 0; 197 198 } 198 199 ek = container_of(h, struct svc_expkey, h); 199 - seq_printf(m, "%s %d 0x%08x", ek->ek_client->name, 200 - ek->ek_fsidtype, ek->ek_fsid[0]); 201 - if (ek->ek_fsidtype != 1) 202 - seq_printf(m, "%08x", ek->ek_fsid[1]); 203 - if (ek->ek_fsidtype == 2) 204 - seq_printf(m, "%08x", ek->ek_fsid[2]); 200 + seq_printf(m, "%s %d 0x", ek->ek_client->name, 201 + ek->ek_fsidtype); 202 + for (i=0; i < key_len(ek->ek_fsidtype)/4; i++) 203 + seq_printf(m, "%08x", ek->ek_fsid[i]); 205 204 if (test_bit(CACHE_VALID, &h->flags) && 206 205 !test_bit(CACHE_NEGATIVE, &h->flags)) { 207 206 seq_printf(m, " "); ··· 231 232 kref_get(&item->ek_client->ref); 232 233 new->ek_client = item->ek_client; 233 234 new->ek_fsidtype = item->ek_fsidtype; 234 - new->ek_fsid[0] = item->ek_fsid[0]; 235 - new->ek_fsid[1] = item->ek_fsid[1]; 236 - new->ek_fsid[2] = item->ek_fsid[2]; 235 + 236 + memcpy(new->ek_fsid, item->ek_fsid, sizeof(new->ek_fsid)); 237 237 } 238 238 239 239 static inline void expkey_update(struct cache_head *cnew, ··· 361 363 struct svc_export *old); 362 364 static struct svc_export *svc_export_lookup(struct svc_export *); 363 365 364 - static int check_export(struct inode *inode, int flags) 366 + static int check_export(struct inode *inode, int flags, unsigned char *uuid) 365 367 { 366 368 367 369 /* We currently export only dirs and regular files. ··· 374 376 /* There are two requirements on a filesystem to be exportable. 375 377 * 1: We must be able to identify the filesystem from a number. 376 378 * either a device number (so FS_REQUIRES_DEV needed) 377 - * or an FSID number (so NFSEXP_FSID needed). 379 + * or an FSID number (so NFSEXP_FSID or ->uuid is needed). 378 380 * 2: We must be able to find an inode from a filehandle. 379 381 * This means that s_export_op must be set. 380 382 */ 381 383 if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) && 382 - !(flags & NFSEXP_FSID)) { 384 + !(flags & NFSEXP_FSID) && 385 + uuid == NULL) { 383 386 dprintk("exp_export: export of non-dev fs without fsid\n"); 384 387 return -EINVAL; 385 388 } ··· 404 405 { 405 406 int len; 406 407 int migrated, i, err; 407 - 408 - len = qword_get(mesg, buf, PAGE_SIZE); 409 - if (len != 5 || memcmp(buf, "fsloc", 5)) 410 - return 0; 411 408 412 409 /* listsize */ 413 410 err = get_int(mesg, &fsloc->locations_count); ··· 515 520 exp.ex_fslocs.locations_count = 0; 516 521 exp.ex_fslocs.migrated = 0; 517 522 523 + exp.ex_uuid = NULL; 524 + 518 525 /* flags */ 519 526 err = get_int(&mesg, &an_int); 520 527 if (err == -ENOENT) ··· 540 543 if (err) goto out; 541 544 exp.ex_fsid = an_int; 542 545 543 - err = check_export(nd.dentry->d_inode, exp.ex_flags); 544 - if (err) goto out; 546 + while ((len = qword_get(&mesg, buf, PAGE_SIZE)) > 0) { 547 + if (strcmp(buf, "fsloc") == 0) 548 + err = fsloc_parse(&mesg, buf, &exp.ex_fslocs); 549 + else if (strcmp(buf, "uuid") == 0) { 550 + /* expect a 16 byte uuid encoded as \xXXXX... */ 551 + len = qword_get(&mesg, buf, PAGE_SIZE); 552 + if (len != 16) 553 + err = -EINVAL; 554 + else { 555 + exp.ex_uuid = 556 + kmemdup(buf, 16, GFP_KERNEL); 557 + if (exp.ex_uuid == NULL) 558 + err = -ENOMEM; 559 + } 560 + } else 561 + /* quietly ignore unknown words and anything 562 + * following. Newer user-space can try to set 563 + * new values, then see what the result was. 564 + */ 565 + break; 566 + if (err) 567 + goto out; 568 + } 545 569 546 - err = fsloc_parse(&mesg, buf, &exp.ex_fslocs); 547 - if (err) 548 - goto out; 570 + err = check_export(nd.dentry->d_inode, exp.ex_flags, 571 + exp.ex_uuid); 572 + if (err) goto out; 549 573 } 550 574 551 575 expp = svc_export_lookup(&exp); ··· 580 562 else 581 563 exp_put(expp); 582 564 out: 565 + nfsd4_fslocs_free(&exp.ex_fslocs); 566 + kfree(exp.ex_uuid); 583 567 kfree(exp.ex_path); 584 568 if (nd.dentry) 585 569 path_release(&nd); ··· 611 591 seq_escape(m, exp->ex_client->name, " \t\n\\"); 612 592 seq_putc(m, '('); 613 593 if (test_bit(CACHE_VALID, &h->flags) && 614 - !test_bit(CACHE_NEGATIVE, &h->flags)) 594 + !test_bit(CACHE_NEGATIVE, &h->flags)) { 615 595 exp_flags(m, exp->ex_flags, exp->ex_fsid, 616 596 exp->ex_anon_uid, exp->ex_anon_gid, &exp->ex_fslocs); 597 + if (exp->ex_uuid) { 598 + int i; 599 + seq_puts(m, ",uuid="); 600 + for (i=0; i<16; i++) { 601 + if ((i&3) == 0 && i) 602 + seq_putc(m, ':'); 603 + seq_printf(m, "%02x", exp->ex_uuid[i]); 604 + } 605 + } 606 + } 617 607 seq_puts(m, ")\n"); 618 608 return 0; 619 609 } ··· 660 630 new->ex_anon_uid = item->ex_anon_uid; 661 631 new->ex_anon_gid = item->ex_anon_gid; 662 632 new->ex_fsid = item->ex_fsid; 633 + new->ex_uuid = item->ex_uuid; 634 + item->ex_uuid = NULL; 663 635 new->ex_path = item->ex_path; 664 636 item->ex_path = NULL; 665 637 new->ex_fslocs.locations = item->ex_fslocs.locations; ··· 784 752 u32 fsidv[3]; 785 753 786 754 if (old_valid_dev(dev)) { 787 - mk_fsid_v0(fsidv, dev, ino); 788 - return exp_find_key(clp, 0, fsidv, NULL); 755 + mk_fsid(FSID_DEV, fsidv, dev, ino, 0, NULL); 756 + return exp_find_key(clp, FSID_DEV, fsidv, NULL); 789 757 } 790 - mk_fsid_v3(fsidv, dev, ino); 791 - return exp_find_key(clp, 3, fsidv, NULL); 758 + mk_fsid(FSID_ENCODE_DEV, fsidv, dev, ino, 0, NULL); 759 + return exp_find_key(clp, FSID_ENCODE_DEV, fsidv, NULL); 792 760 } 793 761 794 762 /* ··· 799 767 { 800 768 u32 fsidv[2]; 801 769 802 - mk_fsid_v1(fsidv, fsid); 770 + mk_fsid(FSID_NUM, fsidv, 0, 0, fsid, NULL); 803 771 804 - return exp_find_key(clp, 1, fsidv, NULL); 772 + return exp_find_key(clp, FSID_NUM, fsidv, NULL); 805 773 } 806 774 807 775 svc_export * ··· 915 883 if ((exp->ex_flags & NFSEXP_FSID) == 0) 916 884 return 0; 917 885 918 - mk_fsid_v1(fsid, exp->ex_fsid); 919 - return exp_set_key(clp, 1, fsid, exp); 886 + mk_fsid(FSID_NUM, fsid, 0, 0, exp->ex_fsid, NULL); 887 + return exp_set_key(clp, FSID_NUM, fsid, exp); 920 888 } 921 889 922 890 static int exp_hash(struct auth_domain *clp, struct svc_export *exp) ··· 926 894 dev_t dev = inode->i_sb->s_dev; 927 895 928 896 if (old_valid_dev(dev)) { 929 - mk_fsid_v0(fsid, dev, inode->i_ino); 930 - return exp_set_key(clp, 0, fsid, exp); 897 + mk_fsid(FSID_DEV, fsid, dev, inode->i_ino, 0, NULL); 898 + return exp_set_key(clp, FSID_DEV, fsid, exp); 931 899 } 932 - mk_fsid_v3(fsid, dev, inode->i_ino); 933 - return exp_set_key(clp, 3, fsid, exp); 900 + mk_fsid(FSID_ENCODE_DEV, fsid, dev, inode->i_ino, 0, NULL); 901 + return exp_set_key(clp, FSID_ENCODE_DEV, fsid, exp); 934 902 } 935 903 936 904 static void exp_unhash(struct svc_export *exp) ··· 1009 977 goto finish; 1010 978 } 1011 979 1012 - err = check_export(nd.dentry->d_inode, nxp->ex_flags); 980 + err = check_export(nd.dentry->d_inode, nxp->ex_flags, NULL); 1013 981 if (err) goto finish; 1014 982 1015 983 err = -ENOMEM; ··· 1202 1170 __be32 rv; 1203 1171 u32 fsidv[2]; 1204 1172 1205 - mk_fsid_v1(fsidv, 0); 1173 + mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL); 1206 1174 1207 - exp = exp_find(clp, 1, fsidv, creq); 1175 + exp = exp_find(clp, FSID_NUM, fsidv, creq); 1208 1176 if (IS_ERR(exp)) 1209 1177 return nfserrno(PTR_ERR(exp)); 1210 1178 if (exp == NULL)
+23 -8
fs/nfsd/nfs3xdr.c
··· 149 149 return p; 150 150 } 151 151 152 + static __be32 *encode_fsid(__be32 *p, struct svc_fh *fhp) 153 + { 154 + u64 f; 155 + switch(fsid_source(fhp)) { 156 + default: 157 + case FSIDSOURCE_DEV: 158 + p = xdr_encode_hyper(p, (u64)huge_encode_dev 159 + (fhp->fh_dentry->d_inode->i_sb->s_dev)); 160 + break; 161 + case FSIDSOURCE_FSID: 162 + p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid); 163 + break; 164 + case FSIDSOURCE_UUID: 165 + f = ((u64*)fhp->fh_export->ex_uuid)[0]; 166 + f ^= ((u64*)fhp->fh_export->ex_uuid)[1]; 167 + p = xdr_encode_hyper(p, f); 168 + break; 169 + } 170 + return p; 171 + } 172 + 152 173 static __be32 * 153 174 encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, 154 175 struct kstat *stat) ··· 190 169 p = xdr_encode_hyper(p, ((u64)stat->blocks) << 9); 191 170 *p++ = htonl((u32) MAJOR(stat->rdev)); 192 171 *p++ = htonl((u32) MINOR(stat->rdev)); 193 - if (is_fsid(fhp, rqstp->rq_reffh)) 194 - p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid); 195 - else 196 - p = xdr_encode_hyper(p, (u64) huge_encode_dev(stat->dev)); 172 + p = encode_fsid(p, fhp); 197 173 p = xdr_encode_hyper(p, (u64) stat->ino); 198 174 p = encode_time3(p, &stat->atime); 199 175 lease_get_mtime(dentry->d_inode, &time); ··· 221 203 p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9); 222 204 *p++ = fhp->fh_post_rdev[0]; 223 205 *p++ = fhp->fh_post_rdev[1]; 224 - if (is_fsid(fhp, rqstp->rq_reffh)) 225 - p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid); 226 - else 227 - p = xdr_encode_hyper(p, (u64)huge_encode_dev(inode->i_sb->s_dev)); 206 + p = encode_fsid(p, fhp); 228 207 p = xdr_encode_hyper(p, (u64) inode->i_ino); 229 208 p = encode_time3(p, &fhp->fh_post_atime); 230 209 p = encode_time3(p, &fhp->fh_post_mtime);
+8 -2
fs/nfsd/nfs4xdr.c
··· 1563 1563 if (exp->ex_fslocs.migrated) { 1564 1564 WRITE64(NFS4_REFERRAL_FSID_MAJOR); 1565 1565 WRITE64(NFS4_REFERRAL_FSID_MINOR); 1566 - } else if (is_fsid(fhp, rqstp->rq_reffh)) { 1566 + } else switch(fsid_source(fhp)) { 1567 + case FSIDSOURCE_FSID: 1567 1568 WRITE64((u64)exp->ex_fsid); 1568 1569 WRITE64((u64)0); 1569 - } else { 1570 + break; 1571 + case FSIDSOURCE_DEV: 1570 1572 WRITE32(0); 1571 1573 WRITE32(MAJOR(stat.dev)); 1572 1574 WRITE32(0); 1573 1575 WRITE32(MINOR(stat.dev)); 1576 + break; 1577 + case FSIDSOURCE_UUID: 1578 + WRITEMEM(exp->ex_uuid, 16); 1579 + break; 1574 1580 } 1575 1581 } 1576 1582 if (bmval0 & FATTR4_WORD0_UNIQUE_HANDLES) {
+46 -42
fs/nfsd/nfsfh.c
··· 119 119 120 120 dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp)); 121 121 122 - /* keep this filehandle for possible reference when encoding attributes */ 123 - rqstp->rq_reffh = fh; 124 - 125 122 if (!fhp->fh_dentry) { 126 123 __u32 *datap=NULL; 127 124 __u32 tfh[3]; /* filehandle fragment for oldstyle filehandles */ ··· 143 146 } 144 147 len = key_len(fh->fh_fsid_type) / 4; 145 148 if (len == 0) goto out; 146 - if (fh->fh_fsid_type == 2) { 149 + if (fh->fh_fsid_type == FSID_MAJOR_MINOR) { 147 150 /* deprecated, convert to type 3 */ 148 - len = 3; 149 - fh->fh_fsid_type = 3; 151 + len = key_len(FSID_ENCODE_DEV)/4; 152 + fh->fh_fsid_type = FSID_ENCODE_DEV; 150 153 fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl(fh->fh_fsid[0]), ntohl(fh->fh_fsid[1]))); 151 154 fh->fh_fsid[1] = fh->fh_fsid[2]; 152 155 } ··· 161 164 /* assume old filehandle format */ 162 165 xdev = old_decode_dev(fh->ofh_xdev); 163 166 xino = u32_to_ino_t(fh->ofh_xino); 164 - mk_fsid_v0(tfh, xdev, xino); 165 - exp = exp_find(rqstp->rq_client, 0, tfh, &rqstp->rq_chandle); 167 + mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL); 168 + exp = exp_find(rqstp->rq_client, FSID_DEV, tfh, 169 + &rqstp->rq_chandle); 166 170 } 167 171 168 172 if (IS_ERR(exp) && (PTR_ERR(exp) == -EAGAIN ··· 332 334 struct dentry *parent = dentry->d_parent; 333 335 __u32 *datap; 334 336 dev_t ex_dev = exp->ex_dentry->d_inode->i_sb->s_dev; 337 + int root_export = (exp->ex_dentry == exp->ex_dentry->d_sb->s_root); 335 338 336 339 dprintk("nfsd: fh_compose(exp %02x:%02x/%ld %s/%s, ino=%ld)\n", 337 340 MAJOR(ex_dev), MINOR(ex_dev), ··· 347 348 if (ref_fh && ref_fh->fh_export == exp) { 348 349 version = ref_fh->fh_handle.fh_version; 349 350 if (version == 0xca) 350 - fsid_type = 0; 351 + fsid_type = FSID_DEV; 351 352 else 352 353 fsid_type = ref_fh->fh_handle.fh_fsid_type; 353 354 /* We know this version/type works for this export 354 355 * so there is no need for further checks. 355 356 */ 357 + } else if (exp->ex_uuid) { 358 + if (fhp->fh_maxsize >= 64) { 359 + if (root_export) 360 + fsid_type = FSID_UUID16; 361 + else 362 + fsid_type = FSID_UUID16_INUM; 363 + } else { 364 + if (root_export) 365 + fsid_type = FSID_UUID8; 366 + else 367 + fsid_type = FSID_UUID4_INUM; 368 + } 356 369 } else if (exp->ex_flags & NFSEXP_FSID) 357 - fsid_type = 1; 370 + fsid_type = FSID_NUM; 358 371 else if (!old_valid_dev(ex_dev)) 359 372 /* for newer device numbers, we must use a newer fsid format */ 360 - fsid_type = 3; 373 + fsid_type = FSID_ENCODE_DEV; 361 374 else 362 - fsid_type = 0; 375 + fsid_type = FSID_DEV; 363 376 364 377 if (ref_fh == fhp) 365 378 fh_put(ref_fh); ··· 407 396 fhp->fh_handle.fh_auth_type = 0; 408 397 datap = fhp->fh_handle.fh_auth+0; 409 398 fhp->fh_handle.fh_fsid_type = fsid_type; 410 - switch (fsid_type) { 411 - case 0: 412 - /* 413 - * fsid_type 0: 414 - * 2byte major, 2byte minor, 4byte inode 415 - */ 416 - mk_fsid_v0(datap, ex_dev, 417 - exp->ex_dentry->d_inode->i_ino); 418 - break; 419 - case 1: 420 - /* fsid_type 1 == 4 bytes filesystem id */ 421 - mk_fsid_v1(datap, exp->ex_fsid); 422 - break; 423 - case 2: 424 - /* 425 - * fsid_type 2: 426 - * 4byte major, 4byte minor, 4byte inode 427 - */ 428 - mk_fsid_v2(datap, ex_dev, 429 - exp->ex_dentry->d_inode->i_ino); 430 - break; 431 - case 3: 432 - /* 433 - * fsid_type 3: 434 - * 4byte devicenumber, 4byte inode 435 - */ 436 - mk_fsid_v3(datap, ex_dev, 437 - exp->ex_dentry->d_inode->i_ino); 438 - break; 439 - } 399 + mk_fsid(fsid_type, datap, ex_dev, 400 + exp->ex_dentry->d_inode->i_ino, 401 + exp->ex_fsid, exp->ex_uuid); 402 + 440 403 len = key_len(fsid_type); 441 404 datap += len/4; 442 405 fhp->fh_handle.fh_size = 4 + len; ··· 514 529 fh->fh_base.fh_pad[4], 515 530 fh->fh_base.fh_pad[5]); 516 531 return buf; 532 + } 533 + 534 + enum fsid_source fsid_source(struct svc_fh *fhp) 535 + { 536 + if (fhp->fh_handle.fh_version != 1) 537 + return FSIDSOURCE_DEV; 538 + switch(fhp->fh_handle.fh_fsid_type) { 539 + case FSID_DEV: 540 + case FSID_ENCODE_DEV: 541 + case FSID_MAJOR_MINOR: 542 + return FSIDSOURCE_DEV; 543 + case FSID_NUM: 544 + return FSIDSOURCE_FSID; 545 + default: 546 + if (fhp->fh_export->ex_flags & NFSEXP_FSID) 547 + return FSIDSOURCE_FSID; 548 + else 549 + return FSIDSOURCE_UUID; 550 + } 517 551 }
+16 -3
fs/nfsd/nfsxdr.c
··· 153 153 struct dentry *dentry = fhp->fh_dentry; 154 154 int type; 155 155 struct timespec time; 156 + u32 f; 156 157 157 158 type = (stat->mode & S_IFMT); 158 159 ··· 174 173 else 175 174 *p++ = htonl(0xffffffff); 176 175 *p++ = htonl((u32) stat->blocks); 177 - if (is_fsid(fhp, rqstp->rq_reffh)) 178 - *p++ = htonl((u32) fhp->fh_export->ex_fsid); 179 - else 176 + switch (fsid_source(fhp)) { 177 + default: 178 + case FSIDSOURCE_DEV: 180 179 *p++ = htonl(new_encode_dev(stat->dev)); 180 + break; 181 + case FSIDSOURCE_FSID: 182 + *p++ = htonl((u32) fhp->fh_export->ex_fsid); 183 + break; 184 + case FSIDSOURCE_UUID: 185 + f = ((u32*)fhp->fh_export->ex_uuid)[0]; 186 + f ^= ((u32*)fhp->fh_export->ex_uuid)[1]; 187 + f ^= ((u32*)fhp->fh_export->ex_uuid)[2]; 188 + f ^= ((u32*)fhp->fh_export->ex_uuid)[3]; 189 + *p++ = htonl(f); 190 + break; 191 + } 181 192 *p++ = htonl((u32) stat->ino); 182 193 *p++ = htonl((u32) stat->atime.tv_sec); 183 194 *p++ = htonl(stat->atime.tv_nsec ? stat->atime.tv_nsec / 1000 : 0);
+4 -3
include/linux/nfsd/export.h
··· 74 74 uid_t ex_anon_uid; 75 75 gid_t ex_anon_gid; 76 76 int ex_fsid; 77 + unsigned char * ex_uuid; /* 16 byte fsid */ 77 78 struct nfsd4_fs_locations ex_fslocs; 78 79 }; 79 80 80 81 /* an "export key" (expkey) maps a filehandlefragement to an 81 - * svc_export for a given client. There can be two per export, one 82 - * for type 0 (dev/ino), one for type 1 (fsid) 82 + * svc_export for a given client. There can be several per export, 83 + * for the different fsid types. 83 84 */ 84 85 struct svc_expkey { 85 86 struct cache_head h; 86 87 87 88 struct auth_domain * ek_client; 88 89 int ek_fsidtype; 89 - u32 ek_fsid[3]; 90 + u32 ek_fsid[6]; 90 91 91 92 struct vfsmount * ek_mnt; 92 93 struct dentry * ek_dentry;
-12
include/linux/nfsd/nfsd.h
··· 254 254 */ 255 255 extern struct timeval nfssvc_boot; 256 256 257 - static inline int is_fsid(struct svc_fh *fh, struct knfsd_fh *reffh) 258 - { 259 - if (fh->fh_export->ex_flags & NFSEXP_FSID) { 260 - struct vfsmount *mnt = fh->fh_export->ex_mnt; 261 - if (!old_valid_dev(mnt->mnt_sb->s_dev) || 262 - (reffh->fh_version == 1 && reffh->fh_fsid_type == 1)) 263 - return 1; 264 - } 265 - return 0; 266 - } 267 - 268 - 269 257 #ifdef CONFIG_NFSD_V4 270 258 271 259 /* before processing a COMPOUND operation, we have to check that there
+76 -23
include/linux/nfsd/nfsfh.h
··· 165 165 166 166 } svc_fh; 167 167 168 - static inline void mk_fsid_v0(u32 *fsidv, dev_t dev, ino_t ino) 169 - { 170 - fsidv[0] = htonl((MAJOR(dev)<<16) | 171 - MINOR(dev)); 172 - fsidv[1] = ino_t_to_u32(ino); 173 - } 168 + enum nfsd_fsid { 169 + FSID_DEV = 0, 170 + FSID_NUM, 171 + FSID_MAJOR_MINOR, 172 + FSID_ENCODE_DEV, 173 + FSID_UUID4_INUM, 174 + FSID_UUID8, 175 + FSID_UUID16, 176 + FSID_UUID16_INUM, 177 + }; 174 178 175 - static inline void mk_fsid_v1(u32 *fsidv, u32 fsid) 176 - { 177 - fsidv[0] = fsid; 178 - } 179 + enum fsid_source { 180 + FSIDSOURCE_DEV, 181 + FSIDSOURCE_FSID, 182 + FSIDSOURCE_UUID, 183 + }; 184 + extern enum fsid_source fsid_source(struct svc_fh *fhp); 179 185 180 - static inline void mk_fsid_v2(u32 *fsidv, dev_t dev, ino_t ino) 181 - { 182 - fsidv[0] = htonl(MAJOR(dev)); 183 - fsidv[1] = htonl(MINOR(dev)); 184 - fsidv[2] = ino_t_to_u32(ino); 185 - } 186 186 187 - static inline void mk_fsid_v3(u32 *fsidv, dev_t dev, ino_t ino) 187 + /* This might look a little large to "inline" but in all calls except 188 + * one, 'vers' is constant so moste of the function disappears. 189 + */ 190 + static inline void mk_fsid(int vers, u32 *fsidv, dev_t dev, ino_t ino, 191 + u32 fsid, unsigned char *uuid) 188 192 { 189 - fsidv[0] = new_encode_dev(dev); 190 - fsidv[1] = ino_t_to_u32(ino); 193 + u32 *up; 194 + switch(vers) { 195 + case FSID_DEV: 196 + fsidv[0] = htonl((MAJOR(dev)<<16) | 197 + MINOR(dev)); 198 + fsidv[1] = ino_t_to_u32(ino); 199 + break; 200 + case FSID_NUM: 201 + fsidv[0] = fsid; 202 + break; 203 + case FSID_MAJOR_MINOR: 204 + fsidv[0] = htonl(MAJOR(dev)); 205 + fsidv[1] = htonl(MINOR(dev)); 206 + fsidv[2] = ino_t_to_u32(ino); 207 + break; 208 + 209 + case FSID_ENCODE_DEV: 210 + fsidv[0] = new_encode_dev(dev); 211 + fsidv[1] = ino_t_to_u32(ino); 212 + break; 213 + 214 + case FSID_UUID4_INUM: 215 + /* 4 byte fsid and inode number */ 216 + up = (u32*)uuid; 217 + fsidv[0] = ino_t_to_u32(ino); 218 + fsidv[1] = up[0] ^ up[1] ^ up[2] ^ up[3]; 219 + break; 220 + 221 + case FSID_UUID8: 222 + /* 8 byte fsid */ 223 + up = (u32*)uuid; 224 + fsidv[0] = up[0] ^ up[2]; 225 + fsidv[1] = up[1] ^ up[3]; 226 + break; 227 + 228 + case FSID_UUID16: 229 + /* 16 byte fsid - NFSv3+ only */ 230 + memcpy(fsidv, uuid, 16); 231 + break; 232 + 233 + case FSID_UUID16_INUM: 234 + /* 8 byte inode and 16 byte fsid */ 235 + *(u64*)fsidv = (u64)ino; 236 + memcpy(fsidv+2, uuid, 16); 237 + break; 238 + default: BUG(); 239 + } 191 240 } 192 241 193 242 static inline int key_len(int type) 194 243 { 195 244 switch(type) { 196 - case 0: return 8; 197 - case 1: return 4; 198 - case 2: return 12; 199 - case 3: return 8; 245 + case FSID_DEV: return 8; 246 + case FSID_NUM: return 4; 247 + case FSID_MAJOR_MINOR: return 12; 248 + case FSID_ENCODE_DEV: return 8; 249 + case FSID_UUID4_INUM: return 8; 250 + case FSID_UUID8: return 8; 251 + case FSID_UUID16: return 16; 252 + case FSID_UUID16_INUM: return 24; 200 253 default: return 0; 201 254 } 202 255 }