diff options
-rw-r--r-- | fs/nfs/nfs3acl.c | 100 | ||||
-rw-r--r-- | fs/nfs/nfs3proc.c | 1 | ||||
-rw-r--r-- | include/linux/nfs_fs.h | 11 |
3 files changed, 97 insertions, 15 deletions
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c index 89b6468700e7..451112ff9aa4 100644 --- a/fs/nfs/nfs3acl.c +++ b/fs/nfs/nfs3acl.c | |||
@@ -113,6 +113,69 @@ int nfs3_removexattr(struct dentry *dentry, const char *name) | |||
113 | return nfs3_proc_setacl(inode, type, NULL); | 113 | return nfs3_proc_setacl(inode, type, NULL); |
114 | } | 114 | } |
115 | 115 | ||
116 | static void __nfs3_forget_cached_acls(struct nfs_inode *nfsi) | ||
117 | { | ||
118 | if (nfsi->acl_access != ERR_PTR(-EAGAIN)) { | ||
119 | posix_acl_release(nfsi->acl_access); | ||
120 | nfsi->acl_access = ERR_PTR(-EAGAIN); | ||
121 | } | ||
122 | if (nfsi->acl_default != ERR_PTR(-EAGAIN)) { | ||
123 | posix_acl_release(nfsi->acl_default); | ||
124 | nfsi->acl_default = ERR_PTR(-EAGAIN); | ||
125 | } | ||
126 | } | ||
127 | |||
128 | void nfs3_forget_cached_acls(struct inode *inode) | ||
129 | { | ||
130 | dprintk("NFS: nfs3_forget_cached_acls(%s/%ld)\n", inode->i_sb->s_id, | ||
131 | inode->i_ino); | ||
132 | spin_lock(&inode->i_lock); | ||
133 | __nfs3_forget_cached_acls(NFS_I(inode)); | ||
134 | spin_unlock(&inode->i_lock); | ||
135 | } | ||
136 | |||
137 | static struct posix_acl *nfs3_get_cached_acl(struct inode *inode, int type) | ||
138 | { | ||
139 | struct nfs_inode *nfsi = NFS_I(inode); | ||
140 | struct posix_acl *acl = ERR_PTR(-EAGAIN); | ||
141 | |||
142 | spin_lock(&inode->i_lock); | ||
143 | switch(type) { | ||
144 | case ACL_TYPE_ACCESS: | ||
145 | acl = nfsi->acl_access; | ||
146 | break; | ||
147 | |||
148 | case ACL_TYPE_DEFAULT: | ||
149 | acl = nfsi->acl_default; | ||
150 | break; | ||
151 | |||
152 | default: | ||
153 | return ERR_PTR(-EINVAL); | ||
154 | } | ||
155 | if (acl == ERR_PTR(-EAGAIN)) | ||
156 | acl = ERR_PTR(-EAGAIN); | ||
157 | else | ||
158 | acl = posix_acl_dup(acl); | ||
159 | spin_unlock(&inode->i_lock); | ||
160 | dprintk("NFS: nfs3_get_cached_acl(%s/%ld, %d) = %p\n", inode->i_sb->s_id, | ||
161 | inode->i_ino, type, acl); | ||
162 | return acl; | ||
163 | } | ||
164 | |||
165 | static void nfs3_cache_acls(struct inode *inode, struct posix_acl *acl, | ||
166 | struct posix_acl *dfacl) | ||
167 | { | ||
168 | struct nfs_inode *nfsi = NFS_I(inode); | ||
169 | |||
170 | dprintk("nfs3_cache_acls(%s/%ld, %p, %p)\n", inode->i_sb->s_id, | ||
171 | inode->i_ino, acl, dfacl); | ||
172 | spin_lock(&inode->i_lock); | ||
173 | __nfs3_forget_cached_acls(NFS_I(inode)); | ||
174 | nfsi->acl_access = posix_acl_dup(acl); | ||
175 | nfsi->acl_default = posix_acl_dup(dfacl); | ||
176 | spin_unlock(&inode->i_lock); | ||
177 | } | ||
178 | |||
116 | struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) | 179 | struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) |
117 | { | 180 | { |
118 | struct nfs_server *server = NFS_SERVER(inode); | 181 | struct nfs_server *server = NFS_SERVER(inode); |
@@ -126,26 +189,32 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) | |||
126 | struct nfs3_getaclres res = { | 189 | struct nfs3_getaclres res = { |
127 | .fattr = &fattr, | 190 | .fattr = &fattr, |
128 | }; | 191 | }; |
129 | struct posix_acl *acl = NULL; | 192 | struct posix_acl *acl; |
130 | int status, count; | 193 | int status, count; |
131 | 194 | ||
132 | if (!nfs_server_capable(inode, NFS_CAP_ACLS)) | 195 | if (!nfs_server_capable(inode, NFS_CAP_ACLS)) |
133 | return ERR_PTR(-EOPNOTSUPP); | 196 | return ERR_PTR(-EOPNOTSUPP); |
134 | 197 | ||
135 | switch (type) { | 198 | status = nfs_revalidate_inode(server, inode); |
136 | case ACL_TYPE_ACCESS: | 199 | if (status < 0) |
137 | args.mask = NFS_ACLCNT|NFS_ACL; | 200 | return ERR_PTR(status); |
138 | break; | 201 | acl = nfs3_get_cached_acl(inode, type); |
139 | 202 | if (acl != ERR_PTR(-EAGAIN)) | |
140 | case ACL_TYPE_DEFAULT: | 203 | return acl; |
141 | if (!S_ISDIR(inode->i_mode)) | 204 | acl = NULL; |
142 | return NULL; | 205 | |
143 | args.mask = NFS_DFACLCNT|NFS_DFACL; | 206 | /* |
144 | break; | 207 | * Only get the access acl when explicitly requested: We don't |
145 | 208 | * need it for access decisions, and only some applications use | |
146 | default: | 209 | * it. Applications which request the access acl first are not |
147 | return ERR_PTR(-EINVAL); | 210 | * penalized from this optimization. |
148 | } | 211 | */ |
212 | if (type == ACL_TYPE_ACCESS) | ||
213 | args.mask |= NFS_ACLCNT|NFS_ACL; | ||
214 | if (S_ISDIR(inode->i_mode)) | ||
215 | args.mask |= NFS_DFACLCNT|NFS_DFACL; | ||
216 | if (args.mask == 0) | ||
217 | return NULL; | ||
149 | 218 | ||
150 | dprintk("NFS call getacl\n"); | 219 | dprintk("NFS call getacl\n"); |
151 | status = rpc_call(server->client_acl, ACLPROC3_GETACL, | 220 | status = rpc_call(server->client_acl, ACLPROC3_GETACL, |
@@ -180,6 +249,7 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) | |||
180 | res.acl_access = NULL; | 249 | res.acl_access = NULL; |
181 | } | 250 | } |
182 | } | 251 | } |
252 | nfs3_cache_acls(inode, res.acl_access, res.acl_default); | ||
183 | 253 | ||
184 | switch(type) { | 254 | switch(type) { |
185 | case ACL_TYPE_ACCESS: | 255 | case ACL_TYPE_ACCESS: |
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index a9ddc196224d..7851569b31c6 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c | |||
@@ -882,4 +882,5 @@ struct nfs_rpc_ops nfs_v3_clientops = { | |||
882 | .file_open = nfs_open, | 882 | .file_open = nfs_open, |
883 | .file_release = nfs_release, | 883 | .file_release = nfs_release, |
884 | .lock = nfs3_proc_lock, | 884 | .lock = nfs3_proc_lock, |
885 | .clear_acl_cache = nfs3_forget_cached_acls, | ||
885 | }; | 886 | }; |
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 7662c5131b47..4ceac9ddac93 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h | |||
@@ -91,6 +91,8 @@ struct nfs_open_context { | |||
91 | */ | 91 | */ |
92 | struct nfs_delegation; | 92 | struct nfs_delegation; |
93 | 93 | ||
94 | struct posix_acl; | ||
95 | |||
94 | /* | 96 | /* |
95 | * nfs fs inode data in memory | 97 | * nfs fs inode data in memory |
96 | */ | 98 | */ |
@@ -144,6 +146,10 @@ struct nfs_inode { | |||
144 | atomic_t data_updates; | 146 | atomic_t data_updates; |
145 | 147 | ||
146 | struct nfs_access_entry cache_access; | 148 | struct nfs_access_entry cache_access; |
149 | #ifdef CONFIG_NFS_V3_ACL | ||
150 | struct posix_acl *acl_access; | ||
151 | struct posix_acl *acl_default; | ||
152 | #endif | ||
147 | 153 | ||
148 | /* | 154 | /* |
149 | * This is the cookie verifier used for NFSv3 readdir | 155 | * This is the cookie verifier used for NFSv3 readdir |
@@ -480,6 +486,7 @@ extern int nfs3_proc_setacl(struct inode *inode, int type, | |||
480 | struct posix_acl *acl); | 486 | struct posix_acl *acl); |
481 | extern int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode, | 487 | extern int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode, |
482 | mode_t mode); | 488 | mode_t mode); |
489 | extern void nfs3_forget_cached_acls(struct inode *inode); | ||
483 | #else | 490 | #else |
484 | static inline int nfs3_proc_set_default_acl(struct inode *dir, | 491 | static inline int nfs3_proc_set_default_acl(struct inode *dir, |
485 | struct inode *inode, | 492 | struct inode *inode, |
@@ -487,6 +494,10 @@ static inline int nfs3_proc_set_default_acl(struct inode *dir, | |||
487 | { | 494 | { |
488 | return 0; | 495 | return 0; |
489 | } | 496 | } |
497 | |||
498 | static inline void nfs3_forget_cached_acls(struct inode *inode) | ||
499 | { | ||
500 | } | ||
490 | #endif /* CONFIG_NFS_V3_ACL */ | 501 | #endif /* CONFIG_NFS_V3_ACL */ |
491 | 502 | ||
492 | /* | 503 | /* |