Skip to content

Commit dc8d38d

Browse files
committed
core: Reduce amount of calls to getattr/Stat, improve vfs.read
For many operations, we currently call VirtualFileSystem#getattr(Inode), which gets a full set of "stat" metadata for a given Inode. In many cases however, we're only interested in the type of the Inode (e.g., directory, regular file, symlink, etc.). Certain VirtualFileSystem implementations may be able to retrieve that specific information significantly faster than the full metadata set. Replace calls to vfs.getattr(Inode).type() with vfs.getStatType() where applicable, and provide default implementations for backwards compatibility. Also don't retrieve Stat information at all where not required: 1. In PseudoFS.checkAccess with ACE4_READ_ATTRIBUTES, and 2. For OperationREAD, allow VirtualFileSystem to skip the Stat check (currently checking StatType but also file size), which is currently done per every call to "read": Clarify the requirement of signaling "eof reached" as per NFSv4 spec, provide a new read() method to VirtualFileSystem with a corresponding callback function, and provide a default implementation for backwards compatibility. Signed-off-by: Christian Kohlschütter <[email protected]>
1 parent d72a1ae commit dc8d38d

20 files changed

+143
-62
lines changed

core/src/main/java/org/dcache/nfs/v3/MountServer.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,18 +105,18 @@ public mountres3 MOUNTPROC3_MNT_3(RpcCall call$, dirpath arg1) {
105105
try {
106106

107107
Inode rootInode = path2Inode(_vfs, mountPoint);
108-
Stat stat = _vfs.getattr(rootInode);
108+
Stat.Type type = _vfs.getStatType(rootInode);
109109

110-
if (stat.type() == Stat.Type.SYMLINK) {
110+
if (type == Stat.Type.SYMLINK) {
111111
/*
112112
* we resolve symlink only once
113113
*/
114114
String path = _vfs.readlink(rootInode);
115115
rootInode = path2Inode(_vfs, path);
116-
stat = _vfs.getattr(rootInode);
116+
type = _vfs.getStatType(rootInode);
117117
}
118118

119-
if (stat.type() != Stat.Type.DIRECTORY) {
119+
if (type != Stat.Type.DIRECTORY) {
120120
throw new NotDirException("Path is not a directory");
121121
}
122122

core/src/main/java/org/dcache/nfs/v4/OperationLINK.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,15 @@ public void process(CompoundContext context, nfs_resop4 result) throws ChimeraNF
5454
result.oplink.resok4.cinfo.atomic = true;
5555

5656
Inode parent = context.currentInode();
57-
Stat parentDirStat = context.getFs().getattr(parent);
58-
Stat inodeStat = context.getFs().getattr(context.savedInode());
5957

60-
if (parentDirStat.type() != Stat.Type.DIRECTORY) {
61-
throw new NotDirException("Can't create a hard-link in non directory object");
58+
Stat.Type inodeStatType = context.getFs().getStatType(context.savedInode());
59+
if (inodeStatType == Stat.Type.DIRECTORY) {
60+
throw new IsDirException("Can't hard-link a directory");
6261
}
6362

64-
if (inodeStat.type() == Stat.Type.DIRECTORY) {
65-
throw new IsDirException("Can't hard-link a directory");
63+
Stat parentDirStat = context.getFs().getattr(parent);
64+
if (parentDirStat.type() != Stat.Type.DIRECTORY) {
65+
throw new NotDirException("Can't create a hard-link in non directory object");
6666
}
6767

6868
result.oplink.resok4.cinfo.before = new changeid4(parentDirStat.getGeneration());

core/src/main/java/org/dcache/nfs/v4/OperationLOCKT.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public void process(CompoundContext context, nfs_resop4 result) throws IOExcepti
5757
throw new InvalException("zero lock len");
5858
}
5959

60-
switch (context.getFs().getattr(inode).type()) {
60+
switch (context.getFs().getStatType(inode)) {
6161
case REGULAR:
6262
// OK
6363
break;

core/src/main/java/org/dcache/nfs/v4/OperationLOOKUP.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,12 @@ public void process(CompoundContext context, nfs_resop4 result) throws ChimeraNF
4848

4949
String name = NameFilter.convertName(_args.oplookup.objname.value);
5050

51-
Stat stat = context.getFs().getattr(context.currentInode());
52-
if (stat.type() == Stat.Type.SYMLINK) {
51+
Stat.Type statType = context.getFs().getStatType(context.currentInode());
52+
if (statType == Stat.Type.SYMLINK) {
5353
throw new SymlinkException("parent not a symbolic link");
5454
}
5555

56-
if (stat.type() != Stat.Type.DIRECTORY) {
56+
if (statType != Stat.Type.DIRECTORY) {
5757
throw new NotDirException("parent not a directory");
5858
}
5959

core/src/main/java/org/dcache/nfs/v4/OperationLOOKUPP.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,13 @@ public OperationLOOKUPP(nfs_argop4 args) {
4646
public void process(CompoundContext context, nfs_resop4 result) throws ChimeraNFSException, IOException {
4747
final LOOKUPP4res res = result.oplookupp;
4848

49-
Stat stat = context.getFs().getattr(context.currentInode());
49+
Stat.Type statType = context.getFs().getStatType(context.currentInode());
5050

51-
if (stat.type() == Stat.Type.SYMLINK) {
51+
if (statType == Stat.Type.SYMLINK) {
5252
throw new SymlinkException("get parent on a symlink");
5353
}
5454

55-
if (stat.type() != Stat.Type.DIRECTORY) {
55+
if (statType != Stat.Type.DIRECTORY) {
5656
throw new NotDirException("not a directory");
5757
}
5858

core/src/main/java/org/dcache/nfs/v4/OperationOPEN.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -316,8 +316,8 @@ private void checkCanAccess(CompoundContext context, Inode inode, uint32_t share
316316
throw new AccessException();
317317
}
318318

319-
Stat stat = context.getFs().getattr(inode);
320-
switch (stat.type()) {
319+
Stat.Type statType = context.getFs().getStatType(inode);
320+
switch (statType) {
321321
case REGULAR:
322322
// OK
323323
break;

core/src/main/java/org/dcache/nfs/v4/OperationOPEN_CONFIRM.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,13 @@ public void process(CompoundContext context, nfs_resop4 result) throws IOExcepti
5353
throw new NotSuppException("operation OPEN_CONFIRM4 is obsolete in 4.x, x > 0");
5454
}
5555

56-
Inode inode = context.currentInode();
57-
Stat stat = context.getFs().getattr(context.currentInode());
56+
Stat.Type statType = context.getFs().getStatType(context.currentInode());
5857

59-
if (stat.type() == Stat.Type.DIRECTORY) {
58+
if (statType == Stat.Type.DIRECTORY) {
6059
throw new IsDirException();
6160
}
6261

63-
if (stat.type() == Stat.Type.SYMLINK) {
62+
if (statType == Stat.Type.SYMLINK) {
6463
throw new InvalException();
6564
}
6665

core/src/main/java/org/dcache/nfs/v4/OperationREAD.java

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,6 @@
2323
import java.nio.ByteBuffer;
2424

2525
import org.dcache.nfs.nfsstat;
26-
import org.dcache.nfs.status.InvalException;
27-
import org.dcache.nfs.status.IsDirException;
28-
import org.dcache.nfs.status.NfsIoException;
2926
import org.dcache.nfs.status.OpenModeException;
3027
import org.dcache.nfs.v4.xdr.READ4res;
3128
import org.dcache.nfs.v4.xdr.READ4resok;
@@ -34,7 +31,6 @@
3431
import org.dcache.nfs.v4.xdr.nfs_opnum4;
3532
import org.dcache.nfs.v4.xdr.nfs_resop4;
3633
import org.dcache.nfs.v4.xdr.stateid4;
37-
import org.dcache.nfs.vfs.Stat;
3834
import org.slf4j.Logger;
3935
import org.slf4j.LoggerFactory;
4036

@@ -50,17 +46,8 @@ public OperationREAD(nfs_argop4 args) {
5046
public void process(CompoundContext context, nfs_resop4 result) throws IOException {
5147
final READ4res res = result.opread;
5248

53-
Stat inodeStat = context.getFs().getattr(context.currentInode());
5449
stateid4 stateid = Stateids.getCurrentStateidIfNeeded(context, _args.opread.stateid);
5550

56-
if (inodeStat.type() == Stat.Type.DIRECTORY) {
57-
throw new IsDirException();
58-
}
59-
60-
if (inodeStat.type() == Stat.Type.SYMLINK) {
61-
throw new InvalException();
62-
}
63-
6451
NFS4Client client;
6552
if (context.getMinorversion() == 0) {
6653
/*
@@ -85,19 +72,17 @@ public void process(CompoundContext context, nfs_resop4 result) throws IOExcepti
8572

8673
ByteBuffer buf = ByteBuffer.allocate(count);
8774

88-
int bytesReaded = context.getFs().read(inode, buf, offset);
89-
if (bytesReaded < 0) {
90-
throw new NfsIoException("IO not allowed");
91-
}
92-
93-
buf.flip();
94-
res.status = nfsstat.NFS_OK;
9575
res.resok4 = new READ4resok();
76+
int bytesRead = context.getFs().read(inode, buf, offset, res.resok4::setEOF);
9677

97-
res.resok4.data = buf;
98-
99-
if (offset + bytesReaded >= inodeStat.getSize()) {
78+
if (bytesRead < 0) {
79+
buf.clear();
10080
res.resok4.eof = true;
81+
} else {
82+
buf.flip();
10183
}
84+
85+
res.status = nfsstat.NFS_OK;
86+
res.resok4.data = buf;
10287
}
10388
}

core/src/main/java/org/dcache/nfs/v4/OperationREADDIR.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,8 @@ public void process(final CompoundContext context, nfs_resop4 result) throws Chi
9494
throw new BadCookieException("bad cookie : " + startValue);
9595
}
9696

97-
Stat stat = context.getFs().getattr(dir);
98-
if (stat.type() != Stat.Type.DIRECTORY) {
97+
Stat.Type statType = context.getFs().getStatType(dir);
98+
if (statType != Stat.Type.DIRECTORY) {
9999
throw new NotDirException();
100100
}
101101

core/src/main/java/org/dcache/nfs/v4/OperationREADLINK.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ public OperationREADLINK(nfs_argop4 args) {
4747
public void process(CompoundContext context, nfs_resop4 result) throws ChimeraNFSException, IOException {
4848
final READLINK4res res = result.opreadlink;
4949

50-
Stat stat = context.getFs().getattr(context.currentInode());
51-
if (stat.type() != Stat.Type.SYMLINK) {
50+
Stat.Type statType = context.getFs().getStatType(context.currentInode());
51+
if (statType != Stat.Type.SYMLINK) {
5252
throw new InvalException("not a symlink");
5353
}
5454

0 commit comments

Comments
 (0)