aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruen@suse.de>2005-06-22 13:16:27 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2005-06-22 16:07:24 -0400
commit055ffbea0596942579b0dae71d5dab78de8135f6 (patch)
tree4799088989e9923c45089cab905f40247af52a45
parentb7fa0554cf1ba6d6895cd0a5b02989a26e0bc704 (diff)
[PATCH] NFS: Fix handling of the umask when an NFSv3 default acl is present.
NFSv3 has no concept of a umask on the server side: The client applies the umask locally, and sends the effective permissions to the server. This behavior is wrong when files are created in a directory that has a default ACL. In this case, the umask is supposed to be ignored, and only the default ACL determines the file's effective permissions. Usually its the server's task to conditionally apply the umask. But since the server knows nothing about the umask, we have to do it on the client side. This patch tries to fetch the parent directory's default ACL before creating a new file, computes the appropriate create mode to send to the server, and finally sets the new file's access and default acl appropriately. Many thanks to Buck Huppmann <buchk@pobox.com> for sending the initial version of this patch, as well as for arguing why we need this change. Signed-off-by: Andreas Gruenbacher <agruen@suse.de> Acked-by: Olaf Kirch <okir@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--fs/nfs/inode.c5
-rw-r--r--fs/nfs/nfs3acl.c29
-rw-r--r--fs/nfs/nfs3proc.c36
-rw-r--r--include/linux/nfs_fs.h9
4 files changed, 73 insertions, 6 deletions
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 440b9cbb6f81..50a03f1504a1 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -490,6 +490,11 @@ nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent)
490#else 490#else
491 server->flags &= ~NFS_MOUNT_NOACL; 491 server->flags &= ~NFS_MOUNT_NOACL;
492#endif /* CONFIG_NFS_V3_ACL */ 492#endif /* CONFIG_NFS_V3_ACL */
493 /*
494 * The VFS shouldn't apply the umask to mode bits. We will
495 * do so ourselves when necessary.
496 */
497 sb->s_flags |= MS_POSIXACL;
493 if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN) 498 if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
494 server->namelen = NFS3_MAXNAMLEN; 499 server->namelen = NFS3_MAXNAMLEN;
495 sb->s_time_gran = 1; 500 sb->s_time_gran = 1;
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c
index 393ba79fc14f..89b6468700e7 100644
--- a/fs/nfs/nfs3acl.c
+++ b/fs/nfs/nfs3acl.c
@@ -301,3 +301,32 @@ int nfs3_proc_setacl(struct inode *inode, int type, struct posix_acl *acl)
301fail: 301fail:
302 return PTR_ERR(alloc); 302 return PTR_ERR(alloc);
303} 303}
304
305int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode,
306 mode_t mode)
307{
308 struct posix_acl *dfacl, *acl;
309 int error = 0;
310
311 dfacl = nfs3_proc_getacl(dir, ACL_TYPE_DEFAULT);
312 if (IS_ERR(dfacl)) {
313 error = PTR_ERR(dfacl);
314 return (error == -EOPNOTSUPP) ? 0 : error;
315 }
316 if (!dfacl)
317 return 0;
318 acl = posix_acl_clone(dfacl, GFP_KERNEL);
319 error = -ENOMEM;
320 if (!acl)
321 goto out_release_dfacl;
322 error = posix_acl_create_masq(acl, &mode);
323 if (error < 0)
324 goto out_release_acl;
325 error = nfs3_proc_setacls(inode, acl, S_ISDIR(inode->i_mode) ?
326 dfacl : NULL);
327out_release_acl:
328 posix_acl_release(acl);
329out_release_dfacl:
330 posix_acl_release(dfacl);
331 return error;
332}
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index d03bac0cc42f..a9ddc196224d 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -314,7 +314,8 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
314 .fh = &fhandle, 314 .fh = &fhandle,
315 .fattr = &fattr 315 .fattr = &fattr
316 }; 316 };
317 int status; 317 mode_t mode = sattr->ia_mode;
318 int status;
318 319
319 dprintk("NFS call create %s\n", dentry->d_name.name); 320 dprintk("NFS call create %s\n", dentry->d_name.name);
320 arg.createmode = NFS3_CREATE_UNCHECKED; 321 arg.createmode = NFS3_CREATE_UNCHECKED;
@@ -324,6 +325,8 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
324 arg.verifier[1] = current->pid; 325 arg.verifier[1] = current->pid;
325 } 326 }
326 327
328 sattr->ia_mode &= ~current->fs->umask;
329
327again: 330again:
328 dir_attr.valid = 0; 331 dir_attr.valid = 0;
329 fattr.valid = 0; 332 fattr.valid = 0;
@@ -370,6 +373,9 @@ again:
370 nfs_refresh_inode(dentry->d_inode, &fattr); 373 nfs_refresh_inode(dentry->d_inode, &fattr);
371 dprintk("NFS reply setattr (post-create): %d\n", status); 374 dprintk("NFS reply setattr (post-create): %d\n", status);
372 } 375 }
376 if (status != 0)
377 goto out;
378 status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode);
373out: 379out:
374 dprintk("NFS reply create: %d\n", status); 380 dprintk("NFS reply create: %d\n", status);
375 return status; 381 return status;
@@ -539,15 +545,24 @@ nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
539 .fh = &fhandle, 545 .fh = &fhandle,
540 .fattr = &fattr 546 .fattr = &fattr
541 }; 547 };
542 int status; 548 int mode = sattr->ia_mode;
549 int status;
543 550
544 dprintk("NFS call mkdir %s\n", dentry->d_name.name); 551 dprintk("NFS call mkdir %s\n", dentry->d_name.name);
545 dir_attr.valid = 0; 552 dir_attr.valid = 0;
546 fattr.valid = 0; 553 fattr.valid = 0;
554
555 sattr->ia_mode &= ~current->fs->umask;
556
547 status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKDIR, &arg, &res, 0); 557 status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKDIR, &arg, &res, 0);
548 nfs_refresh_inode(dir, &dir_attr); 558 nfs_refresh_inode(dir, &dir_attr);
549 if (status == 0) 559 if (status != 0)
550 status = nfs_instantiate(dentry, &fhandle, &fattr); 560 goto out;
561 status = nfs_instantiate(dentry, &fhandle, &fattr);
562 if (status != 0)
563 goto out;
564 status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode);
565out:
551 dprintk("NFS reply mkdir: %d\n", status); 566 dprintk("NFS reply mkdir: %d\n", status);
552 return status; 567 return status;
553} 568}
@@ -642,6 +657,7 @@ nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
642 .fh = &fh, 657 .fh = &fh,
643 .fattr = &fattr 658 .fattr = &fattr
644 }; 659 };
660 mode_t mode = sattr->ia_mode;
645 int status; 661 int status;
646 662
647 switch (sattr->ia_mode & S_IFMT) { 663 switch (sattr->ia_mode & S_IFMT) {
@@ -654,12 +670,20 @@ nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
654 670
655 dprintk("NFS call mknod %s %u:%u\n", dentry->d_name.name, 671 dprintk("NFS call mknod %s %u:%u\n", dentry->d_name.name,
656 MAJOR(rdev), MINOR(rdev)); 672 MAJOR(rdev), MINOR(rdev));
673
674 sattr->ia_mode &= ~current->fs->umask;
675
657 dir_attr.valid = 0; 676 dir_attr.valid = 0;
658 fattr.valid = 0; 677 fattr.valid = 0;
659 status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKNOD, &arg, &res, 0); 678 status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKNOD, &arg, &res, 0);
660 nfs_refresh_inode(dir, &dir_attr); 679 nfs_refresh_inode(dir, &dir_attr);
661 if (status == 0) 680 if (status != 0)
662 status = nfs_instantiate(dentry, &fh, &fattr); 681 goto out;
682 status = nfs_instantiate(dentry, &fh, &fattr);
683 if (status != 0)
684 goto out;
685 status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode);
686out:
663 dprintk("NFS reply mknod: %d\n", status); 687 dprintk("NFS reply mknod: %d\n", status);
664 return status; 688 return status;
665} 689}
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 3a5e442ac776..7662c5131b47 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -478,6 +478,15 @@ extern void nfs_readdata_release(struct rpc_task *task);
478extern struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type); 478extern struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type);
479extern int nfs3_proc_setacl(struct inode *inode, int type, 479extern int nfs3_proc_setacl(struct inode *inode, int type,
480 struct posix_acl *acl); 480 struct posix_acl *acl);
481extern int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode,
482 mode_t mode);
483#else
484static inline int nfs3_proc_set_default_acl(struct inode *dir,
485 struct inode *inode,
486 mode_t mode)
487{
488 return 0;
489}
481#endif /* CONFIG_NFS_V3_ACL */ 490#endif /* CONFIG_NFS_V3_ACL */
482 491
483/* 492/*