diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/fuse/dir.c | 51 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 2 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 5 | ||||
-rw-r--r-- | fs/xfs/xfs_dinode.h | 3 | ||||
-rw-r--r-- | fs/xfs/xfs_inode.c | 31 | ||||
-rw-r--r-- | fs/xfs/xfs_log_recover.c | 13 |
6 files changed, 76 insertions, 29 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 0eda52738ec4..72a5d5b04494 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -1223,30 +1223,46 @@ static int fuse_direntplus_link(struct file *file, | |||
1223 | if (name.name[1] == '.' && name.len == 2) | 1223 | if (name.name[1] == '.' && name.len == 2) |
1224 | return 0; | 1224 | return 0; |
1225 | } | 1225 | } |
1226 | |||
1227 | if (invalid_nodeid(o->nodeid)) | ||
1228 | return -EIO; | ||
1229 | if (!fuse_valid_type(o->attr.mode)) | ||
1230 | return -EIO; | ||
1231 | |||
1226 | fc = get_fuse_conn(dir); | 1232 | fc = get_fuse_conn(dir); |
1227 | 1233 | ||
1228 | name.hash = full_name_hash(name.name, name.len); | 1234 | name.hash = full_name_hash(name.name, name.len); |
1229 | dentry = d_lookup(parent, &name); | 1235 | dentry = d_lookup(parent, &name); |
1230 | if (dentry && dentry->d_inode) { | 1236 | if (dentry) { |
1231 | inode = dentry->d_inode; | 1237 | inode = dentry->d_inode; |
1232 | if (get_node_id(inode) == o->nodeid) { | 1238 | if (!inode) { |
1239 | d_drop(dentry); | ||
1240 | } else if (get_node_id(inode) != o->nodeid || | ||
1241 | ((o->attr.mode ^ inode->i_mode) & S_IFMT)) { | ||
1242 | err = d_invalidate(dentry); | ||
1243 | if (err) | ||
1244 | goto out; | ||
1245 | } else if (is_bad_inode(inode)) { | ||
1246 | err = -EIO; | ||
1247 | goto out; | ||
1248 | } else { | ||
1233 | struct fuse_inode *fi; | 1249 | struct fuse_inode *fi; |
1234 | fi = get_fuse_inode(inode); | 1250 | fi = get_fuse_inode(inode); |
1235 | spin_lock(&fc->lock); | 1251 | spin_lock(&fc->lock); |
1236 | fi->nlookup++; | 1252 | fi->nlookup++; |
1237 | spin_unlock(&fc->lock); | 1253 | spin_unlock(&fc->lock); |
1238 | 1254 | ||
1255 | fuse_change_attributes(inode, &o->attr, | ||
1256 | entry_attr_timeout(o), | ||
1257 | attr_version); | ||
1258 | |||
1239 | /* | 1259 | /* |
1240 | * The other branch to 'found' comes via fuse_iget() | 1260 | * The other branch to 'found' comes via fuse_iget() |
1241 | * which bumps nlookup inside | 1261 | * which bumps nlookup inside |
1242 | */ | 1262 | */ |
1243 | goto found; | 1263 | goto found; |
1244 | } | 1264 | } |
1245 | err = d_invalidate(dentry); | ||
1246 | if (err) | ||
1247 | goto out; | ||
1248 | dput(dentry); | 1265 | dput(dentry); |
1249 | dentry = NULL; | ||
1250 | } | 1266 | } |
1251 | 1267 | ||
1252 | dentry = d_alloc(parent, &name); | 1268 | dentry = d_alloc(parent, &name); |
@@ -1259,25 +1275,30 @@ static int fuse_direntplus_link(struct file *file, | |||
1259 | if (!inode) | 1275 | if (!inode) |
1260 | goto out; | 1276 | goto out; |
1261 | 1277 | ||
1262 | alias = d_materialise_unique(dentry, inode); | 1278 | if (S_ISDIR(inode->i_mode)) { |
1263 | err = PTR_ERR(alias); | 1279 | mutex_lock(&fc->inst_mutex); |
1264 | if (IS_ERR(alias)) | 1280 | alias = fuse_d_add_directory(dentry, inode); |
1265 | goto out; | 1281 | mutex_unlock(&fc->inst_mutex); |
1282 | err = PTR_ERR(alias); | ||
1283 | if (IS_ERR(alias)) { | ||
1284 | iput(inode); | ||
1285 | goto out; | ||
1286 | } | ||
1287 | } else { | ||
1288 | alias = d_splice_alias(inode, dentry); | ||
1289 | } | ||
1290 | |||
1266 | if (alias) { | 1291 | if (alias) { |
1267 | dput(dentry); | 1292 | dput(dentry); |
1268 | dentry = alias; | 1293 | dentry = alias; |
1269 | } | 1294 | } |
1270 | 1295 | ||
1271 | found: | 1296 | found: |
1272 | fuse_change_attributes(inode, &o->attr, entry_attr_timeout(o), | ||
1273 | attr_version); | ||
1274 | |||
1275 | fuse_change_entry_timeout(dentry, o); | 1297 | fuse_change_entry_timeout(dentry, o); |
1276 | 1298 | ||
1277 | err = 0; | 1299 | err = 0; |
1278 | out: | 1300 | out: |
1279 | if (dentry) | 1301 | dput(dentry); |
1280 | dput(dentry); | ||
1281 | return err; | 1302 | return err; |
1282 | } | 1303 | } |
1283 | 1304 | ||
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index c74d6168db99..3850b018815f 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -1118,11 +1118,11 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, | |||
1118 | len, ((char *)p - (char *)q) + 4); | 1118 | len, ((char *)p - (char *)q) + 4); |
1119 | BUG(); | 1119 | BUG(); |
1120 | } | 1120 | } |
1121 | len = (char *)p - (char *)q - (bmval_len << 2); | ||
1122 | *q++ = htonl(bmval0); | 1121 | *q++ = htonl(bmval0); |
1123 | *q++ = htonl(bmval1); | 1122 | *q++ = htonl(bmval1); |
1124 | if (bmval_len == 3) | 1123 | if (bmval_len == 3) |
1125 | *q++ = htonl(bmval2); | 1124 | *q++ = htonl(bmval2); |
1125 | len = (char *)p - (char *)(q + 1); | ||
1126 | *q = htonl(len); | 1126 | *q = htonl(len); |
1127 | 1127 | ||
1128 | /* out: */ | 1128 | /* out: */ |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 8ff6a0019b0b..c827acb0e943 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -830,9 +830,10 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, | |||
830 | flags = O_WRONLY|O_LARGEFILE; | 830 | flags = O_WRONLY|O_LARGEFILE; |
831 | } | 831 | } |
832 | *filp = dentry_open(&path, flags, current_cred()); | 832 | *filp = dentry_open(&path, flags, current_cred()); |
833 | if (IS_ERR(*filp)) | 833 | if (IS_ERR(*filp)) { |
834 | host_err = PTR_ERR(*filp); | 834 | host_err = PTR_ERR(*filp); |
835 | else { | 835 | *filp = NULL; |
836 | } else { | ||
836 | host_err = ima_file_check(*filp, may_flags); | 837 | host_err = ima_file_check(*filp, may_flags); |
837 | 838 | ||
838 | if (may_flags & NFSD_MAY_64BIT_COOKIE) | 839 | if (may_flags & NFSD_MAY_64BIT_COOKIE) |
diff --git a/fs/xfs/xfs_dinode.h b/fs/xfs/xfs_dinode.h index 07d735a80a0f..e5869b50dc41 100644 --- a/fs/xfs/xfs_dinode.h +++ b/fs/xfs/xfs_dinode.h | |||
@@ -39,6 +39,9 @@ typedef struct xfs_timestamp { | |||
39 | * There is a very similar struct icdinode in xfs_inode which matches the | 39 | * There is a very similar struct icdinode in xfs_inode which matches the |
40 | * layout of the first 96 bytes of this structure, but is kept in native | 40 | * layout of the first 96 bytes of this structure, but is kept in native |
41 | * format instead of big endian. | 41 | * format instead of big endian. |
42 | * | ||
43 | * Note: di_flushiter is only used by v1/2 inodes - it's effectively a zeroed | ||
44 | * padding field for v3 inodes. | ||
42 | */ | 45 | */ |
43 | typedef struct xfs_dinode { | 46 | typedef struct xfs_dinode { |
44 | __be16 di_magic; /* inode magic # = XFS_DINODE_MAGIC */ | 47 | __be16 di_magic; /* inode magic # = XFS_DINODE_MAGIC */ |
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index b78481f99d9d..bb262c25c8de 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
@@ -896,7 +896,6 @@ xfs_dinode_to_disk( | |||
896 | to->di_projid_lo = cpu_to_be16(from->di_projid_lo); | 896 | to->di_projid_lo = cpu_to_be16(from->di_projid_lo); |
897 | to->di_projid_hi = cpu_to_be16(from->di_projid_hi); | 897 | to->di_projid_hi = cpu_to_be16(from->di_projid_hi); |
898 | memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad)); | 898 | memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad)); |
899 | to->di_flushiter = cpu_to_be16(from->di_flushiter); | ||
900 | to->di_atime.t_sec = cpu_to_be32(from->di_atime.t_sec); | 899 | to->di_atime.t_sec = cpu_to_be32(from->di_atime.t_sec); |
901 | to->di_atime.t_nsec = cpu_to_be32(from->di_atime.t_nsec); | 900 | to->di_atime.t_nsec = cpu_to_be32(from->di_atime.t_nsec); |
902 | to->di_mtime.t_sec = cpu_to_be32(from->di_mtime.t_sec); | 901 | to->di_mtime.t_sec = cpu_to_be32(from->di_mtime.t_sec); |
@@ -924,6 +923,9 @@ xfs_dinode_to_disk( | |||
924 | to->di_lsn = cpu_to_be64(from->di_lsn); | 923 | to->di_lsn = cpu_to_be64(from->di_lsn); |
925 | memcpy(to->di_pad2, from->di_pad2, sizeof(to->di_pad2)); | 924 | memcpy(to->di_pad2, from->di_pad2, sizeof(to->di_pad2)); |
926 | uuid_copy(&to->di_uuid, &from->di_uuid); | 925 | uuid_copy(&to->di_uuid, &from->di_uuid); |
926 | to->di_flushiter = 0; | ||
927 | } else { | ||
928 | to->di_flushiter = cpu_to_be16(from->di_flushiter); | ||
927 | } | 929 | } |
928 | } | 930 | } |
929 | 931 | ||
@@ -1029,10 +1031,14 @@ xfs_dinode_calc_crc( | |||
1029 | /* | 1031 | /* |
1030 | * Read the disk inode attributes into the in-core inode structure. | 1032 | * Read the disk inode attributes into the in-core inode structure. |
1031 | * | 1033 | * |
1032 | * If we are initialising a new inode and we are not utilising the | 1034 | * For version 5 superblocks, if we are initialising a new inode and we are not |
1033 | * XFS_MOUNT_IKEEP inode cluster mode, we can simple build the new inode core | 1035 | * utilising the XFS_MOUNT_IKEEP inode cluster mode, we can simple build the new |
1034 | * with a random generation number. If we are keeping inodes around, we need to | 1036 | * inode core with a random generation number. If we are keeping inodes around, |
1035 | * read the inode cluster to get the existing generation number off disk. | 1037 | * we need to read the inode cluster to get the existing generation number off |
1038 | * disk. Further, if we are using version 4 superblocks (i.e. v1/v2 inode | ||
1039 | * format) then log recovery is dependent on the di_flushiter field being | ||
1040 | * initialised from the current on-disk value and hence we must also read the | ||
1041 | * inode off disk. | ||
1036 | */ | 1042 | */ |
1037 | int | 1043 | int |
1038 | xfs_iread( | 1044 | xfs_iread( |
@@ -1054,6 +1060,7 @@ xfs_iread( | |||
1054 | 1060 | ||
1055 | /* shortcut IO on inode allocation if possible */ | 1061 | /* shortcut IO on inode allocation if possible */ |
1056 | if ((iget_flags & XFS_IGET_CREATE) && | 1062 | if ((iget_flags & XFS_IGET_CREATE) && |
1063 | xfs_sb_version_hascrc(&mp->m_sb) && | ||
1057 | !(mp->m_flags & XFS_MOUNT_IKEEP)) { | 1064 | !(mp->m_flags & XFS_MOUNT_IKEEP)) { |
1058 | /* initialise the on-disk inode core */ | 1065 | /* initialise the on-disk inode core */ |
1059 | memset(&ip->i_d, 0, sizeof(ip->i_d)); | 1066 | memset(&ip->i_d, 0, sizeof(ip->i_d)); |
@@ -2882,12 +2889,18 @@ xfs_iflush_int( | |||
2882 | __func__, ip->i_ino, ip->i_d.di_forkoff, ip); | 2889 | __func__, ip->i_ino, ip->i_d.di_forkoff, ip); |
2883 | goto corrupt_out; | 2890 | goto corrupt_out; |
2884 | } | 2891 | } |
2892 | |||
2885 | /* | 2893 | /* |
2886 | * bump the flush iteration count, used to detect flushes which | 2894 | * Inode item log recovery for v1/v2 inodes are dependent on the |
2887 | * postdate a log record during recovery. This is redundant as we now | 2895 | * di_flushiter count for correct sequencing. We bump the flush |
2888 | * log every change and hence this can't happen. Still, it doesn't hurt. | 2896 | * iteration count so we can detect flushes which postdate a log record |
2897 | * during recovery. This is redundant as we now log every change and | ||
2898 | * hence this can't happen but we need to still do it to ensure | ||
2899 | * backwards compatibility with old kernels that predate logging all | ||
2900 | * inode changes. | ||
2889 | */ | 2901 | */ |
2890 | ip->i_d.di_flushiter++; | 2902 | if (ip->i_d.di_version < 3) |
2903 | ip->i_d.di_flushiter++; | ||
2891 | 2904 | ||
2892 | /* | 2905 | /* |
2893 | * Copy the dirty parts of the inode into the on-disk | 2906 | * Copy the dirty parts of the inode into the on-disk |
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 6fcc910a50b9..7681b19aa5dc 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c | |||
@@ -2592,8 +2592,16 @@ xlog_recover_inode_pass2( | |||
2592 | goto error; | 2592 | goto error; |
2593 | } | 2593 | } |
2594 | 2594 | ||
2595 | /* Skip replay when the on disk inode is newer than the log one */ | 2595 | /* |
2596 | if (dicp->di_flushiter < be16_to_cpu(dip->di_flushiter)) { | 2596 | * di_flushiter is only valid for v1/2 inodes. All changes for v3 inodes |
2597 | * are transactional and if ordering is necessary we can determine that | ||
2598 | * more accurately by the LSN field in the V3 inode core. Don't trust | ||
2599 | * the inode versions we might be changing them here - use the | ||
2600 | * superblock flag to determine whether we need to look at di_flushiter | ||
2601 | * to skip replay when the on disk inode is newer than the log one | ||
2602 | */ | ||
2603 | if (!xfs_sb_version_hascrc(&mp->m_sb) && | ||
2604 | dicp->di_flushiter < be16_to_cpu(dip->di_flushiter)) { | ||
2597 | /* | 2605 | /* |
2598 | * Deal with the wrap case, DI_MAX_FLUSH is less | 2606 | * Deal with the wrap case, DI_MAX_FLUSH is less |
2599 | * than smaller numbers | 2607 | * than smaller numbers |
@@ -2608,6 +2616,7 @@ xlog_recover_inode_pass2( | |||
2608 | goto error; | 2616 | goto error; |
2609 | } | 2617 | } |
2610 | } | 2618 | } |
2619 | |||
2611 | /* Take the opportunity to reset the flush iteration count */ | 2620 | /* Take the opportunity to reset the flush iteration count */ |
2612 | dicp->di_flushiter = 0; | 2621 | dicp->di_flushiter = 0; |
2613 | 2622 | ||