diff options
Diffstat (limited to 'fs/nfsd/vfs.c')
-rw-r--r-- | fs/nfsd/vfs.c | 303 |
1 files changed, 148 insertions, 155 deletions
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index a293f0273263..6dd5f1970e01 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -1,7 +1,5 @@ | |||
1 | #define MSNFS /* HACK HACK */ | 1 | #define MSNFS /* HACK HACK */ |
2 | /* | 2 | /* |
3 | * linux/fs/nfsd/vfs.c | ||
4 | * | ||
5 | * File operations used by nfsd. Some of these have been ripped from | 3 | * File operations used by nfsd. Some of these have been ripped from |
6 | * other parts of the kernel because they weren't exported, others | 4 | * other parts of the kernel because they weren't exported, others |
7 | * are partial duplicates with added or changed functionality. | 5 | * are partial duplicates with added or changed functionality. |
@@ -16,48 +14,33 @@ | |||
16 | * Zerocpy NFS support (C) 2002 Hirokazu Takahashi <taka@valinux.co.jp> | 14 | * Zerocpy NFS support (C) 2002 Hirokazu Takahashi <taka@valinux.co.jp> |
17 | */ | 15 | */ |
18 | 16 | ||
19 | #include <linux/string.h> | ||
20 | #include <linux/time.h> | ||
21 | #include <linux/errno.h> | ||
22 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
23 | #include <linux/file.h> | 18 | #include <linux/file.h> |
24 | #include <linux/mount.h> | ||
25 | #include <linux/major.h> | ||
26 | #include <linux/splice.h> | 19 | #include <linux/splice.h> |
27 | #include <linux/proc_fs.h> | ||
28 | #include <linux/stat.h> | ||
29 | #include <linux/fcntl.h> | 20 | #include <linux/fcntl.h> |
30 | #include <linux/net.h> | ||
31 | #include <linux/unistd.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/pagemap.h> | ||
34 | #include <linux/in.h> | ||
35 | #include <linux/module.h> | ||
36 | #include <linux/namei.h> | 21 | #include <linux/namei.h> |
37 | #include <linux/vfs.h> | ||
38 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
39 | #include <linux/sunrpc/svc.h> | ||
40 | #include <linux/nfsd/nfsd.h> | ||
41 | #ifdef CONFIG_NFSD_V3 | ||
42 | #include <linux/nfs3.h> | ||
43 | #include <linux/nfsd/xdr3.h> | ||
44 | #endif /* CONFIG_NFSD_V3 */ | ||
45 | #include <linux/nfsd/nfsfh.h> | ||
46 | #include <linux/quotaops.h> | ||
47 | #include <linux/fsnotify.h> | 23 | #include <linux/fsnotify.h> |
48 | #include <linux/posix_acl.h> | ||
49 | #include <linux/posix_acl_xattr.h> | 24 | #include <linux/posix_acl_xattr.h> |
50 | #include <linux/xattr.h> | 25 | #include <linux/xattr.h> |
26 | #include <linux/jhash.h> | ||
27 | #include <linux/ima.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <asm/uaccess.h> | ||
30 | #include <linux/exportfs.h> | ||
31 | #include <linux/writeback.h> | ||
32 | |||
33 | #ifdef CONFIG_NFSD_V3 | ||
34 | #include "xdr3.h" | ||
35 | #endif /* CONFIG_NFSD_V3 */ | ||
36 | |||
51 | #ifdef CONFIG_NFSD_V4 | 37 | #ifdef CONFIG_NFSD_V4 |
52 | #include <linux/nfs4.h> | ||
53 | #include <linux/nfs4_acl.h> | 38 | #include <linux/nfs4_acl.h> |
54 | #include <linux/nfsd_idmap.h> | 39 | #include <linux/nfsd_idmap.h> |
55 | #include <linux/security.h> | ||
56 | #endif /* CONFIG_NFSD_V4 */ | 40 | #endif /* CONFIG_NFSD_V4 */ |
57 | #include <linux/jhash.h> | ||
58 | #include <linux/ima.h> | ||
59 | 41 | ||
60 | #include <asm/uaccess.h> | 42 | #include "nfsd.h" |
43 | #include "vfs.h" | ||
61 | 44 | ||
62 | #define NFSDDBG_FACILITY NFSDDBG_FILEOP | 45 | #define NFSDDBG_FACILITY NFSDDBG_FILEOP |
63 | 46 | ||
@@ -89,12 +72,6 @@ struct raparm_hbucket { | |||
89 | #define RAPARM_HASH_MASK (RAPARM_HASH_SIZE-1) | 72 | #define RAPARM_HASH_MASK (RAPARM_HASH_SIZE-1) |
90 | static struct raparm_hbucket raparm_hash[RAPARM_HASH_SIZE]; | 73 | static struct raparm_hbucket raparm_hash[RAPARM_HASH_SIZE]; |
91 | 74 | ||
92 | static inline int | ||
93 | nfsd_v4client(struct svc_rqst *rq) | ||
94 | { | ||
95 | return rq->rq_prog == NFS_PROGRAM && rq->rq_vers == 4; | ||
96 | } | ||
97 | |||
98 | /* | 75 | /* |
99 | * Called from nfsd_lookup and encode_dirent. Check if we have crossed | 76 | * Called from nfsd_lookup and encode_dirent. Check if we have crossed |
100 | * a mount point. | 77 | * a mount point. |
@@ -116,8 +93,16 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, | |||
116 | 93 | ||
117 | exp2 = rqst_exp_get_by_name(rqstp, &path); | 94 | exp2 = rqst_exp_get_by_name(rqstp, &path); |
118 | if (IS_ERR(exp2)) { | 95 | if (IS_ERR(exp2)) { |
119 | if (PTR_ERR(exp2) != -ENOENT) | 96 | err = PTR_ERR(exp2); |
120 | err = PTR_ERR(exp2); | 97 | /* |
98 | * We normally allow NFS clients to continue | ||
99 | * "underneath" a mountpoint that is not exported. | ||
100 | * The exception is V4ROOT, where no traversal is ever | ||
101 | * allowed without an explicit export of the new | ||
102 | * directory. | ||
103 | */ | ||
104 | if (err == -ENOENT && !(exp->ex_flags & NFSEXP_V4ROOT)) | ||
105 | err = 0; | ||
121 | path_put(&path); | 106 | path_put(&path); |
122 | goto out; | 107 | goto out; |
123 | } | 108 | } |
@@ -141,6 +126,53 @@ out: | |||
141 | return err; | 126 | return err; |
142 | } | 127 | } |
143 | 128 | ||
129 | static void follow_to_parent(struct path *path) | ||
130 | { | ||
131 | struct dentry *dp; | ||
132 | |||
133 | while (path->dentry == path->mnt->mnt_root && follow_up(path)) | ||
134 | ; | ||
135 | dp = dget_parent(path->dentry); | ||
136 | dput(path->dentry); | ||
137 | path->dentry = dp; | ||
138 | } | ||
139 | |||
140 | static int nfsd_lookup_parent(struct svc_rqst *rqstp, struct dentry *dparent, struct svc_export **exp, struct dentry **dentryp) | ||
141 | { | ||
142 | struct svc_export *exp2; | ||
143 | struct path path = {.mnt = mntget((*exp)->ex_path.mnt), | ||
144 | .dentry = dget(dparent)}; | ||
145 | |||
146 | follow_to_parent(&path); | ||
147 | |||
148 | exp2 = rqst_exp_parent(rqstp, &path); | ||
149 | if (PTR_ERR(exp2) == -ENOENT) { | ||
150 | *dentryp = dget(dparent); | ||
151 | } else if (IS_ERR(exp2)) { | ||
152 | path_put(&path); | ||
153 | return PTR_ERR(exp2); | ||
154 | } else { | ||
155 | *dentryp = dget(path.dentry); | ||
156 | exp_put(*exp); | ||
157 | *exp = exp2; | ||
158 | } | ||
159 | path_put(&path); | ||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | /* | ||
164 | * For nfsd purposes, we treat V4ROOT exports as though there was an | ||
165 | * export at *every* directory. | ||
166 | */ | ||
167 | int nfsd_mountpoint(struct dentry *dentry, struct svc_export *exp) | ||
168 | { | ||
169 | if (d_mountpoint(dentry)) | ||
170 | return 1; | ||
171 | if (!(exp->ex_flags & NFSEXP_V4ROOT)) | ||
172 | return 0; | ||
173 | return dentry->d_inode != NULL; | ||
174 | } | ||
175 | |||
144 | __be32 | 176 | __be32 |
145 | nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, | 177 | nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, |
146 | const char *name, unsigned int len, | 178 | const char *name, unsigned int len, |
@@ -169,35 +201,13 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
169 | dentry = dget(dparent); | 201 | dentry = dget(dparent); |
170 | else if (dparent != exp->ex_path.dentry) | 202 | else if (dparent != exp->ex_path.dentry) |
171 | dentry = dget_parent(dparent); | 203 | dentry = dget_parent(dparent); |
172 | else if (!EX_NOHIDE(exp)) | 204 | else if (!EX_NOHIDE(exp) && !nfsd_v4client(rqstp)) |
173 | dentry = dget(dparent); /* .. == . just like at / */ | 205 | dentry = dget(dparent); /* .. == . just like at / */ |
174 | else { | 206 | else { |
175 | /* checking mountpoint crossing is very different when stepping up */ | 207 | /* checking mountpoint crossing is very different when stepping up */ |
176 | struct svc_export *exp2 = NULL; | 208 | host_err = nfsd_lookup_parent(rqstp, dparent, &exp, &dentry); |
177 | struct dentry *dp; | 209 | if (host_err) |
178 | struct path path = {.mnt = mntget(exp->ex_path.mnt), | ||
179 | .dentry = dget(dparent)}; | ||
180 | |||
181 | while (path.dentry == path.mnt->mnt_root && | ||
182 | follow_up(&path)) | ||
183 | ; | ||
184 | dp = dget_parent(path.dentry); | ||
185 | dput(path.dentry); | ||
186 | path.dentry = dp; | ||
187 | |||
188 | exp2 = rqst_exp_parent(rqstp, &path); | ||
189 | if (PTR_ERR(exp2) == -ENOENT) { | ||
190 | dentry = dget(dparent); | ||
191 | } else if (IS_ERR(exp2)) { | ||
192 | host_err = PTR_ERR(exp2); | ||
193 | path_put(&path); | ||
194 | goto out_nfserr; | 210 | goto out_nfserr; |
195 | } else { | ||
196 | dentry = dget(path.dentry); | ||
197 | exp_put(exp); | ||
198 | exp = exp2; | ||
199 | } | ||
200 | path_put(&path); | ||
201 | } | 211 | } |
202 | } else { | 212 | } else { |
203 | fh_lock(fhp); | 213 | fh_lock(fhp); |
@@ -208,7 +218,7 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
208 | /* | 218 | /* |
209 | * check if we have crossed a mount point ... | 219 | * check if we have crossed a mount point ... |
210 | */ | 220 | */ |
211 | if (d_mountpoint(dentry)) { | 221 | if (nfsd_mountpoint(dentry, exp)) { |
212 | if ((host_err = nfsd_cross_mnt(rqstp, &dentry, &exp))) { | 222 | if ((host_err = nfsd_cross_mnt(rqstp, &dentry, &exp))) { |
213 | dput(dentry); | 223 | dput(dentry); |
214 | goto out_nfserr; | 224 | goto out_nfserr; |
@@ -263,6 +273,32 @@ out: | |||
263 | return err; | 273 | return err; |
264 | } | 274 | } |
265 | 275 | ||
276 | /* | ||
277 | * Commit metadata changes to stable storage. | ||
278 | */ | ||
279 | static int | ||
280 | commit_metadata(struct svc_fh *fhp) | ||
281 | { | ||
282 | struct inode *inode = fhp->fh_dentry->d_inode; | ||
283 | const struct export_operations *export_ops = inode->i_sb->s_export_op; | ||
284 | int error = 0; | ||
285 | |||
286 | if (!EX_ISSYNC(fhp->fh_export)) | ||
287 | return 0; | ||
288 | |||
289 | if (export_ops->commit_metadata) { | ||
290 | error = export_ops->commit_metadata(inode); | ||
291 | } else { | ||
292 | struct writeback_control wbc = { | ||
293 | .sync_mode = WB_SYNC_ALL, | ||
294 | .nr_to_write = 0, /* metadata only */ | ||
295 | }; | ||
296 | |||
297 | error = sync_inode(inode, &wbc); | ||
298 | } | ||
299 | |||
300 | return error; | ||
301 | } | ||
266 | 302 | ||
267 | /* | 303 | /* |
268 | * Set various file attributes. | 304 | * Set various file attributes. |
@@ -353,7 +389,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, | |||
353 | * If we are changing the size of the file, then | 389 | * If we are changing the size of the file, then |
354 | * we need to break all leases. | 390 | * we need to break all leases. |
355 | */ | 391 | */ |
356 | host_err = break_lease(inode, FMODE_WRITE | O_NONBLOCK); | 392 | host_err = break_lease(inode, O_WRONLY | O_NONBLOCK); |
357 | if (host_err == -EWOULDBLOCK) | 393 | if (host_err == -EWOULDBLOCK) |
358 | host_err = -ETIMEDOUT; | 394 | host_err = -ETIMEDOUT; |
359 | if (host_err) /* ENOMEM or EWOULDBLOCK */ | 395 | if (host_err) /* ENOMEM or EWOULDBLOCK */ |
@@ -369,7 +405,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, | |||
369 | put_write_access(inode); | 405 | put_write_access(inode); |
370 | goto out_nfserr; | 406 | goto out_nfserr; |
371 | } | 407 | } |
372 | vfs_dq_init(inode); | ||
373 | } | 408 | } |
374 | 409 | ||
375 | /* sanitize the mode change */ | 410 | /* sanitize the mode change */ |
@@ -726,7 +761,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
726 | * Check to see if there are any leases on this file. | 761 | * Check to see if there are any leases on this file. |
727 | * This may block while leases are broken. | 762 | * This may block while leases are broken. |
728 | */ | 763 | */ |
729 | host_err = break_lease(inode, O_NONBLOCK | ((access & NFSD_MAY_WRITE) ? FMODE_WRITE : 0)); | 764 | host_err = break_lease(inode, O_NONBLOCK | ((access & NFSD_MAY_WRITE) ? O_WRONLY : 0)); |
730 | if (host_err == -EWOULDBLOCK) | 765 | if (host_err == -EWOULDBLOCK) |
731 | host_err = -ETIMEDOUT; | 766 | host_err = -ETIMEDOUT; |
732 | if (host_err) /* NOMEM or WOULDBLOCK */ | 767 | if (host_err) /* NOMEM or WOULDBLOCK */ |
@@ -737,15 +772,13 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
737 | flags = O_RDWR|O_LARGEFILE; | 772 | flags = O_RDWR|O_LARGEFILE; |
738 | else | 773 | else |
739 | flags = O_WRONLY|O_LARGEFILE; | 774 | flags = O_WRONLY|O_LARGEFILE; |
740 | |||
741 | vfs_dq_init(inode); | ||
742 | } | 775 | } |
743 | *filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_path.mnt), | 776 | *filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_path.mnt), |
744 | flags, current_cred()); | 777 | flags, current_cred()); |
745 | if (IS_ERR(*filp)) | 778 | if (IS_ERR(*filp)) |
746 | host_err = PTR_ERR(*filp); | 779 | host_err = PTR_ERR(*filp); |
747 | else | 780 | else |
748 | ima_counts_get(*filp); | 781 | host_err = ima_file_check(*filp, access); |
749 | out_nfserr: | 782 | out_nfserr: |
750 | err = nfserrno(host_err); | 783 | err = nfserrno(host_err); |
751 | out: | 784 | out: |
@@ -763,46 +796,6 @@ nfsd_close(struct file *filp) | |||
763 | } | 796 | } |
764 | 797 | ||
765 | /* | 798 | /* |
766 | * Sync a file | ||
767 | * As this calls fsync (not fdatasync) there is no need for a write_inode | ||
768 | * after it. | ||
769 | */ | ||
770 | static inline int nfsd_dosync(struct file *filp, struct dentry *dp, | ||
771 | const struct file_operations *fop) | ||
772 | { | ||
773 | struct inode *inode = dp->d_inode; | ||
774 | int (*fsync) (struct file *, struct dentry *, int); | ||
775 | int err; | ||
776 | |||
777 | err = filemap_fdatawrite(inode->i_mapping); | ||
778 | if (err == 0 && fop && (fsync = fop->fsync)) | ||
779 | err = fsync(filp, dp, 0); | ||
780 | if (err == 0) | ||
781 | err = filemap_fdatawait(inode->i_mapping); | ||
782 | |||
783 | return err; | ||
784 | } | ||
785 | |||
786 | static int | ||
787 | nfsd_sync(struct file *filp) | ||
788 | { | ||
789 | int err; | ||
790 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
791 | dprintk("nfsd: sync file %s\n", filp->f_path.dentry->d_name.name); | ||
792 | mutex_lock(&inode->i_mutex); | ||
793 | err=nfsd_dosync(filp, filp->f_path.dentry, filp->f_op); | ||
794 | mutex_unlock(&inode->i_mutex); | ||
795 | |||
796 | return err; | ||
797 | } | ||
798 | |||
799 | int | ||
800 | nfsd_sync_dir(struct dentry *dp) | ||
801 | { | ||
802 | return nfsd_dosync(NULL, dp, dp->d_inode->i_fop); | ||
803 | } | ||
804 | |||
805 | /* | ||
806 | * Obtain the readahead parameters for the file | 799 | * Obtain the readahead parameters for the file |
807 | * specified by (dev, ino). | 800 | * specified by (dev, ino). |
808 | */ | 801 | */ |
@@ -1005,7 +998,7 @@ static int wait_for_concurrent_writes(struct file *file) | |||
1005 | 998 | ||
1006 | if (inode->i_state & I_DIRTY) { | 999 | if (inode->i_state & I_DIRTY) { |
1007 | dprintk("nfsd: write sync %d\n", task_pid_nr(current)); | 1000 | dprintk("nfsd: write sync %d\n", task_pid_nr(current)); |
1008 | err = nfsd_sync(file); | 1001 | err = vfs_fsync(file, file->f_path.dentry, 0); |
1009 | } | 1002 | } |
1010 | last_ino = inode->i_ino; | 1003 | last_ino = inode->i_ino; |
1011 | last_dev = inode->i_sb->s_dev; | 1004 | last_dev = inode->i_sb->s_dev; |
@@ -1153,8 +1146,9 @@ out: | |||
1153 | #ifdef CONFIG_NFSD_V3 | 1146 | #ifdef CONFIG_NFSD_V3 |
1154 | /* | 1147 | /* |
1155 | * Commit all pending writes to stable storage. | 1148 | * Commit all pending writes to stable storage. |
1156 | * Strictly speaking, we could sync just the indicated file region here, | 1149 | * |
1157 | * but there's currently no way we can ask the VFS to do so. | 1150 | * Note: we only guarantee that data that lies within the range specified |
1151 | * by the 'offset' and 'count' parameters will be synced. | ||
1158 | * | 1152 | * |
1159 | * Unfortunately we cannot lock the file to make sure we return full WCC | 1153 | * Unfortunately we cannot lock the file to make sure we return full WCC |
1160 | * data to the client, as locking happens lower down in the filesystem. | 1154 | * data to the client, as locking happens lower down in the filesystem. |
@@ -1164,23 +1158,32 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1164 | loff_t offset, unsigned long count) | 1158 | loff_t offset, unsigned long count) |
1165 | { | 1159 | { |
1166 | struct file *file; | 1160 | struct file *file; |
1167 | __be32 err; | 1161 | loff_t end = LLONG_MAX; |
1162 | __be32 err = nfserr_inval; | ||
1168 | 1163 | ||
1169 | if ((u64)count > ~(u64)offset) | 1164 | if (offset < 0) |
1170 | return nfserr_inval; | 1165 | goto out; |
1166 | if (count != 0) { | ||
1167 | end = offset + (loff_t)count - 1; | ||
1168 | if (end < offset) | ||
1169 | goto out; | ||
1170 | } | ||
1171 | 1171 | ||
1172 | err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_WRITE, &file); | 1172 | err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_WRITE, &file); |
1173 | if (err) | 1173 | if (err) |
1174 | return err; | 1174 | goto out; |
1175 | if (EX_ISSYNC(fhp->fh_export)) { | 1175 | if (EX_ISSYNC(fhp->fh_export)) { |
1176 | if (file->f_op && file->f_op->fsync) { | 1176 | int err2 = vfs_fsync_range(file, file->f_path.dentry, |
1177 | err = nfserrno(nfsd_sync(file)); | 1177 | offset, end, 0); |
1178 | } else { | 1178 | |
1179 | if (err2 != -EINVAL) | ||
1180 | err = nfserrno(err2); | ||
1181 | else | ||
1179 | err = nfserr_notsupp; | 1182 | err = nfserr_notsupp; |
1180 | } | ||
1181 | } | 1183 | } |
1182 | 1184 | ||
1183 | nfsd_close(file); | 1185 | nfsd_close(file); |
1186 | out: | ||
1184 | return err; | 1187 | return err; |
1185 | } | 1188 | } |
1186 | #endif /* CONFIG_NFSD_V3 */ | 1189 | #endif /* CONFIG_NFSD_V3 */ |
@@ -1333,12 +1336,14 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1333 | goto out_nfserr; | 1336 | goto out_nfserr; |
1334 | } | 1337 | } |
1335 | 1338 | ||
1336 | if (EX_ISSYNC(fhp->fh_export)) { | 1339 | err = nfsd_create_setattr(rqstp, resfhp, iap); |
1337 | err = nfserrno(nfsd_sync_dir(dentry)); | ||
1338 | write_inode_now(dchild->d_inode, 1); | ||
1339 | } | ||
1340 | 1340 | ||
1341 | err2 = nfsd_create_setattr(rqstp, resfhp, iap); | 1341 | /* |
1342 | * nfsd_setattr already committed the child. Transactional filesystems | ||
1343 | * had a chance to commit changes for both parent and child | ||
1344 | * simultaneously making the following commit_metadata a noop. | ||
1345 | */ | ||
1346 | err2 = nfserrno(commit_metadata(fhp)); | ||
1342 | if (err2) | 1347 | if (err2) |
1343 | err = err2; | 1348 | err = err2; |
1344 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | 1349 | mnt_drop_write(fhp->fh_export->ex_path.mnt); |
@@ -1370,7 +1375,6 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1370 | struct dentry *dentry, *dchild = NULL; | 1375 | struct dentry *dentry, *dchild = NULL; |
1371 | struct inode *dirp; | 1376 | struct inode *dirp; |
1372 | __be32 err; | 1377 | __be32 err; |
1373 | __be32 err2; | ||
1374 | int host_err; | 1378 | int host_err; |
1375 | __u32 v_mtime=0, v_atime=0; | 1379 | __u32 v_mtime=0, v_atime=0; |
1376 | 1380 | ||
@@ -1465,11 +1469,6 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1465 | if (created) | 1469 | if (created) |
1466 | *created = 1; | 1470 | *created = 1; |
1467 | 1471 | ||
1468 | if (EX_ISSYNC(fhp->fh_export)) { | ||
1469 | err = nfserrno(nfsd_sync_dir(dentry)); | ||
1470 | /* setattr will sync the child (or not) */ | ||
1471 | } | ||
1472 | |||
1473 | nfsd_check_ignore_resizing(iap); | 1472 | nfsd_check_ignore_resizing(iap); |
1474 | 1473 | ||
1475 | if (createmode == NFS3_CREATE_EXCLUSIVE) { | 1474 | if (createmode == NFS3_CREATE_EXCLUSIVE) { |
@@ -1484,9 +1483,13 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1484 | } | 1483 | } |
1485 | 1484 | ||
1486 | set_attr: | 1485 | set_attr: |
1487 | err2 = nfsd_create_setattr(rqstp, resfhp, iap); | 1486 | err = nfsd_create_setattr(rqstp, resfhp, iap); |
1488 | if (err2) | 1487 | |
1489 | err = err2; | 1488 | /* |
1489 | * nfsd_setattr already committed the child (and possibly also the parent). | ||
1490 | */ | ||
1491 | if (!err) | ||
1492 | err = nfserrno(commit_metadata(fhp)); | ||
1490 | 1493 | ||
1491 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | 1494 | mnt_drop_write(fhp->fh_export->ex_path.mnt); |
1492 | /* | 1495 | /* |
@@ -1601,12 +1604,9 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1601 | } | 1604 | } |
1602 | } else | 1605 | } else |
1603 | host_err = vfs_symlink(dentry->d_inode, dnew, path); | 1606 | host_err = vfs_symlink(dentry->d_inode, dnew, path); |
1604 | |||
1605 | if (!host_err) { | ||
1606 | if (EX_ISSYNC(fhp->fh_export)) | ||
1607 | host_err = nfsd_sync_dir(dentry); | ||
1608 | } | ||
1609 | err = nfserrno(host_err); | 1607 | err = nfserrno(host_err); |
1608 | if (!err) | ||
1609 | err = nfserrno(commit_metadata(fhp)); | ||
1610 | fh_unlock(fhp); | 1610 | fh_unlock(fhp); |
1611 | 1611 | ||
1612 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | 1612 | mnt_drop_write(fhp->fh_export->ex_path.mnt); |
@@ -1668,11 +1668,9 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, | |||
1668 | } | 1668 | } |
1669 | host_err = vfs_link(dold, dirp, dnew); | 1669 | host_err = vfs_link(dold, dirp, dnew); |
1670 | if (!host_err) { | 1670 | if (!host_err) { |
1671 | if (EX_ISSYNC(ffhp->fh_export)) { | 1671 | err = nfserrno(commit_metadata(ffhp)); |
1672 | err = nfserrno(nfsd_sync_dir(ddir)); | 1672 | if (!err) |
1673 | write_inode_now(dest, 1); | 1673 | err = nfserrno(commit_metadata(tfhp)); |
1674 | } | ||
1675 | err = 0; | ||
1676 | } else { | 1674 | } else { |
1677 | if (host_err == -EXDEV && rqstp->rq_vers == 2) | 1675 | if (host_err == -EXDEV && rqstp->rq_vers == 2) |
1678 | err = nfserr_acces; | 1676 | err = nfserr_acces; |
@@ -1768,10 +1766,10 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, | |||
1768 | goto out_dput_new; | 1766 | goto out_dput_new; |
1769 | 1767 | ||
1770 | host_err = vfs_rename(fdir, odentry, tdir, ndentry); | 1768 | host_err = vfs_rename(fdir, odentry, tdir, ndentry); |
1771 | if (!host_err && EX_ISSYNC(tfhp->fh_export)) { | 1769 | if (!host_err) { |
1772 | host_err = nfsd_sync_dir(tdentry); | 1770 | host_err = commit_metadata(tfhp); |
1773 | if (!host_err) | 1771 | if (!host_err) |
1774 | host_err = nfsd_sync_dir(fdentry); | 1772 | host_err = commit_metadata(ffhp); |
1775 | } | 1773 | } |
1776 | 1774 | ||
1777 | mnt_drop_write(ffhp->fh_export->ex_path.mnt); | 1775 | mnt_drop_write(ffhp->fh_export->ex_path.mnt); |
@@ -1852,12 +1850,9 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
1852 | 1850 | ||
1853 | dput(rdentry); | 1851 | dput(rdentry); |
1854 | 1852 | ||
1855 | if (host_err) | 1853 | if (!host_err) |
1856 | goto out_drop; | 1854 | host_err = commit_metadata(fhp); |
1857 | if (EX_ISSYNC(fhp->fh_export)) | ||
1858 | host_err = nfsd_sync_dir(dentry); | ||
1859 | 1855 | ||
1860 | out_drop: | ||
1861 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | 1856 | mnt_drop_write(fhp->fh_export->ex_path.mnt); |
1862 | out_nfserr: | 1857 | out_nfserr: |
1863 | err = nfserrno(host_err); | 1858 | err = nfserrno(host_err); |
@@ -2124,8 +2119,6 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, | |||
2124 | */ | 2119 | */ |
2125 | path.mnt = exp->ex_path.mnt; | 2120 | path.mnt = exp->ex_path.mnt; |
2126 | path.dentry = dentry; | 2121 | path.dentry = dentry; |
2127 | err = ima_path_check(&path, acc & (MAY_READ | MAY_WRITE | MAY_EXEC), | ||
2128 | IMA_COUNT_LEAVE); | ||
2129 | nfsd_out: | 2122 | nfsd_out: |
2130 | return err? nfserrno(err) : 0; | 2123 | return err? nfserrno(err) : 0; |
2131 | } | 2124 | } |