#include <bits/stdc++.h>
using namespace std;
#define rep(i,n) for(int i=0;i<(int)n;i++)
#define double long double
#define sp(p) cout<<setprecision(16)<<fixed<<p<<endl;
#define DEBUG(x) cerr<<#x<<": "<<x<<endl;
#define all(a) a.begin(),a.end()
#define sort(a) sort(all(a))
#define rsort(a) sort(all(a),greater<>())
#define vout(v) cout<<#v<<": ";for(int i=0;i<(int)v.size()-1;i++){cout<<v[i]<<" ";}cout<<v[v.size()-1]<<"\n";
#define vmax(v) *max_element(all(v))
#define debg(a) cout<<#a<<" "<<a<<endl;
#define show(a) for(cont &y:a){for(cont &x:y){cout<<x<<" ";}cout<<endl;}
#define MOUT(m,r,c) rep(i,r){rep(j,c){cout<<m[i][j]<<" ";}cout<<endl;}
#define mout(m) MOUT(m,m.size(),m[0].size())
template<class T> inline int out(const T &t){ print(t); putchar('\n'); return 0; }
template<class T>inline T gcd(T a,T b){if(b==0)return a; return(gcd(b,a%b));}
template<class T>inline T lcm(T a,T b){return a/gcd(a,b)*b;}
typedef long long ll;
typedef pair<int,int> P;
const long long MOD=1000000007;
// const long long INF = 1e18;
const long long INF = 1e8;

int val;
// vector<vector<ll>> dp(10000, vector<ll>(10000, INF));
// vector<vector<int>> dp(100010, vector<int>(100010, 0));
// void warshall_floyd(ll N){
//     for (ll k = 0; k < N; k++){
//         for (ll i = 0; i < N; i++){
//             // for (ll j = 0; j < N; j++) dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j]);
//             for (ll j = 0; j < N; j++) {
//               if(dp[i][k] != 0 && dp[k][j] != 0 )
//                 dp[i][j] = max(dp[i][j], dp[i][k] + dp[k][j]);
//                 val = max(val, dp[i][j]);
//             }
//         }
//     }
// }

// 10^5 deplete memory, so following code results in RE.
// void solve_RE(long long N, long long M, std::vector<long long> x, std::vector<long long> y){
//     for (ll i = 0; i < N; i++) {
//         dp[i][i]=0;
//     }
//     for (ll i = 0; i < M; i++) {
//         dp[x[i]-1][y[i]-1]=1;
//     }
//     // MOUT(dp,N+1,N+1);
//     warshall_floyd(N);
//     // cout<<endl;
//     // MOUT(dp,N+1,N+1);
//     cout << val << "\n";
// }

const ll max_n = 1e5 + 10;
// g: adjacency list.
vector<ll> g[max_n];
// v: topological sorted vector.
vector<ll> v;
bool used[max_n];

void dfs(int u){
	if(used[u]) return;
	used[u] = true;
	for(int i: g[u]) dfs(i);
	v.push_back(u);
}
 
void tsort(ll N){
	for(int i = 0; i < N; i++) dfs(i);
	reverse(v.begin(), v.end());
}

void solve(long long N, long long M, std::vector<long long> x, std::vector<long long> y){
    for (ll i = 0; i < M; i++) {
        g[x[i]-1].push_back(y[i]-1);
    }

    //// topological sort
    tsort(N);
    reverse(all(v));
    // vout(v);

    vector<ll> dp(N,0);
    for(ll i: v){
        // cout << "from: " << i+1 ;
        for(ll u: g[i]){
            // cout << " to: " << u+1 << " ";
            dp[i] = max(dp[i], dp[u]+1);
        }
        // cout<<endl;
    }

    // vout(dp);
    cout << vmax(dp) << endl;

    ////// solve_old
    // for (ll i = 0; i < M; i++) {
    //     D[y[i]] = max(D[y[i]], D[x[i]]+1);
    // }
    // for (ll i = 0; i <= N; i++) {
    //     cout << D[i] << " ";
    // }
    // cout << vmax(D) << "\n";
}

int main(){
    long long N;
    scanf("%lld",&N);
    long long M;
    scanf("%lld",&M);
    std::vector<long long> x(M);
    std::vector<long long> y(M);
    for(int i = 0 ; i < M ; i++){
        scanf("%lld",&x[i]);
        scanf("%lld",&y[i]);
    }
    solve(N, M, std::move(x), std::move(y));
    return 0;
}


Measured memory_bytes: 11124