# Original solution
from collections import deque

def main():
    n, adj = getInputs()

    # maxDistance[start]
    maxDistance = [0] * n
    overallMaxDistance = 0

    calculated = [0] * n

    for v in getVertexSequence(n, adj):
        # distance[dest] (starting at v)
        distance = [0] * n
        currMaxDistance = 0

        toVisit = deque([v])

        while len(toVisit) > 0:
            curr = toVisit.popleft()

            for dest in adj[curr]:
                if calculated[dest] == 1:
                    newDistance = distance[curr] + maxDistance[dest] + 1

                    if newDistance > distance[dest]:
                        distance[dest] = newDistance

                        if distance[dest] > currMaxDistance:
                            currMaxDistance = distance[dest]
                else:
                    if distance[curr] + 1 > distance[dest]:
                        distance[dest] = distance[curr] + 1

                        if distance[dest] > currMaxDistance:
                            currMaxDistance = distance[dest]

                    toVisit.append(dest)

        maxDistance[v] = currMaxDistance
        if currMaxDistance > overallMaxDistance:
            overallMaxDistance = currMaxDistance

        calculated[v] = 1

    print(overallMaxDistance)

def getInputs():
    n, m = [int(x) for x in input().split()]

    adj = []
    for i in range(n):
        adj.append([])

    for i in range(m):
        a, b = [int(x) for x in input().split()]
        adj[a - 1].append(b - 1)

    return n, adj

def getVertexSequence(n, adj):
    pairs = []
    for i in range(n):
        pairs.append((i, adj[i]))

    pairs.sort(key=(lambda x: len(x[1])))

    sequence = []
    for i in range(n):
        sequence.append(pairs[i][0])

    return sequence

main()


# Optimized solution
def main():
    n, adj = getInputs()
    sequence = getTopologicalSort(n, adj)

    distance = [-1] * n
    longest = -1

    for v in sequence:
        if len(adj[v]) == 0:
            distance[v] = 0
        else:
            for dest in adj[v]:
                distance[v] = max(distance[v], 1 + distance[dest])
                longest = max(longest, distance[v])

    print(longest)

def getTopologicalSort(n, adj):
    state = [0] * n
    toVisit = list(range(n))

    topologicalSort = []
    order = []

    while len(toVisit) > 0:
        curr = toVisit.pop()

        if state[curr] == 0:
            order.append(curr)
            state[curr] = 1

            foundNewDest = False
            for dest in adj[curr]:
                if state[dest] == 0:
                    toVisit.append(dest)
                    foundNewDest = True

            if not foundNewDest:
                while True:
                    v = order[-1]

                    allProcessed = True
                    for dest in adj[v]:
                        if state[dest] == 0:
                            allProcessed = False
                            break

                    if allProcessed:
                        state[v] = 2
                        topologicalSort.append(order.pop())

                    if len(order) == 0 or not allProcessed:
                        break

    return topologicalSort

def getInputs():
    n, m = [int(x) for x in input().split()]

    adj = []
    for i in range(n):
        adj.append([])

    for i in range(m):
        a, b = [int(x) for x in input().split()]
        adj[a - 1].append(b - 1)

    return n, adj

main()