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

using namespace std;

 

#define             ll  long long

#define            ull  unsigned long long

#define            P_B  push_back

#define            M_P  make_pair

#define         DBG(x)  printf("%s %d\n", #x, x)

#define       DBGLL(x)  printf("%s %lld\n", #x, x)

#define         SCI(x)  scanf("%d",&x)

#define         SCD(x)  scanf("%lf",&x)

#define         SCS(x)  scanf("%s",x)

#define         CLR(x)  memset(x, 0, sizeof(x))

#define        CLRN(x)  memset(x, -1, sizeof(x))

#define        SCLL(x)  scanf("%lld", &x)

#define      FOR(i, n)  for(int i = 0; i < n; i++)

#define  FORR(i, m, n)  for(int i = m; i < n; i++)

#define     SCI2(m, n)  scanf("%d%d", &m, &n)

#define  SCI3(m, n, o)  scanf("%d%d%d",&m, &n, &o)

#define     SCD2(m, n)  scanf("%lf%lf",&m,&n)

#define  SCD3(m, n, o)  scanf("%lf%lf%lf",&m,&n,&o)

#define    SCLL2(m, n)  scanf("%lld%lld", &m, &n)

#define SCLL3(m, n, o)  scanf("%lld%lld%lld",&m, &n, &o)

#define             vi  vector<int>

#define            vii  vector<pair<int, int> >

#define            vll  vector<pair<ll, ll> >

#define            Mod  1000000007

#define            INF  1000000000

 



int n, m;

queue<int> st;

vi node[100001];

vector<bool> selected(100001, false);

vector<bool> visited(100001, false);

int maxxes[100001];



void topsort(int v)

{

	if(selected[v]) return;

	selected[v] = true;

	for(auto it : node[v]){

		if(!selected[it]){

			topsort(it);

		}

	}

	st.push(v);

}



int notdfs(int v, int cnt)

{

	// cnt++;

	visited[v] = true;

	int mx =  -1;

	// DBG(mx);

	// DBG(v);

	for(auto it : node[v]){

		// if(!visited[it]){

			mx = max(mx, maxxes[it]);

			// DBG(mx);

			// DBG(it);

		// }

	}

	maxxes[v] = mx + 1;

	return mx + 1;

}



int main()

{

	SCI2(n, m);

	FORR(i, 1, m + 1){

		int p, q;

		SCI2(p, q);

		node[p].P_B(q);

	}

	FORR(i, 1, n + 1)topsort(i);

	int max_ = 0;

	FORR(i, 1, n + 1){

		int x = st.front();

		// DBG(x);

		st.pop();

		if(!visited[x]){

			max_ = max(max_, notdfs(x, -1));

		}

	}

	// FORR(i, 1, n + 1) printf("%d ", maxxes[i]);

	// cout << endl;

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

}

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

#define f first

#define s second

#define pb push_back

#define ENDL '\n'

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

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

#define deb(a) cout << #a << ": " << a << ENDL

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

#define _ ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);



using namespace std;



typedef long long lli;

typedef long double ld;

typedef pair<lli, lli> ii;

typedef vector<lli> vi;



vector<vector<lli>> graph;

vector<lli> dp;



int dfs(int u) {

    if(dp[u] != -1) return dp[u];

    int ret = 0;

    for(auto it : graph[u]) {

        ret = max(ret, dfs(it) + 1);

    }

    dp[u] = ret;

    return ret;

}



int main()

{   _

    lli n, m, u, v; cin >> n >> m;

    graph.resize(n + 1);

    dp.resize(n + 1);

    fill(all(dp), -1);

    fore(i, 0, m) {

        cin >> u >> v;

        graph[u].pb(v);

    }

    int mx = 0;

    fore(i, 1, n + 1) mx = max(mx, dfs(i));

    cout << mx << ENDL;

    return 0;

}