// Slower C++ solution:
#include<bits/stdc++.h>

using namespace std;



int n, m;

vector<int>ady[100001];

vector<int>topoSort;

vector<int>who[100001];

bool visitado[100001];

int memo[100001];



void dfs(int nodo){

    visitado[nodo] = true;

    for(int i : ady[nodo])

        if (!visitado[i])

            dfs(i);

    topoSort.push_back(nodo);

}



void topological_sort(){

    for(int i = 1; i <= n; i++)

        if(!visitado[i])

            dfs(i);

}



int dp(int nodo){

    if(who[nodo].size() == 0)//es nodo raiz

        return  1;

    if(memo[nodo])

        return memo[nodo];

    int Max = 0;

    for(auto i : who[nodo])

        memo[nodo] = max(memo[nodo], dp(i) + 1);

    return memo[nodo];

}



int maxPath(){

    topological_sort();

    //hacemos orden topologico

    // for(int i = 0; i < n; i++)

    //     cout<<topoSort[i]<<" ";

    // cout<<endl;

    // for(int i = 1; i <= n; i++){

    //     cout<<i<<": ";

    //     for(auto j : who[i])

    //         cout<<j<<" ";

    //     cout<<endl;

    // }

    // cout<<endl;

    // exit(0);

    int Max = -1;

    for(int i = 0; i < n; i++)        

        Max = max(Max, dp(topoSort[i]));

    return Max;

}



int main(){



    cin.tie(0);

    ios_base::sync_with_stdio(0);



    cin>>n>>m;



    while(m--){

        int a, b;

        cin>>a>>b;

        ady[a].push_back(b);

        who[b].push_back(a);

    }

    cout<<maxPath() - 1;

}

// Faster C++ solution for the same problem (measured speedup: 1.60730366900983x):
#include<iostream>

#include<iomanip>

#include<cstdio>

#include<cmath>

#include<vector>

#include<string>

#include<algorithm>

#include<queue>

#include<set>

#include<map>

#include<limits>

#include<stack>

#include<array>

#include<stdio.h>

#include<cstring>



using namespace std;



typedef long long ll;

typedef pair<int,int> ii;

typedef vector<pair<int,int> > vii;

typedef vector<vii> vvii;

typedef vector<int> vi;

typedef vector<vi> vvi;

typedef vector<ll> vll;

typedef vector<vll> vvll;

typedef vector<bool> vb;

typedef vector<vb> vvb;

typedef vector<char> vc;

typedef vector<vc> vvc;

typedef vector<string> vs;



int INF = std::numeric_limits<int>::max();

ll LLINF = 1e15;

int NINF = std::numeric_limits<int>::min();

int MOD = 1e9+7;



int col[] = {0,-1,0,1,1,1,-1,-1};

int row[] = {-1,0,1,0,1,-1,1,-1};



//knight moves

int cc[] = {1,2,2,1,-1,-1,-2,-2};

int rr[] = {-2,-1,1,2,-2,2,1,-1};



vvi adjLst(1e5+5,vi());

vb vstd(1e5+5,0);

vi dp(1e5+5,1);





void dfs(int u)

{

    vstd[u] = 1;

    for(int i = 0 ; i < adjLst[u].size() ; ++i)

    {

        if(!vstd[adjLst[u][i]])

            dfs(adjLst[u][i]);



        dp[u] = max(dp[u], dp[adjLst[u][i]] +1);

    }

}





int main()

{

    //cout << LLINF ;

    ios::sync_with_stdio(0);

    cin.tie(0);



    int n, m, u, v;

    cin >> n >> m;

    for(int i = 0; i < m ; ++i)

    {

        cin >> u >> v;

        adjLst[u].push_back(v);

    }



    int mx = 0;

    for(int i = 1 ; i <= n ; ++i)

    {

        if(!vstd[i])

            dfs(i);

    }



    for(int i = 1; i <= n ; ++i)

        mx = max(mx,dp[i]);



    cout << mx-1;



    return 0;

}