// Slower C++ solution:


/**

    And in the end, the love you take is equal to the love you make.



        I LOVE YOU LAURA.

**/



#include <bits/stdc++.h>

#include <ext/pb_ds/assoc_container.hpp>

#include <ext/pb_ds/tree_policy.hpp>

#include <ext/rope>



#define _CRT_SECURE_NO_DEPRECATE

#define _CRT_DISABLE_PERFCRIT_LOCKS



#define findOrder find_by_order

#define orderKey order_of_key



#define isOn(mask, i) (mask & (1 << i))

#define turn(mask, i) (mask |= (1 << i))

#define switch(mask, i) (mask &= ~(1 << i))

#define change(mask, i) (mask ^= (1 << i))

#define lowbit(mask) (mask & (-mask))

#define turnAll(mask, n) (mask = (1 << n) - 1)

#define switchLastBit(mask) (mask & (mask - 1))

#define turnLastZero(mask) (mask | (mask + 1))

#define modulo(x, mod) ((x) & (mod - 1))

#define log2(x) (31 - __builtin_clz(x))



#define mkp make_pair

#define pb push_back

#define pf push_front

#define eb emplace_back

#define ef emplace_front

#define ins insert

#define rsz resize

#define f first

#define s second

#define lb lower_bound

#define ub upper_bound



#define sz(x) ((int)x.size())

#define all(x) begin(x), end(x)

#define rall(x) rbegin(x), rend(x)



#define debug(x) (cerr << x << " ")



using namespace std;

using namespace __gnu_pbds;

using namespace __gnu_cxx;



typedef double db;

typedef long long ll;

typedef long double ld;

typedef unsigned long long ull;



typedef pair<int, int> ii;

typedef pair<ll,ll> pll;

typedef pair<ld,ld> pdb;

typedef pair<int, ii> tri;

typedef complex<ld> cd;



typedef vector<int> vi;

typedef vector<ii> vii;

typedef vector<ld> vdb;

typedef vector<cd> vcd;

typedef vector<ll> vll;

typedef vector<string> vs;

typedef vector<vll> matrix;



typedef tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> indexed_tree;



const ll mod = 1e9+7;

const int maxn = 1e5+2;

const int pi = 2 * acos(0.0);

const db eps = 1e-9;



ll n, m;

vll graph[maxn];

ll dp[maxn];



ll dfs (int node){

    ll &ans = dp[node];



    if (ans != -1) return ans;



    for (auto v: graph[node]){

        ans = max(ans, dfs(v) + 1);

    }

    return ans;

}



int main()

{

    ios_base::sync_with_stdio(0);

    cin.tie(0); cout.tie(0);



    memset(dp, -1, sizeof dp);



    cin >> n >> m;



    for (int i = 1; i <= m; i++){

        int a, b; cin >> a >> b;



        graph[a].pb(b);

    }



    ll ans = 0;

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

        ans = max(ans, dfs(i) + 1);

    }



    cout << ans << "\n";



    return 0;

}


// Faster C++ solution for the same problem (measured speedup: 4.370567603572455x):
#include<bits/stdc++.h>

#define si(a) scanf("%d", &a)

#define fore(i,a,b) for(int i = a; i < b; ++i)

using namespace std;

typedef long long ll;

typedef pair<int,int> pi;

typedef vector<int> vi;

vector<vector<int> > gr;

vi out;

vi ans;

vector<bool> visited;

vi aux;

void dfs(int u){

	visited[u] = true;

	//ans[u] = max(ans[u], val);

	fore(j,0,gr[u].size()){

		if(!visited[ gr[u][j] ])

			dfs(gr[u][j]);

		//ans[u] = max(ans[u], ans[ gr[u][j] ] + 1);

	}

	aux.push_back(u);

}

void solve(){

	int n,m;

	si(n); si(m);

	int x,y;

	gr.assign(n+1,vector<int>());

	out.assign(n+1,0);

	ans.assign(n+1,0);

	vector<pi> inv(m);

	aux.reserve(n);

	vi in(n+1);

	visited.assign(n+1,false);

	fore(i,0,m){

		si(x);si(y);

		inv[i] = pi(x,y);

		out[x]++;

		in[y]++;

	}

	fore(i,1,n+1)

		gr[i].reserve( in[i] );

	fore(i,0,m){

		x = inv[i].first;

		y = inv[i].second;

		gr[x].push_back(y);

	}

		

	fore(i,1,n+1)

		if(!visited[i])

			dfs(i);

	vi dp(n+1);

	//printf("aux: ");for(int i:aux) printf("%d ", i);printf("\n");

	for(int v: aux){

		if(gr[v].size() == 0)

			dp[v] = 0;

		else{

			int k = 0;

			for(int u: gr[v])

				k = max(k, dp[u]);

			dp[v] = k+1;

		}

	}

	int anss = 0;

	//printf("dp: ");for(int i:dp) printf("%d ", i);printf("\n");

	

	for(int i: dp)

		anss = max(anss, i);

	

	printf("%d\n", anss);

}

int main(){

	solve();

	return 0;

}