func readMountStats()

in image/resources/knfsd-agent/mounts.go [93:228]


func readMountStats(proc procfs.Proc, nfsRoot string) (*client.MountStatsResponse, error) {
	info, err := proc.MountInfo()
	if err != nil {
		return nil, err
	}

	stats, err := proc.MountStats()
	if err != nil {
		return nil, err
	}

	type InfoKey struct {
		Device string
		Mount  string
	}

	// NFS stats only includes super options and is missing some of the
	// per-mount options such as noatime. So fetch all the of the options from
	// /proc/self/mountinfo.
	// This avoids a client needing to query both /mounts and /mountstats and
	// having to merge the results locally to get the complete information.
	options := make(map[InfoKey]map[string]string)
	for _, m := range info {
		if !isNFS(m.FSType) {
			continue
		}
		if !strings.HasPrefix(m.MountPoint, nfsRoot) {
			continue
		}
		key := InfoKey{
			Device: m.Source,
			Mount:  m.MountPoint,
		}
		options[key] = combineMountOptions(m.Options, m.SuperOptions)
	}

	var mounts []client.MountStats
	for _, e := range stats {
		if !isNFS(e.Type) {
			continue
		}
		if !strings.HasPrefix(e.Mount, nfsRoot) {
			continue
		}

		m := client.MountStats{
			Device: e.Device,
			Mount:  e.Mount,
			Export: e.Mount[len(nfsRoot)-1:],
			// lookup the options from mountinfo
			Options: options[InfoKey{e.Device, e.Mount}],
		}

		if s, ok := e.Stats.(*procfs.MountStatsNFS); ok {
			// combine the options from the stats with options from mountinfo
			m.Options = combineMountOptions(m.Options, s.Opts)

			ops := make([]client.NFSOperationStats, len(s.Operations))
			for i, o := range s.Operations {
				retries := uint64(0)
				if o.Transmissions > o.Requests {
					retries = o.Transmissions - o.Requests
				}

				ops[i] = client.NFSOperationStats{
					Operation:             o.Operation,
					Requests:              o.Requests,
					Transmissions:         o.Transmissions,
					Retries:               retries,
					MajorTimeouts:         o.MajorTimeouts,
					BytesSent:             o.BytesSent,
					BytesReceived:         o.BytesReceived,
					QueueMilliseconds:     o.CumulativeQueueMilliseconds,
					RTTMilliseconds:       o.CumulativeTotalResponseMilliseconds,
					ExecutionMilliseconds: o.CumulativeTotalRequestMilliseconds,
					Errors:                o.Errors,
				}
			}

			m.Stats = client.NFSMountStats{
				Age: client.Duration(s.Age),
				Bytes: client.NFSByteStats{
					NormalRead:  s.Bytes.Read,
					NormalWrite: s.Bytes.Write,
					DirectRead:  s.Bytes.DirectRead,
					DirectWrite: s.Bytes.DirectWrite,
					ServerRead:  s.Bytes.ReadTotal,
					ServerWrite: s.Bytes.WriteTotal,
					ReadPages:   s.Bytes.ReadPages,
					WritePages:  s.Bytes.WritePages,
				},
				Events: client.NFSEventStats{
					InodeRevalidate:     s.Events.InodeRevalidate,
					DnodeRevalidate:     s.Events.DnodeRevalidate,
					DataInvalidate:      s.Events.DataInvalidate,
					AttributeInvalidate: s.Events.AttributeInvalidate,

					VFSOpen:        s.Events.VFSOpen,
					VFSLookup:      s.Events.VFSLookup,
					VFSAccess:      s.Events.VFSAccess,
					VFSUpdatePage:  s.Events.VFSUpdatePage,
					VFSReadPage:    s.Events.VFSReadPage,
					VFSReadPages:   s.Events.VFSReadPages,
					VFSWritePage:   s.Events.VFSWritePage,
					VFSWritePages:  s.Events.VFSWritePages,
					VFSGetdents:    s.Events.VFSGetdents,
					VFSSetattr:     s.Events.VFSSetattr,
					VFSFlush:       s.Events.VFSFlush,
					VFSFsync:       s.Events.VFSFsync,
					VFSLock:        s.Events.VFSLock,
					VFSFileRelease: s.Events.VFSFileRelease,

					// CongestionWait is not used by the kernel
					Truncation:     s.Events.Truncation,
					WriteExtension: s.Events.WriteExtension,
					SillyRename:    s.Events.SillyRename,
					ShortRead:      s.Events.ShortRead,
					ShortWrite:     s.Events.ShortWrite,
					Delay:          s.Events.JukeboxDelay,
					PNFSRead:       s.Events.PNFSRead,
					PNFSWrite:      s.Events.PNFSWrite,
				},
				Operations: ops,
			}
		}
		mounts = append(mounts, m)
	}

	sort.Slice(mounts, func(i, j int) bool {
		a := mounts[i].Mount
		b := mounts[j].Mount
		return a < b
	})

	return &client.MountStatsResponse{Mounts: mounts}, nil
}