aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/vfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/vfs.c')
-rw-r--r--fs/nfsd/vfs.c303
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)
90static struct raparm_hbucket raparm_hash[RAPARM_HASH_SIZE]; 73static struct raparm_hbucket raparm_hash[RAPARM_HASH_SIZE];
91 74
92static inline int
93nfsd_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
129static 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
140static 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 */
167int 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
145nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, 177nfsd_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 */
279static int
280commit_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);
749out_nfserr: 782out_nfserr:
750 err = nfserrno(host_err); 783 err = nfserrno(host_err);
751out: 784out:
@@ -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 */
770static 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
786static int
787nfsd_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
799int
800nfsd_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);
1186out:
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
1860out_drop:
1861 mnt_drop_write(fhp->fh_export->ex_path.mnt); 1856 mnt_drop_write(fhp->fh_export->ex_path.mnt);
1862out_nfserr: 1857out_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);
2129nfsd_out: 2122nfsd_out:
2130 return err? nfserrno(err) : 0; 2123 return err? nfserrno(err) : 0;
2131} 2124}